Skip to content

Commit d58e9d9

Browse files
author
Marton ILLES
committed
elf: consider cases when program segments are located at the end of the file
Program segments can be placed at the end of the file, up till now we did not calculate the program segment end hence ELF files where program segments were placed at the end of the file were miss calculated. This could happen when there are no sections in the ELF file, which is unusual though possible.
1 parent 4f71764 commit d58e9d9

File tree

3 files changed

+52
-2
lines changed

3 files changed

+52
-2
lines changed
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
version https://git-lfs.github.com/spec/v1
2+
oid sha256:5755d4f41982bdaae3edb565813ffe193db1d0576d77d4170b3b0082d04dda37
3+
size 36917

tests/integration/executable/elf/elf32/__output__/sample_32_prg_end.elf_extract/.gitkeep

Whitespace-only changes.

unblob/handlers/executable/elf.py

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,7 @@ class _ELFBase(StructHandler):
9595

9696
EXTRACTOR = ELFKernelExtractor()
9797
SECTION_HEADER_STRUCT = "elf_shdr_t"
98+
PROGRAM_HEADER_STRUCT = "elf_phdr_t"
9899

99100
@staticmethod
100101
def _check_field(field, value):
@@ -143,12 +144,30 @@ def get_last_section_end(
143144

144145
return last_section_end
145146

147+
def get_last_program_end(
148+
self, file: File, programs_start_offset: int, programs_num: int, endian
149+
) -> int:
150+
last_program_end = 0
151+
file.seek(programs_start_offset)
152+
153+
for _ in range(programs_num):
154+
program_header = self._struct_parser.parse(
155+
self.PROGRAM_HEADER_STRUCT, file, endian
156+
)
157+
158+
program_end = program_header.p_offset + program_header.p_filesz
159+
if program_end > last_program_end:
160+
last_program_end = program_end
161+
162+
return last_program_end
163+
146164
def get_end_offset(
147165
self, file: File, start_offset: int, header: Instance, endian
148166
) -> int:
149167
# Usually the section header is the last, but in some cases the program headers are
150168
# put to the end of the file, and in some cases sections header and actual sections
151-
# can be also intermixed, so we need also to check the end of the last section.
169+
# can be also intermixed, so we need also to check the end of the last section and
170+
# also the last program segment.
152171
# We check which one is the last and use it as a file size.
153172
section_headers_end = (
154173
start_offset + header.e_shoff + (header.e_shnum * header.e_shentsize)
@@ -161,7 +180,13 @@ def get_end_offset(
161180
file, start_offset + header.e_shoff, header.e_shnum, endian
162181
)
163182

164-
return max(section_headers_end, program_headers_end, last_section_end)
183+
last_program_end = self.get_last_program_end(
184+
file, start_offset + header.e_phoff, header.e_phnum, endian
185+
)
186+
187+
return max(
188+
section_headers_end, program_headers_end, last_section_end, last_program_end
189+
)
165190

166191
def calculate_chunk(self, file: File, start_offset: int) -> Optional[ValidChunk]:
167192
endian = self.get_endianness(file, start_offset)
@@ -231,6 +256,17 @@ class ELF32Handler(_ELFBase):
231256
uint32 sh_addralign;
232257
uint32 sh_entsize;
233258
} elf_shdr_t;
259+
260+
typedef struct elf32_phdr {
261+
uint32 p_type;
262+
uint32 p_offset;
263+
uint32 p_vaddr;
264+
uint32 p_paddr;
265+
uint32 p_filesz;
266+
uint32 p_memsz;
267+
uint32 p_flags;
268+
uint32 p_align;
269+
} elf_phdr_t;
234270
"""
235271
HEADER_STRUCT = "elf_header_32_t"
236272

@@ -290,5 +326,16 @@ class ELF64Handler(_ELFBase):
290326
uint64 sh_addralign;
291327
uint64 sh_entsize;
292328
} elf_shdr_t;
329+
330+
typedef struct elf64_phdr {
331+
uint32 p_type;
332+
uint32 p_flags;
333+
uint64 p_offset;
334+
uint64 p_vaddr;
335+
uint64 p_paddr;
336+
uint64 p_filesz;
337+
uint64 p_memsz;
338+
uint64 p_align;
339+
} elf_phdr_t;
293340
"""
294341
HEADER_STRUCT = "elf_header_64_t"

0 commit comments

Comments
 (0)