建立 MAG160C 逆向工程交接仓库
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
#------------------------------------------------------------------------------
|
||||
# elftools: elf/gnuversions.py
|
||||
#
|
||||
# ELF sections
|
||||
#
|
||||
# Yann Rouillard (yann@pleiades.fr.eu.org)
|
||||
# This code is in the public domain
|
||||
#------------------------------------------------------------------------------
|
||||
from __future__ import annotations
|
||||
|
||||
from functools import cached_property
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from ..common.utils import struct_parse, elf_assert
|
||||
from .sections import Section, Symbol
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from collections.abc import Iterator
|
||||
|
||||
from ..construct.core import Struct
|
||||
from ..construct.lib.container import Container
|
||||
from .elffile import ELFFile
|
||||
from .sections import StringTableSection, SymbolTableSection
|
||||
|
||||
|
||||
class Version:
|
||||
""" Version object - representing a version definition or dependency
|
||||
entry from a "Version Needed" or a "Version Dependency" table section.
|
||||
|
||||
This kind of entry contains a pointer to an array of auxiliary entries
|
||||
that store the information about version names or dependencies.
|
||||
These entries are not stored in this object and should be accessed
|
||||
through the appropriate method of a section object which will return
|
||||
an iterator of VersionAuxiliary objects.
|
||||
|
||||
Similarly to Section objects, allows dictionary-like access to
|
||||
verdef/verneed entry
|
||||
"""
|
||||
def __init__(self, entry: Container, name: str | None = None) -> None:
|
||||
self.entry = entry
|
||||
self.name = name
|
||||
|
||||
def __getitem__(self, name: str) -> Any:
|
||||
""" Implement dict-like access to entry
|
||||
"""
|
||||
return self.entry[name]
|
||||
|
||||
|
||||
class VersionAuxiliary:
|
||||
""" Version Auxiliary object - representing an auxiliary entry of a version
|
||||
definition or dependency entry
|
||||
|
||||
Similarly to Section objects, allows dictionary-like access to the
|
||||
verdaux/vernaux entry
|
||||
"""
|
||||
def __init__(self, entry: Container, name: str) -> None:
|
||||
self.entry = entry
|
||||
self.name = name
|
||||
|
||||
def __getitem__(self, name: str) -> Any:
|
||||
""" Implement dict-like access to entries
|
||||
"""
|
||||
return self.entry[name]
|
||||
|
||||
|
||||
class GNUVersionSection(Section):
|
||||
""" Common ancestor class for ELF SUNW|GNU Version Needed/Dependency
|
||||
sections class which contains shareable code
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
header: Container,
|
||||
name: str,
|
||||
elffile: ELFFile,
|
||||
stringtable: StringTableSection,
|
||||
field_prefix: str,
|
||||
version_struct: Struct,
|
||||
version_auxiliaries_struct: Struct,
|
||||
) -> None:
|
||||
super().__init__(header, name, elffile)
|
||||
self.stringtable = stringtable
|
||||
self.field_prefix = field_prefix
|
||||
self.version_struct = version_struct
|
||||
self.version_auxiliaries_struct = version_auxiliaries_struct
|
||||
|
||||
def num_versions(self) -> int:
|
||||
""" Number of version entries in the section
|
||||
"""
|
||||
return self['sh_info']
|
||||
|
||||
def _field_name(self, name: str, auxiliary: bool = False) -> str:
|
||||
""" Return the real field's name of version or a version auxiliary
|
||||
entry
|
||||
"""
|
||||
middle = 'a_' if auxiliary else '_'
|
||||
return self.field_prefix + middle + name
|
||||
|
||||
def _iter_version_auxiliaries(
|
||||
self,
|
||||
entry_offset: int,
|
||||
count: int,
|
||||
) -> Iterator[VersionAuxiliary]:
|
||||
""" Yield all auxiliary entries of a version entry
|
||||
"""
|
||||
name_field = self._field_name('name', auxiliary=True)
|
||||
next_field = self._field_name('next', auxiliary=True)
|
||||
|
||||
for _ in range(count):
|
||||
entry = struct_parse(
|
||||
self.version_auxiliaries_struct,
|
||||
self.stream,
|
||||
stream_pos=entry_offset)
|
||||
|
||||
name = self.stringtable.get_string(entry[name_field])
|
||||
version_aux = VersionAuxiliary(entry, name)
|
||||
yield version_aux
|
||||
|
||||
entry_offset += entry[next_field]
|
||||
|
||||
def iter_versions(self) -> Iterator[tuple[Version, Iterator[VersionAuxiliary]]]:
|
||||
""" Yield all the version entries in the section
|
||||
Each time it returns the main version structure
|
||||
and an iterator to walk through its auxiliaries entries
|
||||
"""
|
||||
aux_field = self._field_name('aux')
|
||||
count_field = self._field_name('cnt')
|
||||
next_field = self._field_name('next')
|
||||
|
||||
entry_offset = self['sh_offset']
|
||||
for _ in range(self.num_versions()):
|
||||
entry = struct_parse(
|
||||
self.version_struct,
|
||||
self.stream,
|
||||
stream_pos=entry_offset)
|
||||
|
||||
elf_assert(entry[count_field] > 0,
|
||||
'Expected number of version auxiliary entries (%s) to be > 0'
|
||||
'for the following version entry: %s' % (
|
||||
count_field, str(entry)))
|
||||
|
||||
version = Version(entry)
|
||||
aux_entries_offset = entry_offset + entry[aux_field]
|
||||
version_auxiliaries_iter = self._iter_version_auxiliaries(
|
||||
aux_entries_offset, entry[count_field])
|
||||
|
||||
yield version, version_auxiliaries_iter
|
||||
|
||||
entry_offset += entry[next_field]
|
||||
|
||||
|
||||
class GNUVerNeedSection(GNUVersionSection):
|
||||
""" ELF SUNW or GNU Version Needed table section.
|
||||
Has an associated StringTableSection that's passed in the constructor.
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
header: Container,
|
||||
name: str,
|
||||
elffile: ELFFile,
|
||||
stringtable: StringTableSection,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
header, name, elffile, stringtable, 'vn',
|
||||
elffile.structs.Elf_Verneed, elffile.structs.Elf_Vernaux)
|
||||
|
||||
def has_indexes(self) -> bool:
|
||||
""" Return True if at least one version definition entry has an index
|
||||
that is stored in the vna_other field.
|
||||
This information is used for symbol versioning
|
||||
"""
|
||||
return self._has_indexes
|
||||
|
||||
@cached_property
|
||||
def _has_indexes(self) -> bool:
|
||||
return any(
|
||||
vernaux['vna_other']
|
||||
for _, vernaux_iter in self.iter_versions()
|
||||
for vernaux in vernaux_iter
|
||||
)
|
||||
|
||||
def iter_versions(self) -> Iterator[tuple[Version, Iterator[VersionAuxiliary]]]:
|
||||
for verneed, vernaux in super().iter_versions():
|
||||
verneed.name = self.stringtable.get_string(verneed['vn_file'])
|
||||
yield verneed, vernaux
|
||||
|
||||
def get_version(self, index: int) -> tuple[Version, VersionAuxiliary] | None:
|
||||
""" Get the version information located at index #n in the table
|
||||
Return boths the verneed structure and the vernaux structure
|
||||
that contains the name of the version
|
||||
"""
|
||||
for verneed, vernaux_iter in self.iter_versions():
|
||||
for vernaux in vernaux_iter:
|
||||
if vernaux['vna_other'] == index:
|
||||
return verneed, vernaux
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class GNUVerDefSection(GNUVersionSection):
|
||||
""" ELF SUNW or GNU Version Definition table section.
|
||||
Has an associated StringTableSection that's passed in the constructor.
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
header: Container,
|
||||
name: str,
|
||||
elffile: ELFFile,
|
||||
stringtable: StringTableSection,
|
||||
) -> None:
|
||||
super().__init__(
|
||||
header, name, elffile, stringtable, 'vd',
|
||||
elffile.structs.Elf_Verdef, elffile.structs.Elf_Verdaux)
|
||||
|
||||
def get_version(self, index: int) -> tuple[Version, Iterator[VersionAuxiliary]] | None:
|
||||
""" Get the version information located at index #n in the table
|
||||
Return boths the verdef structure and an iterator to retrieve
|
||||
both the version names and dependencies in the form of
|
||||
verdaux entries
|
||||
"""
|
||||
for verdef, verdaux_iter in self.iter_versions():
|
||||
if verdef['vd_ndx'] == index:
|
||||
return verdef, verdaux_iter
|
||||
|
||||
return None
|
||||
|
||||
|
||||
class GNUVerSymSection(Section):
|
||||
""" ELF SUNW or GNU Versym table section.
|
||||
Has an associated SymbolTableSection that's passed in the constructor.
|
||||
"""
|
||||
def __init__(
|
||||
self,
|
||||
header: Container,
|
||||
name: str,
|
||||
elffile: ELFFile,
|
||||
symboltable: SymbolTableSection,
|
||||
) -> None:
|
||||
super().__init__(header, name, elffile)
|
||||
self.symboltable = symboltable
|
||||
|
||||
def num_symbols(self) -> int:
|
||||
""" Number of symbols in the table
|
||||
"""
|
||||
return self['sh_size'] // self['sh_entsize']
|
||||
|
||||
def get_symbol(self, n: int) -> Symbol:
|
||||
""" Get the symbol at index #n from the table (Symbol object)
|
||||
It begins at 1 and not 0 since the first entry is used to
|
||||
store the current version of the syminfo table
|
||||
"""
|
||||
# Grab the symbol's entry from the stream
|
||||
entry_offset = self['sh_offset'] + n * self['sh_entsize']
|
||||
entry = struct_parse(
|
||||
self.structs.Elf_Versym,
|
||||
self.stream,
|
||||
stream_pos=entry_offset)
|
||||
# Find the symbol name in the associated symbol table
|
||||
name = self.symboltable.get_symbol(n).name
|
||||
return Symbol(entry, name)
|
||||
|
||||
def iter_symbols(self) -> Iterator[Symbol]:
|
||||
""" Yield all the symbols in the table
|
||||
"""
|
||||
for i in range(self.num_symbols()):
|
||||
yield self.get_symbol(i)
|
||||
Reference in New Issue
Block a user