Shofel2_T124_python/venv/lib/python3.10/site-packages/qiling/debugger/utils.py

345 lines
14 KiB
Python
Raw Permalink Normal View History

2024-05-25 16:45:07 +00:00
#!/usr/bin/env python3
#
# Cross Platform and Multi Architecture Advanced Binary Emulation Framework
#
from elftools.common.exceptions import ELFError
from elftools.common.py3compat import (
ifilter, byte2int, bytes2str, itervalues, str2bytes, iterbytes)
from elftools.elf.elffile import ELFFile
from elftools.elf.dynamic import DynamicSection, DynamicSegment
from elftools.elf.enums import ENUM_D_TAG
from elftools.elf.segments import InterpSegment
from elftools.elf.sections import NoteSection, SymbolTableSection
from elftools.elf.gnuversions import (
GNUVerSymSection, GNUVerDefSection,
GNUVerNeedSection,
)
from elftools.elf.relocation import RelocationSection
from elftools.elf.descriptions import (
describe_ei_class, describe_ei_data, describe_ei_version,
describe_ei_osabi, describe_e_type, describe_e_machine,
describe_e_version_numeric, describe_p_type, describe_p_flags,
describe_sh_type, describe_sh_flags,
describe_symbol_type, describe_symbol_bind, describe_symbol_visibility,
describe_symbol_shndx, describe_reloc_type, describe_dyn_tag,
describe_dt_flags, describe_dt_flags_1, describe_ver_flags, describe_note,
describe_attr_tag_arm
)
from elftools.elf.constants import E_FLAGS
from elftools.elf.constants import E_FLAGS_MASKS
from qiling import Qiling
class QlReadELF(object):
def __init__(self, ql:Qiling, elf_stream):
self.ql = ql
self.elffile = ELFFile(elf_stream)
self._versioninfo = None
def elf_file_header(self):
elf_header = {}
def add_info(key, value):
elf_header[key] = value
header = self.elffile.header
e_ident = header['e_ident']
add_info('Magic', ' '.join('%2.2x' % byte2int(b)
for b in self.elffile.e_ident_raw))
add_info('Class',describe_ei_class(e_ident['EI_CLASS']))
add_info('Data', describe_ei_data(e_ident['EI_DATA']))
add_info('Version', e_ident['EI_VERSION'])
add_info('OS/ABI', describe_ei_osabi(e_ident['EI_OSABI']))
add_info('ABI Version', e_ident['EI_ABIVERSION'])
add_info('Type', describe_e_type(header['e_type']))
add_info('Machine', describe_e_machine(header['e_machine']))
add_info('Version_e', describe_e_version_numeric(header['e_version']))
add_info('Entry point address', self._format_hex(header['e_entry']))
add_info('Start of program headers', header['e_phoff'])
add_info('Start of section headers', header['e_shoff'])
add_info('Flags', [self._format_hex(header['e_flags']),
self.decode_flags(header['e_flags'])])
add_info('Size of this header', header['e_ehsize'])
add_info('Size of program headers', header['e_phentsize'])
add_info('Number of program headers', header['e_phnum'])
add_info('Size of section headers', header['e_shentsize'])
add_info('Number of section headers', header['e_shnum'])
add_info('Section header string table index', header['e_shstrndx'])
return elf_header
def elf_program_headers(self):
program_headers = []
def add_info(dic):
program_headers.append(dic)
if self.elffile.num_segments() == 0:
return None
for segment in self.elffile.iter_segments():
program_hdr = {}
program_hdr['Type'] = describe_p_type(segment['p_type'])
program_hdr['Offset'] = self._format_hex(segment['p_offset'], fieldsize=6)
program_hdr['VirtAddr'] = self._format_hex(segment['p_vaddr'], fullhex=True)
program_hdr['PhysAddr'] = self._format_hex(segment['p_paddr'], fullhex=True)
program_hdr['FileSiz'] = self._format_hex(segment['p_filesz'], fieldsize=5)
program_hdr['MemSiz'] = self._format_hex(segment['p_memsz'], fieldsize=5)
program_hdr['Flg'] = describe_p_flags(segment['p_flags'])
program_hdr['Align'] = self._format_hex(segment['p_align'])
add_info(program_hdr)
return program_headers
def elf_section_headers(self):
section_headers = []
def add_info(dic):
section_headers.append(dic)
if self.elffile.num_sections() == 0:
return None
for nsec, section in enumerate(self.elffile.iter_sections()):
section_hdr = {}
section_hdr['index'] = nsec
section_hdr['Name'] = section.name
section_hdr['Type'] = describe_sh_type(section['sh_type'])
section_hdr['Addr'] = self._format_hex(section['sh_addr'], fieldsize=8, lead0x=False)
section_hdr['Offset'] = self._format_hex(section['sh_offset'], fieldsize=6, lead0x=False)
section_hdr['Size'] = self._format_hex(section['sh_size'], fieldsize=6, lead0x=False)
section_hdr['ES'] = self._format_hex(section['sh_entsize'], fieldsize=2, lead0x=False)
section_hdr['Flag'] = describe_sh_flags(section['sh_flags'])
section_hdr['Lk'] = section['sh_link']
section_hdr['Inf'] = section['sh_info']
section_hdr['Al'] = section['sh_addralign']
add_info(section_hdr)
return section_headers
def elf_symbol_tables(self):
symbol_tables_list = []
def add_info(dic):
symbol_tables_list.append(dic)
self._init_versioninfo()
symbol_tables = [s for s in self.elffile.iter_sections()
if isinstance(s, SymbolTableSection)]
if not symbol_tables and self.elffile.num_sections() == 0:
return None
for section in symbol_tables:
if not isinstance(section, SymbolTableSection):
continue
if section['sh_entsize'] == 0:
continue
for nsym, symbol in enumerate(section.iter_symbols()):
version_info = ''
if (section['sh_type'] == 'SHT_DYNSYM' and
self._versioninfo['type'] == 'GNU'):
version = self._symbol_version(nsym)
if (version['name'] != symbol.name and
version['index'] not in ('VER_NDX_LOCAL',
'VER_NDX_GLOBAL')):
if version['filename']:
# external symbol
version_info = '@%(name)s (%(index)i)' % version
else:
# internal symbol
if version['hidden']:
version_info = '@%(name)s' % version
else:
version_info = '@@%(name)s' % version
symbol_info = {}
symbol_info['index'] = nsym
symbol_info['Value'] = self._format_hex(
symbol['st_value'], fullhex=True, lead0x=False)
symbol_info['Size'] = symbol['st_size']
symbol_info['Type'] = describe_symbol_type(symbol['st_info']['type'])
symbol_info['Bind'] = describe_symbol_bind(symbol['st_info']['bind'])
symbol_info['Vis'] = describe_symbol_visibility(symbol['st_other']['visibility'])
symbol_info['Ndx'] = describe_symbol_shndx(symbol['st_shndx'])
symbol_info['Name'] = symbol.name
symbol_info['version_info'] = version_info
add_info(symbol_info)
return symbol_tables_list
def decode_flags(self, flags):
description = ""
if self.elffile['e_machine'] == "EM_ARM":
eabi = flags & E_FLAGS.EF_ARM_EABIMASK
flags &= ~E_FLAGS.EF_ARM_EABIMASK
if flags & E_FLAGS.EF_ARM_RELEXEC:
description += ', relocatable executabl'
flags &= ~E_FLAGS.EF_ARM_RELEXEC
if eabi == E_FLAGS.EF_ARM_EABI_VER5:
EF_ARM_KNOWN_FLAGS = E_FLAGS.EF_ARM_ABI_FLOAT_SOFT|E_FLAGS.EF_ARM_ABI_FLOAT_HARD|E_FLAGS.EF_ARM_LE8|E_FLAGS.EF_ARM_BE8
description += ', Version5 EABI'
if flags & E_FLAGS.EF_ARM_ABI_FLOAT_SOFT:
description += ", soft-float ABI"
elif flags & E_FLAGS.EF_ARM_ABI_FLOAT_HARD:
description += ", hard-float ABI"
if flags & E_FLAGS.EF_ARM_BE8:
description += ", BE8"
elif flags & E_FLAGS.EF_ARM_LE8:
description += ", LE8"
if flags & ~EF_ARM_KNOWN_FLAGS:
description += ', <unknown>'
else:
description += ', <unrecognized EABI>'
elif self.elffile['e_machine'] == "EM_MIPS":
if flags & E_FLAGS.EF_MIPS_NOREORDER:
description += ", noreorder"
if flags & E_FLAGS.EF_MIPS_PIC:
description += ", pic"
if flags & E_FLAGS.EF_MIPS_CPIC:
description += ", cpic"
if (flags & E_FLAGS.EF_MIPS_ABI2):
description += ", abi2"
if (flags & E_FLAGS.EF_MIPS_32BITMODE):
description += ", 32bitmode"
if (flags & E_FLAGS_MASKS.EFM_MIPS_ABI_O32):
description += ", o32"
elif (flags & E_FLAGS_MASKS.EFM_MIPS_ABI_O64):
description += ", o64"
elif (flags & E_FLAGS_MASKS.EFM_MIPS_ABI_EABI32):
description += ", eabi32"
elif (flags & E_FLAGS_MASKS.EFM_MIPS_ABI_EABI64):
description += ", eabi64"
if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_1:
description += ", mips1"
if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_2:
description += ", mips2"
if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_3:
description += ", mips3"
if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_4:
description += ", mips4"
if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_5:
description += ", mips5"
if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_32R2:
description += ", mips32r2"
if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_64R2:
description += ", mips64r2"
if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_32:
description += ", mips32"
if (flags & E_FLAGS.EF_MIPS_ARCH) == E_FLAGS.EF_MIPS_ARCH_64:
description += ", mips64"
return description
def _format_hex(self, addr, fieldsize=None, fullhex=False, lead0x=True,
alternate=False):
""" Format an address into a hexadecimal string.
fieldsize:
Size of the hexadecimal field (with leading zeros to fit the
address into. For example with fieldsize=8, the format will
be %08x
If None, the minimal required field size will be used.
fullhex:
If True, override fieldsize to set it to the maximal size
needed for the elfclass
lead0x:
If True, leading 0x is added
alternate:
If True, override lead0x to emulate the alternate
hexadecimal form specified in format string with the #
character: only non-zero values are prefixed with 0x.
This form is used by readelf.
"""
if alternate:
if addr == 0:
lead0x = False
else:
lead0x = True
fieldsize -= 2
s = '0x' if lead0x else ''
if fullhex:
fieldsize = 8 if self.elffile.elfclass == 32 else 16
if fieldsize is None:
field = '%x'
else:
field = '%' + '0%sx' % fieldsize
return s + field % addr
def _init_versioninfo(self):
""" Search and initialize informations about version related sections
and the kind of versioning used (GNU or Solaris).
"""
if self._versioninfo is not None:
return
self._versioninfo = {'versym': None, 'verdef': None,
'verneed': None, 'type': None}
for section in self.elffile.iter_sections():
if isinstance(section, GNUVerSymSection):
self._versioninfo['versym'] = section
elif isinstance(section, GNUVerDefSection):
self._versioninfo['verdef'] = section
elif isinstance(section, GNUVerNeedSection):
self._versioninfo['verneed'] = section
elif isinstance(section, DynamicSection):
for tag in section.iter_tags():
if tag['d_tag'] == 'DT_VERSYM':
self._versioninfo['type'] = 'GNU'
break
if not self._versioninfo['type'] and (
self._versioninfo['verneed'] or self._versioninfo['verdef']):
self._versioninfo['type'] = 'Solaris'
def _symbol_version(self, nsym):
""" Return a dict containing information on the
or None if no version information is available
"""
self._init_versioninfo()
symbol_version = dict.fromkeys(('index', 'name', 'filename', 'hidden'))
if (not self._versioninfo['versym'] or
nsym >= self._versioninfo['versym'].num_symbols()):
return None
symbol = self._versioninfo['versym'].get_symbol(nsym)
index = symbol.entry['ndx']
if not index in ('VER_NDX_LOCAL', 'VER_NDX_GLOBAL'):
index = int(index)
if self._versioninfo['type'] == 'GNU':
# In GNU versioning mode, the highest bit is used to
# store wether the symbol is hidden or not
if index & 0x8000:
index &= ~0x8000
symbol_version['hidden'] = True
if (self._versioninfo['verdef'] and
index <= self._versioninfo['verdef'].num_versions()):
_, verdaux_iter = \
self._versioninfo['verdef'].get_version(index)
symbol_version['name'] = next(verdaux_iter).name
else:
verneed, vernaux = \
self._versioninfo['verneed'].get_version(index)
symbol_version['name'] = vernaux.name
symbol_version['filename'] = verneed.name
symbol_version['index'] = index
return symbol_version