summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCyrille Bagard <nocbos@gmail.com>2018-04-30 13:44:56 (GMT)
committerCyrille Bagard <nocbos@gmail.com>2018-04-30 13:44:56 (GMT)
commitcf981a295153f12efdbe50d7bef54f13385d443c (patch)
tree6a4a2e9ab4d4e0548cf8d687c6d50fdfede2590b
Provided some initial samples of Python bindings usage.
-rw-r--r--python/ins_collect.py80
-rw-r--r--python/ins_stats.py62
-rw-r--r--python/readelf.py574
3 files changed, 716 insertions, 0 deletions
diff --git a/python/ins_collect.py b/python/ins_collect.py
new file mode 100644
index 0000000..f48a49e
--- /dev/null
+++ b/python/ins_collect.py
@@ -0,0 +1,80 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+import sys
+import pychrysalide
+from pychrysalide.analysis.contents import FileContent
+from pychrysalide.format.elf import ElfFormat
+from pychrysalide.analysis import LoadedBinary
+
+
+if len(sys.argv) != 2:
+ print('Usage: %s <elf binary>' % sys.argv[0])
+ sys.exit(1)
+
+
+# Load the provided binary
+
+cnt = FileContent(sys.argv[1])
+
+fmt = ElfFormat(cnt)
+
+binary = LoadedBinary(fmt)
+
+binary.analyze_and_wait()
+
+
+# Compute some stats
+
+ins_count = 0
+
+opsize_0 = 0
+opsize_1 = 0
+
+srcsz_0 = 0
+srcsz_1 = 0
+
+destsz_0 = 0
+destsz_1 = 0
+
+for ins in binary.processor.instrs:
+
+ ins_count += 1
+
+ size = len(ins.operands)
+
+ if size == 0:
+ opsize_0 += 1
+
+ elif size == 1:
+ opsize_1 += 1
+
+ size = len(ins.sources)
+
+ if size == 0:
+ srcsz_0 += 1
+
+ elif size == 1:
+ srcsz_1 += 1
+
+ size = len(ins.destinations)
+
+ if size == 0:
+ destsz_0 += 1
+
+ elif size == 1:
+ destsz_1 += 1
+
+
+# Display the results
+
+print('=== Collected %d instructions ===' % ins_count)
+
+print('No operand: %u' % opsize_0)
+print('One operand: %u' % opsize_1)
+
+print('No source: %u' % srcsz_0)
+print('One source: %u' % srcsz_1)
+
+print('No destination: %u' % destsz_0)
+print('One destination: %u' % destsz_1)
diff --git a/python/ins_stats.py b/python/ins_stats.py
new file mode 100644
index 0000000..d9b5602
--- /dev/null
+++ b/python/ins_stats.py
@@ -0,0 +1,62 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+import sys
+import pychrysalide
+from pychrysalide.analysis.contents import FileContent
+from pychrysalide.format.dex import DexFormat
+from pychrysalide.analysis import LoadedBinary
+from threading import Event
+
+
+if len(sys.argv) != 2:
+ print('Usage: %s <dex classes>' % sys.argv[0])
+ sys.exit(1)
+
+
+# Load the provided binary
+
+cnt = FileContent(sys.argv[1])
+
+fmt = DexFormat(cnt)
+
+binary = LoadedBinary(fmt)
+
+binary.analyze_and_wait()
+
+
+# Compute some stats
+
+raw = [ "dn", "db", "dw", "dd", "dq" ]
+
+collected = { }
+
+max_len = 0
+ins_count = 0
+
+for ins in binary.processor.instrs:
+
+ if ins.keyword in raw:
+ continue
+
+ if len(ins.keyword) > max_len:
+ max_len = len(ins.keyword)
+
+ ins_count += 1
+
+ if ins.keyword in collected.keys():
+ collected[ins.keyword] += 1
+ else:
+ collected[ins.keyword] = 1
+
+
+# Display the results
+
+stats = [ (k, v) for k, v in collected.items() ]
+
+stats = sorted(stats, key = lambda s: s[1], reverse = True)
+
+print('=== Collected %d instructions ===' % ins_count)
+
+for s in stats:
+ print(' %s %d (%d%%)' % (s[0].ljust(max_len + 2, '.'), s[1], (s[1] * 100) / ins_count))
diff --git a/python/readelf.py b/python/readelf.py
new file mode 100644
index 0000000..5bc5e93
--- /dev/null
+++ b/python/readelf.py
@@ -0,0 +1,574 @@
+#!/usr/bin/python3
+# -*- coding: utf-8 -*-
+
+import argparse
+import math
+import sys
+import pychrysalide
+from collections import OrderedDict
+from pychrysalide.analysis.contents import FileContent
+from pychrysalide.analysis import LoadedBinary
+from pychrysalide.arch import vmpa
+from pychrysalide.format.elf import ElfFormat
+
+
+def _get_string(fmt, start, offset):
+ """Extract a given string."""
+
+ string = None
+
+ maxlen = fmt.content.compute_size()
+
+ end = start + offset
+
+ while end < maxlen:
+
+ byte = fmt.content.read_u8(vmpa(end, vmpa.VMPA_NO_VIRTUAL))
+
+ if byte == 0x00:
+ break
+
+ end += 1
+
+ string = fmt.content.read_raw(vmpa(start + offset, vmpa.VMPA_NO_VIRTUAL), end - start)
+
+ return string.decode('utf-8')
+
+
+def display_elf_header(fmt):
+ """Displays the information contained in the file's main header."""
+
+ # File class
+ elf_classes = {
+ ElfFormat.ELFCLASS32 : 'ELF32',
+ ElfFormat.ELFCLASS64 : 'ELF64'
+ }
+
+ # Data encoding
+ elf_encodings = {
+ ElfFormat.ELFDATA2LSB : "2's complement, little endian",
+ ElfFormat.ELFDATA2MSB : "2's complement, big endian"
+ }
+
+ # Object file type
+ elf_types = {
+ ElfFormat.ET_REL : 'Relocatable file',
+ ElfFormat.ET_EXEC : 'Executable file',
+ ElfFormat.ET_DYN : 'Shared object file',
+ ElfFormat.ET_CORE : 'Core file'
+ }
+
+ # Architecture
+ elf_machines = {
+ ElfFormat.EM_ARM : 'ARM',
+ ElfFormat.EM_AARCH64 : 'ARM AARCH64'
+ }
+
+ # ELF Header
+
+ header = fmt.get_header()
+
+ fields = OrderedDict()
+
+ fields['Magic'] = ' '.join([ '%02x' % c for c in header.e_ident ])
+ fields['Class'] = elf_classes[header.e_ident[ElfFormat.EI_CLASS]] if header.e_ident[ElfFormat.EI_CLASS] in elf_classes.keys() else 'Invalid'
+ fields['Data'] = elf_encodings[header.e_ident[ElfFormat.EI_DATA]] if header.e_ident[ElfFormat.EI_DATA] in elf_encodings.keys() else 'Invalid'
+ fields['Version'] = '%u' % header.e_ident[ElfFormat.EI_VERSION]
+ fields['OS/ABI'] = 'UNIX - System V' if header.e_ident[ElfFormat.EI_OSABI] == ElfFormat.ELFOSABI_SYSV else 'Other than UNIX'
+ fields['ABI Version'] = '%u' % header.e_ident[ElfFormat.EI_ABIVERSION]
+ fields['Type'] = elf_types[header.e_type] if header.e_type in elf_types.keys() else 'Other file type'
+ fields['Machine'] = elf_machines[header.e_machine] if header.e_machine in elf_machines.keys() else 'Other architecture'
+ fields['Version'] = '0x%x' % header.e_version
+ fields['Entry point address'] = '0x%x' % header.e_entry
+ fields['Start of program headers'] = '%u (bytes into file)' % header.e_phoff
+ fields['Start of section headers'] = '%u (bytes into file)' % header.e_shoff
+ fields['Flags'] = '0x%x' % header.e_flags
+ fields['Size of this header'] = '%u (bytes)' % header.e_ehsize
+ fields['Size of program headers'] = '%u (bytes)' % header.e_phentsize
+ fields['Number of program headers'] = '%u' % header.e_phnum
+ fields['Size of section headers'] = '%u (bytes)' % header.e_shentsize
+ fields['Number of section headers'] = '%u' % header.e_shnum
+ fields['Section header string table index'] = '%u' % header.e_shstrndx
+
+ # Compute the max length and the relative format
+
+ max_len = 0
+
+ for k in fields.keys():
+ if len(k) > max_len:
+ max_len = len(k)
+
+ max_len += len(':')
+
+ line = ' {0:<%d} {1}' % max_len
+
+ # Final display
+
+ print('ELF Header:')
+
+ for k, v in fields.items():
+ print(line.format(k + ':', v))
+
+ print()
+
+
+def display_elf_program_headers(fmt):
+ """Displays the information contained in the file's program headers, if it has any."""
+
+ # Segment type
+ segment_types = {
+ ElfFormat.PT_NULL : 'NULL',
+ ElfFormat.PT_LOAD : 'LOAD',
+ ElfFormat.PT_DYNAMIC : 'DYNAMIC',
+ ElfFormat.PT_INTERP : 'INTERP',
+ ElfFormat.PT_NOTE : 'NOTE',
+ ElfFormat.PT_SHLIB : 'SHLIB',
+ ElfFormat.PT_PHDR : 'PHDR',
+ ElfFormat.PT_TLS : 'TLS',
+ ElfFormat.PT_GNU_EH_FRAME : 'GNU_EH_FRAME',
+ ElfFormat.PT_GNU_STACK : 'GNU_STACK',
+ ElfFormat.PT_GNU_RELRO : 'GNU_RELRO'
+ }
+
+ # Data computing
+
+ header = fmt.get_header()
+
+ fields = []
+
+ fields.append([ 'Type', 'Offset', 'VirtAddr', 'PhysAddr', 'FileSiz', 'MemSiz', 'Flg', 'Align' ])
+
+ for i in range(header.e_phnum):
+
+ phdr = fmt.find_program_by_index(i)
+
+ fields.append([ segment_types[phdr.p_type] if phdr.p_type in segment_types.keys() else 'UNKNOWN',
+ '0x%x' % phdr.p_offset,
+ '0x%x' % phdr.p_vaddr,
+ '0x%x' % phdr.p_paddr,
+ '0x%x' % phdr.p_filesz,
+ '0x%x' % phdr.p_memsz,
+ '%c%c%c' % ('R' if phdr.p_flags & ElfFormat.PF_R else ' ',
+ 'W' if phdr.p_flags & ElfFormat.PF_W else ' ',
+ 'X' if phdr.p_flags & ElfFormat.PF_X else ' '),
+ '0x%x' % phdr.p_align])
+
+ # Max string length
+
+ count = len(fields[0])
+ lengths = [ 0 for i in range(count) ]
+
+ for f in fields:
+ for c in range(count):
+
+ if len(f[c]) > lengths[c]:
+ lengths[c] = len(f[c])
+
+ # Relative format string
+
+ line = ' '
+
+ for c in range(count):
+ line += '{%u:<%u}' % (c, lengths[c] + 1)
+
+ # Final display
+
+ print('Program Headers:')
+
+ for f in fields:
+ print(line.format(*f))
+
+ print()
+
+ # Second final display
+
+ line = ' {0:<7} {1}'
+
+ print('Section to Segment mapping:')
+
+ print(line.format('Segment', 'Sections...'))
+
+ for i in range(header.e_phnum):
+
+ phdr = fmt.find_program_by_index(i)
+
+ contained = ''
+
+ for j in range(header.e_shnum):
+
+ section = fmt.find_section_by_index(j)
+
+ if not (section.sh_flags & ElfFormat.SHF_ALLOC):
+ continue
+
+ if section.sh_addr < phdr.p_vaddr:
+ continue
+
+ if (section.sh_addr + section.sh_size) > (phdr.p_vaddr + phdr.p_memsz):
+ continue
+
+ if len(contained) > 0:
+ contained += ' ' + section.name
+ else:
+ contained = section.name
+
+ print(line.format(i, contained))
+
+ print()
+
+
+def display_elf_section_headers(fmt):
+ """Displays the information contained in the file's section headers, if it has any."""
+
+ # Section type
+ section_types = {
+ ElfFormat.SHT_NULL : 'NULL',
+ ElfFormat.SHT_PROGBITS : 'PROGBITS',
+ ElfFormat.SHT_SYMTAB : 'SYMTAB',
+ ElfFormat.SHT_STRTAB : 'STRTAB',
+ ElfFormat.SHT_RELA : 'RELA',
+ ElfFormat.SHT_HASH : 'HASH',
+ ElfFormat.SHT_DYNAMIC : 'DYNAMIC',
+ ElfFormat.SHT_NOTE : 'NOTE',
+ ElfFormat.SHT_NOBITS : 'NOBITS',
+ ElfFormat.SHT_REL : 'REL',
+ ElfFormat.SHT_SHLIB : 'SHLIB',
+ ElfFormat.SHT_DYNSYM : 'DYNSYM',
+ ElfFormat.SHT_INIT_ARRAY : 'NIT_ARRAY',
+ ElfFormat.SHT_FINI_ARRAY : 'FINI_ARRAY',
+ ElfFormat.SHT_PREINIT_ARRAY : 'PREINIT_ARRAY',
+ ElfFormat.SHT_GROUP : 'GROUP',
+ ElfFormat.SHT_SYMTAB_SHNDX : 'SYMTAB_SHNDX',
+ ElfFormat.SHT_GNU_ATTRIBUTES : 'GNU_ATTRIBUTES',
+ ElfFormat.SHT_GNU_HASH : 'GNU_HASH',
+ ElfFormat.SHT_GNU_LIBLIST : 'GNU_LIBLIST',
+ ElfFormat.SHT_CHECKSUM : 'CHECKSUM',
+ ElfFormat.SHT_SUNW_move : 'SUNW_move',
+ ElfFormat.SHT_SUNW_COMDAT : 'SUNW_COMDAT',
+ ElfFormat.SHT_SUNW_syminfo : 'SUNW_syminfo',
+ ElfFormat.SHT_GNU_verdef : 'GNU_verdef',
+ ElfFormat.SHT_GNU_verneed : 'GNU_verneed',
+ ElfFormat.SHT_GNU_versym : 'GNU_versym'
+ }
+
+
+ def build_section_flags(flags):
+
+ desc = ''
+
+ desc += 'W' if flags & ElfFormat.SHF_WRITE else ''
+ desc += 'A' if flags & ElfFormat.SHF_ALLOC else ''
+ desc += 'X' if flags & ElfFormat.SHF_EXECINSTR else ''
+ desc += 'M' if flags & ElfFormat.SHF_MERGE else ''
+ desc += 'S' if flags & ElfFormat.SHF_STRINGS else ''
+ desc += 'I' if flags & ElfFormat.SHF_INFO_LINK else ''
+ desc += 'L' if flags & ElfFormat.SHF_LINK_ORDER else ''
+ desc += 'G' if flags & ElfFormat.SHF_GROUP else ''
+ desc += 'T' if flags & ElfFormat.SHF_TLS else ''
+ desc += 'X' if flags & ElfFormat.SHF_EXCLUDE else ''
+
+ return desc
+
+
+ header = fmt.get_header()
+
+ count = header.e_shnum
+
+
+ section = fmt.find_section_by_index(header.e_shstrndx)
+
+ if section:
+ strtab_pos = section.sh_offset
+ else:
+ strtab_pos = None
+
+
+ # Compute max string lengths
+
+ name_maxlen = 0
+ type_maxlen = 0
+
+ esize_maxlen = 99 # ES (log10)
+ flags_maxlen = 3 # Flg
+ link_maxlen = 99 # Lk (log10)
+ info_maxlen = 999 # Inf (log10)
+ align_maxlen = 99 # Al (log10)
+
+ for i in range(header.e_shnum):
+
+ section = fmt.find_section_by_index(i)
+
+ if len(section.name) > name_maxlen:
+ name_maxlen = len(section.name)
+
+ if section.sh_type in section_types.keys():
+ if len(section_types[section.sh_type]) > type_maxlen:
+ type_maxlen = len(section_types[section.sh_type])
+
+ if section.sh_entsize > esize_maxlen:
+ esize_maxlen = section.sh_entsize
+
+ flags_desc = build_section_flags(section.sh_flags)
+
+ if len(flags_desc) > flags_maxlen:
+ flags_maxlen = len(flags_desc)
+
+ if section.sh_link > link_maxlen:
+ link_maxlen = section.sh_link
+
+ if section.sh_info > info_maxlen:
+ info_maxlen = section.sh_info
+
+ if section.sh_addralign > align_maxlen:
+ align_maxlen = section.sh_addralign
+
+ # Relative format string
+
+ esize_maxlen = math.log10(esize_maxlen)
+ link_maxlen = math.log10(link_maxlen)
+ info_maxlen = math.log10(info_maxlen)
+ align_maxlen = math.log10(align_maxlen)
+
+ if esize_maxlen % 1:
+ esize_maxlen +=1
+
+ if link_maxlen % 1:
+ link_maxlen +=1
+ if info_maxlen % 1:
+ info_maxlen +=1
+ if align_maxlen % 1:
+ align_maxlen +=1
+
+ esize_maxlen = int(esize_maxlen)
+ link_maxlen = int(link_maxlen)
+ info_maxlen = int(info_maxlen)
+ align_maxlen = int(align_maxlen)
+
+ line = ' [{0:>2}] {1:<%u} {2:<%u} {3:<8} {4:<8} {5:<8} {6:>%u} {7:>%u} {8:>%u} {9:>%u} {10:>%u}' \
+ % (name_maxlen, type_maxlen, esize_maxlen, flags_maxlen, link_maxlen, info_maxlen, align_maxlen)
+
+ # Final display
+
+ headers = [ 'NR', 'Name', 'Type', 'Addr', 'Off', 'Size', 'ES', 'Flg', 'Lk', 'Inf', 'Al' ]
+
+ print('Section Headers:')
+ print(line.format(*headers))
+
+ for i in range(header.e_shnum):
+
+ section = fmt.find_section_by_index(i)
+
+ if section.sh_type in section_types.keys():
+ sec_type = section_types[section.sh_type]
+ else:
+ sec_type = '???'
+
+ flags_desc = build_section_flags(section.sh_flags)
+
+ print(line.format(i, section.name, sec_type, '%08x' % section.sh_addr, '%08x' % section.sh_offset, '%08x' % section.sh_size,
+ '%x' % section.sh_entsize, flags_desc, '%u' % section.sh_link, '%u' % section.sh_info, '%u' % section.sh_addralign))
+
+ print()
+
+ print('Key to Flags:')
+ print(' W (write), A (alloc), X (execute), M (merge), S (strings)')
+ print(' I (info), L (link order), G (group), T (TLS), E (exclude)')
+
+ print()
+
+
+def display_elf_dynamic_items(fmt):
+ """Displays the information contained in the file's dynamic items, if it has any."""
+
+ # Dynamic entry types
+ elf_dynamic_types = {
+ ElfFormat.DT_NULL : 'NULL',
+ ElfFormat.DT_NEEDED : 'NEEDED',
+ ElfFormat.DT_PLTRELSZ : 'PLTRELSZ',
+ ElfFormat.DT_PLTGOT : 'PLTGOT',
+ ElfFormat.DT_HASH : 'HASH',
+ ElfFormat.DT_STRTAB : 'STRTAB',
+ ElfFormat.DT_SYMTAB : 'SYMTAB',
+ ElfFormat.DT_RELA : 'RELA',
+ ElfFormat.DT_RELASZ : 'RELASZ',
+ ElfFormat.DT_RELAENT : 'RELAENT',
+ ElfFormat.DT_STRSZ : 'STRSZ',
+ ElfFormat.DT_SYMENT : 'SYMENT',
+ ElfFormat.DT_INIT : 'INIT',
+ ElfFormat.DT_FINI : 'FINI',
+ ElfFormat.DT_SONAME : 'SONAME',
+ ElfFormat.DT_RPATH : 'RPATH',
+ ElfFormat.DT_SYMBOLIC : 'SYMBOLIC',
+ ElfFormat.DT_REL : 'REL',
+ ElfFormat.DT_RELSZ : 'RELSZ',
+ ElfFormat.DT_RELENT : 'RELENT',
+ ElfFormat.DT_PLTREL : 'PLTREL',
+ ElfFormat.DT_DEBUG : 'DEBUG',
+ ElfFormat.DT_TEXTREL : 'TEXTREL',
+ ElfFormat.DT_JMPREL : 'JMPREL',
+ ElfFormat.DT_BIND_NOW : 'BIND_NOW',
+ ElfFormat.DT_INIT_ARRAY : 'INIT_ARRAY',
+ ElfFormat.DT_FINI_ARRAY : 'FINI_ARRAY',
+ ElfFormat.DT_INIT_ARRAYSZ : 'INIT_ARRAYSZ',
+ ElfFormat.DT_FINI_ARRAYSZ : 'FINI_ARRAYSZ',
+ ElfFormat.DT_RUNPATH : 'RUNPATH',
+ ElfFormat.DT_FLAGS : 'FLAGS',
+ ElfFormat.DT_ENCODING : 'ENCODING',
+ ElfFormat.DT_PREINIT_ARRAY : 'PREINIT_ARRAY',
+ ElfFormat.DT_PREINIT_ARRAYSZ : 'PREINIT_ARRAYSZ'
+ }
+
+ # See http://www.sco.com/developers/gabi/latest/ch5.dynamic.html
+ elf_dynamic_values = {
+ ElfFormat.DT_NULL : '0x%x',
+ ElfFormat.DT_NEEDED : 'Shared library: [%s]',
+ ElfFormat.DT_PLTRELSZ : '%u (bytes)',
+ ElfFormat.DT_PLTGOT : '0x%x',
+ ElfFormat.DT_HASH : '0x%x',
+ ElfFormat.DT_STRTAB : '0x%x',
+ ElfFormat.DT_SYMTAB : '0x%x',
+ ElfFormat.DT_RELA : '0x%x',
+ ElfFormat.DT_RELASZ : '%u (bytes)',
+ ElfFormat.DT_RELAENT : '%u (bytes)',
+ ElfFormat.DT_STRSZ : '%u (bytes)',
+ ElfFormat.DT_SYMENT : '%u (bytes)',
+ ElfFormat.DT_INIT : '0x%x',
+ ElfFormat.DT_FINI : '0x%x',
+ ElfFormat.DT_SONAME : '%u',
+ ElfFormat.DT_RPATH : '%u',
+ ElfFormat.DT_SYMBOLIC : '0x%x',
+ ElfFormat.DT_REL : '0x%x',
+ ElfFormat.DT_RELSZ : '%u (bytes)',
+ ElfFormat.DT_RELENT : '%u (bytes)',
+ ElfFormat.DT_PLTREL : '%u',
+ ElfFormat.DT_DEBUG : '0x%x',
+ ElfFormat.DT_TEXTREL : '0x%x',
+ ElfFormat.DT_JMPREL : '0x%x',
+ ElfFormat.DT_BIND_NOW : '0x%x',
+ ElfFormat.DT_INIT_ARRAY : '0x%x',
+ ElfFormat.DT_FINI_ARRAY : '0x%x',
+ ElfFormat.DT_INIT_ARRAYSZ : '%u (bytes)',
+ ElfFormat.DT_FINI_ARRAYSZ : '%u (bytes)',
+ ElfFormat.DT_RUNPATH : '%u',
+ ElfFormat.DT_FLAGS : '0x%x',
+ ElfFormat.DT_ENCODING : '0x%x',
+ ElfFormat.DT_PREINIT_ARRAY : '%u (bytes)',
+ ElfFormat.DT_PREINIT_ARRAYSZ : '%u (bytes)'
+ }
+
+ # Find the right segment & data
+
+ phdr = fmt.find_program_by_type(ElfFormat.PT_DYNAMIC)
+
+ assert(phdr.p_filesz % fmt.sizeof_dyn == 0)
+
+ count = int(phdr.p_filesz / fmt.sizeof_dyn)
+
+ # Fix the item counter !?
+
+ for i in range(count):
+
+ item = fmt.find_dynamic_item_by_index(i)
+
+ if item.d_tag == ElfFormat.DT_NULL:
+ break
+
+ count = i + 1
+
+ # Get the string location
+
+ strtab_pos = None
+ strtab_addr = None
+
+ for i in range(count):
+
+ item = fmt.find_dynamic_item_by_index(i)
+
+ if item.d_tag == ElfFormat.DT_STRTAB:
+ strtab_addr = item['d_un.d_ptr']
+ break
+
+ loc = fmt.translate_address_into_vmpa(strtab_addr)
+ assert(loc)
+
+ strtab_pos = loc.phys
+
+ # Final display
+
+ print('Dynamic section at offset 0x%x contains %u %s:' % (phdr.p_offset, count, 'entries' if count > 1 else 'entry'))
+
+ line = ' {0:<10} {1:<30} {2}'
+
+ print(line.format(' Tag', ' Type', ' Name/Value'))
+
+ line = ' {0} {1:<30} {2}'
+
+ for i in range(count):
+
+ item = fmt.find_dynamic_item_by_index(i)
+
+ item_type = '(%s)' % elf_dynamic_types[item.d_tag] if item.d_tag in elf_dynamic_types.keys() else '(UNKNOWN)'
+
+ item_format = elf_dynamic_values[item.d_tag] if item.d_tag in elf_dynamic_values.keys() else '0x%x'
+
+ if '%s' in item_format:
+ if strtab_pos is None:
+ item_value = item_format % item['d_un.d_val']
+ else:
+ item_value = item_format % _get_string(fmt, strtab_pos, item['d_un.d_val'])
+
+ elif '%u' in item_format:
+ item_value = item_format % item['d_un.d_val']
+
+ else:
+ item_value = item_format % item['d_un.d_ptr']
+
+ print(line.format('0x%08x' % item.d_tag, item_type, item_value))
+
+ if item.d_tag == ElfFormat.DT_NULL:
+ break
+
+ print()
+
+
+if __name__ == '__main__':
+
+ parser = argparse.ArgumentParser(description='readelf - Displays information about ELF files.', add_help=False)
+
+ parser.add_argument('-H', '--help', action='store_true', help='Display the command line options understood by readelf.')
+
+ parser.add_argument('-a', '--all', action='store_true', help='Equivalent to specifying --file-header, --segments, --sections, --dynamic.')
+ parser.add_argument('-h', '--file-header', action='store_true', help='Displays the information contained in the ELF header at the start of the file.')
+ parser.add_argument('-l', '--program-headers', '--segments', action='store_true', help='Displays the information contained in the file\'s segment headers, if it has any.')
+ parser.add_argument('-S', '--section-headers', '--sections', action='store_true', help='Displays the information contained in the file\'s section headers, if it has any.')
+ parser.add_argument('-d', '--dynamic', action='store_true', help='Displays the contents of the file\'s dynamic section, if it has one.')
+
+ parser.add_argument('elffile', type=str, help='The object file to be examined')
+
+ args = parser.parse_args()
+
+ if args.help:
+ parser.print_help()
+ sys.exit(1)
+
+ cnt = FileContent(args.elffile)
+
+ fmt = ElfFormat(cnt)
+
+ binary = LoadedBinary(fmt)
+
+ binary.analyze_and_wait()
+
+ print()
+
+ if args.all or args.file_header:
+ display_elf_header(fmt)
+
+ if args.all or args.program_headers:
+ display_elf_program_headers(fmt)
+
+ if args.all or args.section_headers:
+ display_elf_section_headers(fmt)
+
+ if args.all or args.dynamic:
+ display_elf_dynamic_items(fmt)