Compare commits

..

No commits in common. "1762c8c43542c0aab1807ce5b7168ead063b2531" and "fd650d3dff2e542524c7fd7055dab14f7e35ff5c" have entirely different histories.

2 changed files with 23 additions and 52 deletions

View File

@ -33,8 +33,6 @@ class elf_symbol():
name: Name of the symbol name: Name of the symbol
section: section where the symbol data is placed
index: Absolut index in the symbol table index: Absolut index in the symbol table
info: Type of the symbol info: Type of the symbol
@ -57,8 +55,6 @@ class elf_symbol():
else: else:
self.name = '' self.name = ''
self.section: elf_section | None = self.file.sections[self['st_shndx']] if self['st_shndx'] < len(self.file.sections) else None
self.index = index self.index = index
self.info, self.description = fdat.st_info_values[fields['st_info'] & 0x0F] self.info, self.description = fdat.st_info_values[fields['st_info'] & 0x0F]
@ -72,19 +68,15 @@ class elf_symbol():
Returns: Returns:
Symbol data Symbol data
""" """
assert self.section, 'This symbol is not associated to a data section' offset = self.file.sections[self['st_shndx']]['sh_offset'] + self['st_value']
if self.section.type == 'SHT_NOBITS': return self.file.read_bytes(offset, self['st_size'])
return b'\x00' * self['st_size']
else:
offset = self.section['sh_offset'] + self['st_value']
return self.file.read_bytes(offset, self['st_size'])
def read_data_hex(self) -> str: def read_data_hex(self) -> str:
return ' '.join(f'{d:02X}' for d in self.read_data()) return ' '.join(f'{d:02X}' for d in self.read_data())
def get_relocations(self) -> 'relocation_list': def get_relocations(self) -> 'relocation_list':
"""List all relocations that are pointing to this symbol. """List all relocations that are pointing to this symbol.
The symbol section must be of type SHT_PROGBITS (program code). Therefore The symbol must be of type SHT_PROGBITS (program code). Therefore
this function lists typically all relocations that will be this function lists typically all relocations that will be
applied to the function represented by the symbol. applied to the function represented by the symbol.
@ -92,9 +84,10 @@ class elf_symbol():
List of relocations List of relocations
""" """
ret: list[elf_relocation] = list() ret: list[elf_relocation] = list()
assert self.section and self.section.type == 'SHT_PROGBITS' section = self.file.sections[self.fields['st_shndx']]
assert section.type == 'SHT_PROGBITS'
for reloc in self.file.get_relocations(): for reloc in self.file.get_relocations():
if reloc.target_section == self.section: if reloc.target_section == section:
offset = reloc['r_offset'] - self['st_value'] offset = reloc['r_offset'] - self['st_value']
if 0 <= offset < self['st_size']: if 0 <= offset < self['st_size']:
ret.append(reloc) ret.append(reloc)
@ -112,7 +105,7 @@ class elf_symbol():
f'name {self.name}\n' +\ f'name {self.name}\n' +\
f'stb {self.stb} ({self.stb_description})\n' +\ f'stb {self.stb} ({self.stb_description})\n' +\
f'info {self.info} ({self.description})\n' +\ f'info {self.info} ({self.description})\n' +\
'\n'.join(f"{k:18} {v:4} {fdat.symbol_fields[k]}" for k, v in self.fields.items()) + '\n' '\n'.join(f'{k:18} {v:4}' for k, v in self.fields.items()) + '\n'
class elf_section(): class elf_section():
@ -163,18 +156,7 @@ class elf_section():
Returns: Returns:
Data of the section Data of the section
""" """
if self.type == 'SHT_NOBITS': return self.file.read_bytes(self['sh_offset'], self['sh_size'])
return b'\x00' * self['sh_size']
else:
return self.file.read_bytes(self['sh_offset'], self['sh_size'])
def get_symbols(self) -> 'symbol_list':
"""Lists all ELF symbols associated with this section
Returns:
Symbol list
"""
return symbol_list(self.file._list_symbols(self.index))
def get_data_hex(self) -> str: def get_data_hex(self) -> str:
data = self.file.read_bytes(self['sh_offset'], self['sh_size']) data = self.file.read_bytes(self['sh_offset'], self['sh_size'])
@ -338,9 +320,9 @@ class symbol_list(elf_list[elf_symbol]):
"""A class for representing a list of ELF symbols """A class for representing a list of ELF symbols
""" """
def _compact_table(self) -> tuple[list[str], list[list[int | str]], list[str]]: def _compact_table(self) -> tuple[list[str], list[list[int | str]], list[str]]:
columns = ['index', 'name', 'info', 'size', 'stb', 'section', 'description'] columns = ['index', 'name', 'info', 'size', 'stb', 'description']
data: list[list[str | int]] = [[item.index, item.name, item.info, item.fields['st_size'], data: list[list[str | int]] = [[item.index, item.name, item.info, item.fields['st_size'],
item.stb, item.section.name if item.section else '', item.description] for item in self] item.stb, item.description] for item in self]
return columns, data, ['index', 'size'] return columns, data, ['index', 'size']
@ -387,15 +369,14 @@ class elf_file:
string_table_section: The string table section (first section with string_table_section: The string table section (first section with
the name .strtab) the name .strtab)
""" """
def __init__(self, data: bytes | bytearray): def __init__(self, data: bytes):
assert isinstance(data, (bytes, bytearray)), 'Binary ELF data must be provided as bytes or bytearray.'
self._data = data self._data = data
# Defaults required for function _read_int_from_elf_field # Defaults required for function _read_int_from_elf_field
self.bit_width = 32 self.bit_width = 32
self.byteorder: Literal['little', 'big'] = 'little' self.byteorder: Literal['little', 'big'] = 'little'
assert self._read_bytes_from_elf_field('e_ident[EI_MAG]') == b'\x7fELF', 'Not an ELF file' assert self._read_bytes_from_elf_field('e_ident[EI_MAG]') == bytes([0x7F, 0x45, 0x4c, 0x46]), 'Not an ELF file'
self.bit_width = {1: 32, 2: 64}[self._read_int_from_elf_field('e_ident[EI_CLASS]')] self.bit_width = {1: 32, 2: 64}[self._read_int_from_elf_field('e_ident[EI_CLASS]')]
@ -433,7 +414,7 @@ class elf_file:
offs = self.fields['e_shoff'] + i * self.fields['e_shentsize'] offs = self.fields['e_shoff'] + i * self.fields['e_shentsize']
yield {fn: self._read_from_sh_field(offs, fn) for fn in fdat.section_header.keys()} yield {fn: self._read_from_sh_field(offs, fn) for fn in fdat.section_header.keys()}
def _list_symbols(self, section_index: int | None = None) -> Generator[elf_symbol, None, None]: def _list_symbols(self) -> Generator[elf_symbol, None, None]:
if self.symbol_table_section: if self.symbol_table_section:
offs = self.symbol_table_section['sh_offset'] offs = self.symbol_table_section['sh_offset']
@ -453,8 +434,7 @@ class elf_file:
ret['st_value'] = self.read_int(i + 8, 8) ret['st_value'] = self.read_int(i + 8, 8)
ret['st_size'] = self.read_int(i + 16, 8) ret['st_size'] = self.read_int(i + 16, 8)
if section_index is None or section_index == ret['st_shndx']: yield elf_symbol(self, ret, j)
yield elf_symbol(self, ret, j)
def get_relocations(self, reloc_section: elf_section | str | list[str] | None = None) -> relocation_list: def get_relocations(self, reloc_section: elf_section | str | list[str] | None = None) -> relocation_list:
"""List relocations. """List relocations.

View File

@ -271,7 +271,7 @@ section_header = {
}, },
"sh_size": { "sh_size": {
"32": "0x14", "64": "0x20", "size32": "4", "size64": "8", "field_name": "sh_size", "32": "0x14", "64": "0x20", "size32": "4", "size64": "8", "field_name": "sh_size",
"description": "Size in bytes of the section in memory or 0. May be equal to size in file." "description": "Size in bytes of the section in the file image. May be 0."
}, },
"sh_link": { "sh_link": {
"32": "0x18", "64": "0x28", "size32": "4", "size64": "4", "field_name": "sh_link", "32": "0x18", "64": "0x28", "size32": "4", "size64": "4", "field_name": "sh_link",
@ -316,25 +316,16 @@ section_header_types_ex = {0x60000000: 'OS-specific',
0x70000000: 'Processor-specific', 0x70000000: 'Processor-specific',
0x80000000: 'Application-specific'} 0x80000000: 'Application-specific'}
symbol_fields = {
"st_name": "Index into the string table for the symbol's name",
"st_info": "Encodes the symbol's type and its binding attribute",
"st_other": "Defines symbol visibility within and outside the object file",
"st_shndx": "Specifies which section this symbol is associated with",
"st_value": "Holds the symbol's address or offset, depending on context",
"st_size": "Specifies the size of the symbol (e.g., function length or variable size)"
}
st_info_values = { st_info_values = {
0: ("STT_NOTYPE", "Type is unspecified"), 0: ("STT_NOTYPE", "Symbol type is unspecified"),
1: ("STT_OBJECT", "Data object"), 1: ("STT_OBJECT", "Symbol is a data object"),
2: ("STT_FUNC", "Code object"), 2: ("STT_FUNC", "Symbol is a code object"),
3: ("STT_SECTION", "Section associated"), 3: ("STT_SECTION", "Symbol associated with a section"),
4: ("STT_FILE", "File name"), 4: ("STT_FILE", "Symbol's name is file name"),
5: ("STT_COMMON", "Common data object"), 5: ("STT_COMMON", "Symbol is a common data object"),
6: ("STT_TLS", "Thread-local data object"), 6: ("STT_TLS", "Symbol is thread-local data object"),
7: ("STT_NUM", "Number of defined types"), 7: ("STT_NUM", "Number of defined types"),
10: ("STT_GNU_IFUNC", "Indirect code object") 10: ("STT_GNU_IFUNC", "Symbol is indirect code object")
} }
stb_values = { stb_values = {