Skip to content

Commit 6e89ec3

Browse files
authored
Merge pull request #390 from onekey-sec/fix-elf-program-segment
elf: consider cases when program segments are located at the end of the file
2 parents 4f71764 + d58e9d9 commit 6e89ec3

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)