Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added handling of program segments and overlapping parts #9

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 25 additions & 3 deletions makeelf/elf.py
Original file line number Diff line number Diff line change
Expand Up @@ -208,12 +208,34 @@ def __bytes__(self):
self.Elf.Ehdr.e_shentsize = 0
self.Elf.Ehdr.e_shnum = 0

# update section offsets in section headers
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you meant program headers, as you're changing Phdr

orig_poffset = []
for i, Phdr in enumerate(self.Elf.Phdr_table):
program = self.Elf.programs[i]
program_len = len(program)
Phdr.p_filesz = program_len
orig_poffset.append(Phdr.p_offset)
if isinstance(program, memoryview):
idx, hdr = next((i, x) for i, x in enumerate(self.Elf.Phdr_table) if program.obj is self.Elf.programs[i])
Phdr.p_offset = Phdr.p_offset - orig_poffset[idx] + hdr.p_offset
else:
Phdr.p_offset = cursor
cursor += program_len

# update section offsets in section headers
for i, Shdr in enumerate(self.Elf.Shdr_table):
section_len = len(self.Elf.sections[i])
Shdr.sh_offset = cursor
section = self.Elf.sections[i]
section_len = len(section)
# Check for all zeros - strip such sections
if next((False for b in section if b != 0x00), True):
Shdr.sh_offset = -1
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, now I understand why you are checking sh_offset for negative values. Don't do it that way. Someone might try to serialize Shdr in the meantime and will get exception, because of that. If the goal is to strip a section, just do it here. You have access to section, so it could be assigned to None, empty array or anything that can unambiguously mark it as empty.

elif isinstance(section, memoryview):
idx, hdr = next((i, x) for i, x in enumerate(self.Elf.Phdr_table) if section.obj is self.Elf.programs[i])
Shdr.sh_offset = Shdr.sh_offset - orig_poffset[idx] + hdr.p_offset
else:
Shdr.sh_offset = cursor
cursor += section_len
Shdr.sh_size = section_len
cursor += section_len

return bytes(self.Elf)

Expand Down
99 changes: 92 additions & 7 deletions makeelf/elfstruct.py
100755 → 100644
Original file line number Diff line number Diff line change
Expand Up @@ -766,7 +766,7 @@ class Elf32:
# \param sections List of section contents
# \param little Endianness of ELF file
def __init__(self, Ehdr=None, Phdr_table=None, Shdr_table=None,
sections=None, little=False):
programs=None, sections=None, little=False):
if Ehdr is None:
Ehdr = Elf32_Ehdr()
if Phdr_table is None:
Expand All @@ -775,6 +775,8 @@ def __init__(self, Ehdr=None, Phdr_table=None, Shdr_table=None,
Shdr_table = []
if sections is None:
sections = []
if programs is None:
programs = []

if isinstance(Ehdr, Elf32_Ehdr):
## Instance of \link Elf32_Ehdr \endlink
Expand All @@ -796,6 +798,14 @@ def __init__(self, Ehdr=None, Phdr_table=None, Shdr_table=None,
else:
raise Exception('Shdr table must be a list of Elf32_Shdr objects')

if isinstance(programs, list):
## List of section content
# \details Contains raw bytes objects or any type that can be
# converted using bytes function
self.programs = programs
else:
raise Exception('Programs must be a list containing program content')

if isinstance(sections, list):
## List of section content
# \details Contains raw bytes objects or any type that can be
Expand Down Expand Up @@ -847,15 +857,27 @@ def __bytes__(self):
headers[cursor] = Shdr
cursor += self.Ehdr.e_shentsize

# programs
for i, Phdr in enumerate(self.Phdr_table):
if len(self.programs[i]) != 0 and not isinstance(self.programs[i], memoryview):
headers[Phdr.p_offset] = self.programs[i]

# sections
for i, Shdr in enumerate(self.Shdr_table):
if len(self.sections[i]) != 0:
if Shdr.sh_offset < 0:
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sh_offset of negative value is impossible to serialize. Maybe it should be forbidden on shdr object creation? It is going to result in exception, if just shdr object serialization is performed, so sounds like a better place to prevent such situation.

pass
elif len(self.sections[i]) != 0 and not isinstance(self.sections[i], memoryview):
headers[Shdr.sh_offset] = self.sections[i]

# find file size
end_of_file = sorted(headers.keys())[-1]
end_of_file += len(headers[end_of_file])

# Set all invalid offsets to end of file
for i, Shdr in enumerate(self.Shdr_table):
if Shdr.sh_offset < 0:
Shdr.sh_offset = end_of_file
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't do any magic in this file. If for some reason, this kind of stuff is required, please do it in ELF() class.

In here, invalid structures must be treated as perfectly fine.


# create and populate buffer
b = bytes(end_of_file)
for off in headers:
Expand All @@ -878,6 +900,18 @@ def __bytes__(self):
b = makeelf.utils.bytes_xor(b, aligned)
return b

def create_section_from_hdr(blob, programs, phdrs, hdr):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Try to document new functions you're adding. It is hard for anyone else to use such functions. This is even more important to other two functions, as there is no single call to them.

first = hdr.sh_offset
last = first + hdr.sh_size
program, idx = next(((p, idx) for idx, p in enumerate(phdrs) if p.p_offset <= first and last <= (p.p_offset + p.p_filesz)), (None, None))
if program != None and hdr.sh_size > 0:
section = memoryview(programs[idx])[first - program.p_offset:last - program.p_offset]
elif blob and last <= len(blob):
section = bytearray(blob[first:last])
else:
section = bytearray([0x00 for i in range(hdr.sh_size)])
return section

##
# \brief Deserialization of object
#
Expand Down Expand Up @@ -905,16 +939,67 @@ def from_bytes(b, little=False):
Shdr, b = Elf32_Shdr.from_bytes(b, little)
Shdr_a.append(Shdr)

# Programs
programs = []
Phdr_f = []
Phdr_a = sorted(Phdr_a, key=lambda p: -p.p_filesz)
for Phdr in Phdr_a:
first = Phdr.p_offset
last = first + Phdr.p_filesz
program, idx = next(((p, idx) for idx, p in enumerate(Phdr_f) if p.p_offset <= first and last <= (p.p_offset + p.p_filesz)), (None, None))
if not program or Phdr.p_filesz == 0:
program = bytearray(blob[first:last])
else:
program = memoryview(programs[idx])[first - program.p_offset:last - program.p_offset]
programs.append(program)
Phdr_f.append(Phdr)

# Sections
sections = []
# TODO: support of section content handlers, i.e. _Strtab, _Symtab
for i, Shdr in enumerate(Shdr_a):
first = Shdr.sh_offset
last = first + Shdr.sh_size
section = blob[first:last]
for Shdr in Shdr_a:
section = Elf32.create_section_from_hdr(blob, programs, Phdr_a, Shdr)
sections.append(section)

return Elf32(Ehdr, Phdr_a, Shdr_a, sections, little=Ehdr.little), None
return Elf32(Ehdr, Phdr_a, Shdr_a, programs, sections, little=Ehdr.little), None

def extend_program(self, idx, extension):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, move this function to elf module. elfstruct's purpose is to provide a kind of a model for storing data in ELF file. Any manipulations should be done outside of it.

program = self.programs[idx]
Phdr = self.Phdr_table[idx]
to_update = []
for i, Shdr in enumerate(self.Shdr_table):
section = self.sections[i]
if not isinstance(section, memoryview):
continue
if not section.obj is program:
continue
to_update.append((i, Shdr))
section.release()
self.programs[idx].extend(extension)
program = self.programs[idx]
Phdr.p_filesz = len(program)
for i, Shdr in to_update:
first = Shdr.sh_offset - Phdr.p_offset
last = first + Shdr.sh_size
self.sections[i] = memoryview(program)[first:last]
return program

def resize_section(self, section, size):
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same situation here

idx, Shdr = next(((idx, p) for idx, p in enumerate(self.Shdr_table) if self.sections[idx] is section))
if len(section) == 0:
Shdr.sh_size = size
self.sections[idx] = Elf32.create_section_from_hdr(None, self.programs, self.Phdr_table, Shdr)
return
if not isinstance(section, memoryview):
if len(section) > size:
self.sections[idx] = section[:size]
else:
self.sections[idx].extend([0xFF for i in range(size - len(section))])
return
pidx, Phdr = next(((i, p) for i, p in enumerate(self.Phdr_table) if self.programs[i] is section.obj))
first = Shdr.sh_offset - Phdr.p_offset
last = first + size
self.sections[idx] = memoryview(self.programs[pidx])[first:last]

##
# \brief Length of object
Expand Down