mirror of
https://github.com/lief-project/LIEF
synced 2026-06-08 15:30:44 +00:00
960 lines
30 KiB
Python
960 lines
30 KiB
Python
#!/usr/bin/env python
|
|
"""Pretty-print the structure of a PE binary.
|
|
|
|
Equivalent to ``dumpbin``/``llvm-readobj`` with a selection of the
|
|
most useful flags. The file is parsed with ``lief.PE.parse`` and each
|
|
requested section (DOS/optional header, sections, imports, exports,
|
|
resources, TLS, debug, authenticode, ...) is rendered as a formatted
|
|
table.
|
|
|
|
Example:
|
|
|
|
$ python pe_reader.py -a program.exe
|
|
"""
|
|
|
|
import argparse
|
|
import sys
|
|
import traceback
|
|
|
|
import lief
|
|
from lief import PE
|
|
|
|
|
|
class exceptions_handler(object):
|
|
func = None
|
|
|
|
def __init__(self, exceptions, on_except_callback=None):
|
|
self.exceptions = exceptions
|
|
self.on_except_callback = on_except_callback
|
|
|
|
def __call__(self, *args, **kwargs):
|
|
if self.func is None:
|
|
self.func = args[0]
|
|
return self
|
|
try:
|
|
return self.func(*args, **kwargs)
|
|
except self.exceptions as e:
|
|
if self.on_except_callback is not None:
|
|
self.on_except_callback(e)
|
|
else:
|
|
print("-" * 60)
|
|
print("Exception in {}: {}".format(self.func.__name__, e))
|
|
exc_type, exc_value, exc_traceback = sys.exc_info()
|
|
traceback.print_tb(exc_traceback)
|
|
print("-" * 60)
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_information(binary):
|
|
print("== Information ==\n")
|
|
format_str = "{:<30} {:<30}"
|
|
format_hex = "{:<30} 0x{:<28x}"
|
|
print(format_hex.format("Virtual size:", binary.virtual_size))
|
|
print(format_str.format("Imphash:", PE.get_imphash(binary)))
|
|
print(format_str.format("PIE:", str(binary.is_pie)))
|
|
print(format_str.format("NX:", str(binary.has_nx)))
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_header(binary):
|
|
dos_header = binary.dos_header
|
|
header = binary.header
|
|
optional_header = binary.optional_header
|
|
|
|
format_str = "{:<33} {:<30}"
|
|
format_hex = "{:<33} 0x{:<28x}"
|
|
format_dec = "{:<33} {:<30d}"
|
|
|
|
print("== Dos Header ==")
|
|
print(format_str.format("Magic:", str((dos_header.magic))))
|
|
print(
|
|
format_dec.format(
|
|
"Used bytes in the last page:", dos_header.used_bytes_in_last_page
|
|
)
|
|
)
|
|
print(format_dec.format("File size in pages:", dos_header.file_size_in_pages))
|
|
print(format_dec.format("Number of relocations:", dos_header.numberof_relocation))
|
|
print(
|
|
format_dec.format(
|
|
"Header size in paragraphs:", dos_header.header_size_in_paragraphs
|
|
)
|
|
)
|
|
print(
|
|
format_dec.format(
|
|
"Minimum extra paragraphs:", dos_header.minimum_extra_paragraphs
|
|
)
|
|
)
|
|
print(
|
|
format_dec.format(
|
|
"Maximum extra paragraphs", dos_header.maximum_extra_paragraphs
|
|
)
|
|
)
|
|
print(format_dec.format("Initial relative SS", dos_header.initial_relative_ss))
|
|
print(format_hex.format("Initial SP:", dos_header.initial_sp))
|
|
print(format_hex.format("Checksum:", dos_header.checksum))
|
|
print(format_dec.format("Initial IP:", dos_header.initial_ip))
|
|
print(format_dec.format("Initial CS:", dos_header.initial_relative_cs))
|
|
print(
|
|
format_hex.format(
|
|
"Address of relocation table:", dos_header.addressof_relocation_table
|
|
)
|
|
)
|
|
print(format_dec.format("Overlay number:", dos_header.overlay_number))
|
|
print(format_dec.format("OEM ID:", dos_header.oem_id))
|
|
print(format_dec.format("OEM information", dos_header.oem_info))
|
|
print(
|
|
format_hex.format(
|
|
"Address of optional header:", dos_header.addressof_new_exeheader
|
|
)
|
|
)
|
|
print("")
|
|
|
|
print("== Header ==")
|
|
|
|
char_str = " - ".join(
|
|
[str(chara).split(".")[-1] for chara in header.characteristics_list]
|
|
)
|
|
|
|
print(format_str.format("Signature:", "".join(map(chr, header.signature))))
|
|
print(format_str.format("Machine:", str(header.machine)))
|
|
print(format_dec.format("Number of sections:", header.numberof_sections))
|
|
print(format_dec.format("Time Date stamp:", header.time_date_stamps))
|
|
print(format_dec.format("Pointer to symbols:", header.pointerto_symbol_table))
|
|
print(format_dec.format("Number of symbols:", header.numberof_symbols))
|
|
print(format_dec.format("Size of optional header:", header.sizeof_optional_header))
|
|
print(format_str.format("Characteristics:", char_str))
|
|
print("")
|
|
|
|
dll_char_str = " - ".join(
|
|
[
|
|
str(chara).split(".")[-1]
|
|
for chara in optional_header.dll_characteristics_lists
|
|
]
|
|
)
|
|
subsystem_str = str(optional_header.subsystem).split(".")[-1]
|
|
print("== Optional Header ==")
|
|
magic = "PE32" if optional_header.magic == PE.PE_TYPE.PE32 else "PE64"
|
|
print(format_str.format("Magic:", magic))
|
|
print(
|
|
format_dec.format("Major linker version:", optional_header.major_linker_version)
|
|
)
|
|
print(
|
|
format_dec.format("Minor linker version:", optional_header.minor_linker_version)
|
|
)
|
|
print(format_dec.format("Size of code:", optional_header.sizeof_code))
|
|
print(
|
|
format_dec.format(
|
|
"Size of initialized data:", optional_header.sizeof_initialized_data
|
|
)
|
|
)
|
|
print(
|
|
format_dec.format(
|
|
"Size of uninitialized data:", optional_header.sizeof_uninitialized_data
|
|
)
|
|
)
|
|
print(format_hex.format("Entry point:", optional_header.addressof_entrypoint))
|
|
print(format_hex.format("Base of code:", optional_header.baseof_code))
|
|
if magic == "PE32":
|
|
print(format_hex.format("Base of data", optional_header.baseof_data))
|
|
print(format_hex.format("Image base:", optional_header.imagebase))
|
|
print(format_hex.format("Section alignment:", optional_header.section_alignment))
|
|
print(format_hex.format("File alignment:", optional_header.file_alignment))
|
|
print(
|
|
format_dec.format(
|
|
"Major operating system version:",
|
|
optional_header.major_operating_system_version,
|
|
)
|
|
)
|
|
print(
|
|
format_dec.format(
|
|
"Minor operating system version:",
|
|
optional_header.minor_operating_system_version,
|
|
)
|
|
)
|
|
print(
|
|
format_dec.format("Major image version:", optional_header.major_image_version)
|
|
)
|
|
print(
|
|
format_dec.format("Minor image version:", optional_header.minor_image_version)
|
|
)
|
|
print(
|
|
format_dec.format(
|
|
"Major subsystem version:", optional_header.major_subsystem_version
|
|
)
|
|
)
|
|
print(
|
|
format_dec.format(
|
|
"Minor subsystem version:", optional_header.minor_subsystem_version
|
|
)
|
|
)
|
|
print(
|
|
format_dec.format("WIN32 version value:", optional_header.win32_version_value)
|
|
)
|
|
print(format_hex.format("Size of image:", optional_header.sizeof_image))
|
|
print(format_hex.format("Size of headers:", optional_header.sizeof_headers))
|
|
print(format_hex.format("Checksum:", optional_header.checksum))
|
|
print(format_str.format("Subsystem:", subsystem_str))
|
|
print(format_str.format("DLL Characteristics:", dll_char_str))
|
|
print(
|
|
format_hex.format(
|
|
"Size of stack reserve:", optional_header.sizeof_stack_reserve
|
|
)
|
|
)
|
|
print(
|
|
format_hex.format("Size of stack commit:", optional_header.sizeof_stack_commit)
|
|
)
|
|
print(
|
|
format_hex.format("Size of heap reserve:", optional_header.sizeof_heap_reserve)
|
|
)
|
|
print(format_hex.format("Size of heap commit:", optional_header.sizeof_heap_commit))
|
|
print(format_dec.format("Loader flags:", optional_header.loader_flags))
|
|
print(
|
|
format_dec.format(
|
|
"Number of RVA and size:", optional_header.numberof_rva_and_size
|
|
)
|
|
)
|
|
print("")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_data_directories(binary):
|
|
data_directories = binary.data_directories
|
|
|
|
print("== Data Directories ==")
|
|
f_title = "|{:<24} | {:<10} | {:<10} | {:<8} |"
|
|
f_value = "|{:<24} | 0x{:<8x} | 0x{:<8x} | {:<8} |"
|
|
print(f_title.format("Type", "RVA", "Size", "Section"))
|
|
|
|
for directory in data_directories:
|
|
section_name = directory.section.name if directory.has_section else ""
|
|
print(
|
|
f_value.format(
|
|
str(directory.type).split(".")[-1],
|
|
directory.rva,
|
|
directory.size,
|
|
section_name,
|
|
)
|
|
)
|
|
print("")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_sections(binary):
|
|
sections = binary.sections
|
|
|
|
print("== Sections ==")
|
|
f_title = "|{:<10} | {:<16} | {:<16} | {:<18} | {:<16} | {:<9} | {:<9}"
|
|
f_value = (
|
|
"|{:<10} | 0x{:<14x} | 0x{:<14x} | 0x{:<16x} | 0x{:<14x} | {:<9.2f} | {:<9}"
|
|
)
|
|
print(
|
|
f_title.format(
|
|
"Name",
|
|
"Offset",
|
|
"Size",
|
|
"Virtual Address",
|
|
"Virtual size",
|
|
"Entropy",
|
|
"Flags",
|
|
)
|
|
)
|
|
|
|
for section in sections:
|
|
flags = ""
|
|
for flag in section.characteristics_lists:
|
|
flags += str(flag).split(".")[-1] + " "
|
|
print(
|
|
f_value.format(
|
|
section.name,
|
|
section.offset,
|
|
section.size,
|
|
section.virtual_address,
|
|
section.virtual_size,
|
|
section.entropy,
|
|
flags,
|
|
)
|
|
)
|
|
print("")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_symbols(binary):
|
|
symbols = binary.symbols
|
|
if len(symbols) > 0:
|
|
print("== Symbols ==")
|
|
f_title = "|{:<20} | {:<10} | {:<8} | {:<8} | {:<8} | {:<13} |"
|
|
f_value = "|{:<20} | 0x{:<8x} | {:<14} | {:<10} | {:<12} | {:<13} |"
|
|
|
|
print(
|
|
f_title.format(
|
|
"Name",
|
|
"Value",
|
|
"Section number",
|
|
"Basic type",
|
|
"Complex type",
|
|
"Storage class",
|
|
)
|
|
)
|
|
for symbol in symbols:
|
|
section_nb_str = ""
|
|
if symbol.section_number <= 0:
|
|
section_nb_str = str(
|
|
PE.SYMBOL_SECTION_NUMBER(symbol.section_number)
|
|
).split(".")[-1]
|
|
else:
|
|
try:
|
|
section_nb_str = symbol.section.name
|
|
except Exception:
|
|
section_nb_str = "section<{:d}>".format(symbol.section_number)
|
|
|
|
print(
|
|
f_value.format(
|
|
symbol.name[:20],
|
|
symbol.value,
|
|
section_nb_str,
|
|
str(symbol.base_type).split(".")[-1],
|
|
str(symbol.complex_type).split(".")[-1],
|
|
str(symbol.storage_class).split(".")[-1],
|
|
)
|
|
)
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_imports(binary, resolve=False):
|
|
print("== Imports ==")
|
|
imports = binary.imports
|
|
|
|
for import_ in imports:
|
|
if resolve:
|
|
import_ = lief.PE.resolve_ordinals(import_)
|
|
|
|
print(import_.name)
|
|
entries = import_.entries
|
|
f_value = " {:<33} 0x{:<14x} 0x{:<14x} 0x{:<16x}"
|
|
for entry in entries:
|
|
print(f_value.format(entry.name, entry.data, entry.iat_value, entry.hint))
|
|
print("")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_tls(binary):
|
|
format_str = "{:<33} {:<30}"
|
|
format_hex = "{:<33} 0x{:<28x}"
|
|
|
|
print("== TLS ==")
|
|
tls = binary.tls
|
|
callbacks = tls.callbacks
|
|
print(format_hex.format("Address of callbacks:", tls.addressof_callbacks))
|
|
if len(callbacks) > 0:
|
|
print("Callbacks:")
|
|
for callback in callbacks:
|
|
print(" " + hex(callback))
|
|
|
|
print(format_hex.format("Address of index:", tls.addressof_index))
|
|
print(format_hex.format("Size of zero fill:", tls.sizeof_zero_fill))
|
|
print(
|
|
"{:<33} 0x{:<10x} 0x{:<10x}".format(
|
|
"Address of raw data:", tls.addressof_raw_data[0], tls.addressof_raw_data[1]
|
|
)
|
|
)
|
|
print(format_hex.format("Size of raw data:", len(tls.data_template)))
|
|
print(format_hex.format("Characteristics:", tls.characteristics))
|
|
print(format_str.format("Section:", tls.section.name))
|
|
print(format_str.format("Data directory:", str(tls.directory.type)))
|
|
print("")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_relocations(binary):
|
|
relocations = binary.relocations
|
|
print("== Relocations ==")
|
|
for relocation in relocations:
|
|
entries = relocation.entries
|
|
print(hex(relocation.virtual_address))
|
|
for entry in entries:
|
|
print(
|
|
" 0x{:<8x} {:<8}".format(
|
|
entry.position, str(entry.type).split(".")[-1]
|
|
)
|
|
)
|
|
print("")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_export(binary):
|
|
print("== Exports ==")
|
|
exports = binary.get_export()
|
|
entries = exports.entries
|
|
f_value = "{:<20} 0x{:<10x} 0x{:<10x} 0x{:<6x} 0x{:<6x} 0x{:<10x}"
|
|
print(
|
|
f_value.format(
|
|
exports.name,
|
|
exports.export_flags,
|
|
exports.timestamp,
|
|
exports.major_version,
|
|
exports.minor_version,
|
|
exports.ordinal_base,
|
|
)
|
|
)
|
|
entries = sorted(entries, key=lambda e: e.ordinal)
|
|
for entry in entries:
|
|
extern = "[EXTERN]" if entry.is_extern else ""
|
|
print(
|
|
" {:<20} {:d} 0x{:<10x} {:<13}".format(
|
|
entry.name[:20], entry.ordinal, entry.address, extern
|
|
)
|
|
)
|
|
print("")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_debug(binary):
|
|
format_str = "{:<33} {:<30}"
|
|
format_hex = "{:<33} 0x{:<28x}"
|
|
format_dec = "{:<33} {:<30d}"
|
|
|
|
debugs = binary.debug
|
|
print("== Debug ({}) ==".format(len(debugs)))
|
|
for debug in debugs:
|
|
print(format_hex.format("Characteristics:", debug.characteristics))
|
|
print(format_hex.format("Timestamp:", debug.timestamp))
|
|
print(format_dec.format("Major version:", debug.major_version))
|
|
print(format_dec.format("Minor version:", debug.minor_version))
|
|
print(format_str.format("type:", str(debug.type).split(".")[-1]))
|
|
print(format_hex.format("Size of data:", debug.sizeof_data))
|
|
print(format_hex.format("Address of raw data:", debug.addressof_rawdata))
|
|
print(format_hex.format("Pointer to raw data:", debug.pointerto_rawdata))
|
|
|
|
if isinstance(debug, lief.PE.CodeViewPDB):
|
|
code_view: lief.PE.CodeViewPDB = debug
|
|
cv_signature = code_view.cv_signature
|
|
sig_str = " ".join(map(lambda e: "{:02x}".format(e), code_view.signature))
|
|
print(
|
|
format_str.format(
|
|
"Code View Signature:", str(cv_signature).split(".")[-1]
|
|
)
|
|
)
|
|
print(format_str.format("Signature:", sig_str))
|
|
print(format_dec.format("Age:", code_view.age))
|
|
print(format_str.format("Filename:", code_view.filename))
|
|
elif isinstance(debug, lief.PE.CodeView):
|
|
code_view: lief.PE.CodeView = debug
|
|
cv_signature = code_view.cv_signature
|
|
print(
|
|
format_str.format(
|
|
"Code View Signature:", str(cv_signature).split(".")[-1]
|
|
)
|
|
)
|
|
elif isinstance(debug, lief.PE.Pogo):
|
|
pogo: lief.PE.Pogo = debug
|
|
sig_str = str(pogo.signature).split(".")[-1]
|
|
print(format_str.format("Signature:", sig_str))
|
|
print("Entries:")
|
|
for entry in pogo.entries:
|
|
print(
|
|
" {:<20} 0x{:x} ({:d})".format(
|
|
entry.name, entry.start_rva, entry.size
|
|
)
|
|
)
|
|
|
|
print("\n")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_signature(binary):
|
|
for signature in binary.signatures:
|
|
print(signature)
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_rich_header(binary):
|
|
print("== Rich Header ==")
|
|
header = binary.rich_header
|
|
print("Key: 0x{:08x}".format(header.key))
|
|
|
|
for entry in header.entries:
|
|
print(
|
|
" - ID: {:04x} Build ID: {:04x} Count: {:d}".format(
|
|
entry.id, entry.build_id, entry.count
|
|
)
|
|
)
|
|
print("")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_resources(binary):
|
|
print("== Resources ==")
|
|
manager = binary.resources_manager
|
|
|
|
print(manager)
|
|
|
|
print("")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_load_configuration(binary):
|
|
format_str = "{:<45} {:<30}"
|
|
format_hex = "{:<45} 0x{:<28x}"
|
|
format_dec = "{:<45} {:<30d}"
|
|
|
|
print("== Load Configuration ==")
|
|
config = binary.load_configuration
|
|
|
|
print(format_str.format("Version:", str(config.version).split(".")[-1]))
|
|
print(format_dec.format("Characteristics:", config.characteristics))
|
|
print(format_dec.format("Timedatestamp:", config.timedatestamp))
|
|
print(format_dec.format("Major version:", config.major_version))
|
|
print(format_dec.format("Minor version:", config.minor_version))
|
|
print(format_hex.format("Global flags clear:", config.global_flags_clear))
|
|
print(format_hex.format("Global flags set:", config.global_flags_set))
|
|
print(
|
|
format_dec.format(
|
|
"Critical section default timeout:", config.critical_section_default_timeout
|
|
)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"Decommit free block threshold:", config.decommit_free_block_threshold
|
|
)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"Decommit total free threshold:", config.decommit_total_free_threshold
|
|
)
|
|
)
|
|
print(format_hex.format("Lock prefix table:", config.lock_prefix_table))
|
|
print(format_hex.format("Maximum allocation size:", config.maximum_allocation_size))
|
|
print(
|
|
format_hex.format("Virtual memory threshold:", config.virtual_memory_threshold)
|
|
)
|
|
print(format_hex.format("Process affinity mask:", config.process_affinity_mask))
|
|
print(format_hex.format("Process heap flags:", config.process_heap_flags))
|
|
print(format_hex.format("CSD Version:", config.csd_version))
|
|
print(format_hex.format("Reserved 1:", config.reserved1))
|
|
print(format_hex.format("Edit list:", config.editlist))
|
|
print(format_hex.format("Security cookie:", config.security_cookie))
|
|
|
|
if isinstance(config, lief.PE.LoadConfigurationV0):
|
|
print(format_hex.format("SE handler table:", config.se_handler_table))
|
|
print(format_dec.format("SE handler count:", config.se_handler_count))
|
|
|
|
if isinstance(config, lief.PE.LoadConfigurationV1):
|
|
flags_str = " - ".join(
|
|
map(lambda e: str(e).split(".")[-1], config.guard_cf_flags_list)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"GCF check function pointer:", config.guard_cf_check_function_pointer
|
|
)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"GCF dispatch function pointer:",
|
|
config.guard_cf_dispatch_function_pointer,
|
|
)
|
|
)
|
|
print(format_hex.format("GCF function table :", config.guard_cf_function_table))
|
|
print(format_dec.format("GCF Function count :", config.guard_cf_function_count))
|
|
print(
|
|
"{:<45} {} (0x{:x})".format(
|
|
"Guard flags:", flags_str, int(config.guard_flags)
|
|
)
|
|
)
|
|
|
|
if isinstance(config, lief.PE.LoadConfigurationV2):
|
|
code_integrity = config.code_integrity
|
|
print("Code Integrity:")
|
|
print(format_dec.format(" " * 3 + "Flags:", code_integrity.flags))
|
|
print(format_dec.format(" " * 3 + "Catalog:", code_integrity.catalog))
|
|
print(
|
|
format_hex.format(
|
|
" " * 3 + "Catalog offset:", code_integrity.catalog_offset
|
|
)
|
|
)
|
|
print(format_dec.format(" " * 3 + "Reserved:", code_integrity.reserved))
|
|
|
|
if isinstance(config, lief.PE.LoadConfigurationV3):
|
|
print(
|
|
format_hex.format(
|
|
"Guard address taken iat entry table:",
|
|
config.guard_address_taken_iat_entry_table,
|
|
)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"Guard address taken iat entry count:",
|
|
config.guard_address_taken_iat_entry_count,
|
|
)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"Guard long jump target table:", config.guard_long_jump_target_table
|
|
)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"Guard long jump target count:", config.guard_long_jump_target_count
|
|
)
|
|
)
|
|
|
|
if isinstance(config, lief.PE.LoadConfigurationV4):
|
|
print(
|
|
format_hex.format(
|
|
"Dynamic value relocation table:", config.dynamic_value_reloc_table
|
|
)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"Hybrid metadata pointer:", config.hybrid_metadata_pointer
|
|
)
|
|
)
|
|
|
|
if isinstance(config, lief.PE.LoadConfigurationV5):
|
|
print(
|
|
format_hex.format("GRF failure routine:", config.guard_rf_failure_routine)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"GRF failure routine function pointer:",
|
|
config.guard_rf_failure_routine_function_pointer,
|
|
)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"Dynamic value reloctable offset:",
|
|
config.dynamic_value_reloctable_offset,
|
|
)
|
|
)
|
|
print(
|
|
format_hex.format(
|
|
"Dynamic value reloctable section:",
|
|
config.dynamic_value_reloctable_section,
|
|
)
|
|
)
|
|
|
|
if isinstance(config, lief.PE.LoadConfigurationV6):
|
|
print(
|
|
format_hex.format(
|
|
"GRF verify stackpointer function pointer:",
|
|
config.guard_rf_verify_stackpointer_function_pointer,
|
|
)
|
|
)
|
|
print(format_hex.format("Hotpatch table offset:", config.hotpatch_table_offset))
|
|
|
|
if isinstance(config, lief.PE.LoadConfigurationV7):
|
|
print(format_hex.format("Reserved 3:", config.reserved3))
|
|
|
|
print("")
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_ctor(binary):
|
|
print("== Constructors ==\n")
|
|
|
|
print("Functions: ({:d})".format(len(binary.ctor_functions)))
|
|
for idx, f in enumerate(binary.ctor_functions):
|
|
print(" [{:d}] {}: 0x{:x}".format(idx, f.name, f.address))
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_exception_functions(binary):
|
|
print("== Exception functions ==\n")
|
|
|
|
print("Functions: ({:d})".format(len(binary.exception_functions)))
|
|
for idx, f in enumerate(binary.exception_functions):
|
|
print(" [{:d}] {}: 0x{:x}".format(idx, f.name, f.address))
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_functions(binary):
|
|
print("== Functions ==\n")
|
|
|
|
print("Functions: ({:d})".format(len(binary.functions)))
|
|
for idx, f in enumerate(binary.functions):
|
|
print(
|
|
" [{:d}] {}: 0x{:x} ({:d} bytes)".format(idx, f.name, f.address, f.size)
|
|
)
|
|
|
|
|
|
@exceptions_handler(Exception)
|
|
def print_delay_imports(binary):
|
|
delay_imports = binary.delay_imports
|
|
if len(delay_imports) == 0:
|
|
return
|
|
print("== Delay Imports ==\n")
|
|
for imp in delay_imports:
|
|
print(imp.name)
|
|
print(" Attribute: {}".format(imp.attribute))
|
|
print(" Handle: 0x{:x}".format(imp.handle))
|
|
print(" IAT: 0x{:x}".format(imp.iat))
|
|
print(" Names Table: 0x{:x}".format(imp.names_table))
|
|
print(" Bound IAT: 0x{:x}".format(imp.biat))
|
|
print(" Unload IAT: 0x{:x}".format(imp.uiat))
|
|
print(" Timestamp: 0x{:x}".format(imp.timestamp))
|
|
for entry in imp.entries:
|
|
print(
|
|
" {:<25} 0x{:08x}: 0x{:010x} - 0x{:x}".format(
|
|
entry.name, entry.value, entry.iat_value, entry.hint
|
|
)
|
|
)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("pe_file")
|
|
|
|
parser.add_argument(
|
|
"-a",
|
|
"--all",
|
|
action="store_true",
|
|
dest="show_all",
|
|
help="Show all informations",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-d",
|
|
"--data-directories",
|
|
action="store_true",
|
|
dest="show_data_directories",
|
|
help="Display data directories",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--dbg", action="store_true", dest="show_debug", help="Display debug directory"
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-g",
|
|
"--signature",
|
|
action="store_true",
|
|
dest="show_signature",
|
|
help="Display the binary's signature if any",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-H",
|
|
"--header",
|
|
action="store_true",
|
|
dest="show_headers",
|
|
help="Display headers",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-i",
|
|
"--import",
|
|
action="store_true",
|
|
dest="show_imports",
|
|
help="Display imported functions and libraries",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--resolve-ordinals",
|
|
action="store_true",
|
|
dest="resolve_ordinals",
|
|
help="When used with --import, it attempts to resolve names of ordinal imports",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-r",
|
|
"--relocs",
|
|
action="store_true",
|
|
dest="show_relocs",
|
|
help="Display the relocations (if present)",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-R",
|
|
"--rich-header",
|
|
action="store_true",
|
|
dest="show_richheader",
|
|
help="Display the Rich Header",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--resources",
|
|
"--rsrc",
|
|
action="store_true",
|
|
dest="show_resources",
|
|
help="Display the resources (if present)",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-S",
|
|
"--section-headers",
|
|
"--sections",
|
|
action="store_true",
|
|
dest="show_section_header",
|
|
help="Display the sections' headers",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-s",
|
|
"--symbols",
|
|
"--syms",
|
|
action="store_true",
|
|
dest="show_symbols",
|
|
help="Display symbols",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-t",
|
|
"--tls",
|
|
action="store_true",
|
|
dest="show_tls",
|
|
help="Display TLS informations",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-x",
|
|
"--export",
|
|
action="store_true",
|
|
dest="show_export",
|
|
help="Display exported functions/libraries",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--load-config",
|
|
action="store_true",
|
|
dest="show_loadconfig",
|
|
help="Display load configuration",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--ctor", action="store_true", dest="show_ctor", help="Constructor functions"
|
|
)
|
|
|
|
parser.add_argument(
|
|
"-f",
|
|
"--functions",
|
|
action="store_true",
|
|
dest="show_functions",
|
|
help="Display all functions found in the binary",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--exception-functions",
|
|
action="store_true",
|
|
dest="show_pfunctions",
|
|
help="Display functions found in the exception directory",
|
|
)
|
|
|
|
parser.add_argument(
|
|
"--delay-imports",
|
|
action="store_true",
|
|
dest="show_delay_imports",
|
|
help="Display delay imports",
|
|
)
|
|
|
|
# Logging setup
|
|
logger_group = parser.add_argument_group("Logger")
|
|
verbosity = logger_group.add_mutually_exclusive_group()
|
|
|
|
verbosity.add_argument(
|
|
"--debug",
|
|
dest="main_verbosity",
|
|
action="store_const",
|
|
const=lief.logging.LEVEL.DEBUG,
|
|
)
|
|
|
|
verbosity.add_argument(
|
|
"--trace",
|
|
dest="main_verbosity",
|
|
action="store_const",
|
|
const=lief.logging.LEVEL.TRACE,
|
|
)
|
|
|
|
verbosity.add_argument(
|
|
"--info",
|
|
dest="main_verbosity",
|
|
action="store_const",
|
|
const=lief.logging.LEVEL.INFO,
|
|
)
|
|
|
|
verbosity.add_argument(
|
|
"--warn",
|
|
dest="main_verbosity",
|
|
action="store_const",
|
|
const=lief.logging.LEVEL.WARN,
|
|
)
|
|
|
|
verbosity.add_argument(
|
|
"--err",
|
|
dest="main_verbosity",
|
|
action="store_const",
|
|
const=lief.logging.LEVEL.ERROR,
|
|
)
|
|
|
|
verbosity.add_argument(
|
|
"--critical",
|
|
dest="main_verbosity",
|
|
action="store_const",
|
|
const=lief.logging.LEVEL.CRITICAL,
|
|
)
|
|
|
|
parser.set_defaults(main_verbosity=lief.logging.LEVEL.WARN)
|
|
|
|
args = parser.parse_args()
|
|
lief.logging.set_level(args.main_verbosity)
|
|
|
|
binary = PE.parse(args.pe_file)
|
|
|
|
if binary is None:
|
|
sys.exit(1)
|
|
|
|
print_information(binary)
|
|
|
|
if args.show_data_directories or args.show_all:
|
|
print_data_directories(binary)
|
|
|
|
if args.show_headers or args.show_all:
|
|
print_header(binary)
|
|
|
|
if (args.show_imports or args.show_all) and binary.has_imports:
|
|
print_imports(binary, resolve=args.resolve_ordinals)
|
|
|
|
if (args.show_relocs or args.show_all) and binary.has_relocations:
|
|
print_relocations(binary)
|
|
|
|
if args.show_section_header or args.show_all:
|
|
print_sections(binary)
|
|
|
|
if args.show_symbols or args.show_all:
|
|
print_symbols(binary)
|
|
|
|
if (args.show_tls or args.show_all) and binary.has_tls:
|
|
print_tls(binary)
|
|
|
|
if (args.show_export or args.show_all) and binary.has_exports:
|
|
print_export(binary)
|
|
|
|
if (args.show_debug or args.show_all) and binary.has_debug:
|
|
print_debug(binary)
|
|
|
|
if (args.show_signature or args.show_all) and binary.has_signatures:
|
|
print_signature(binary)
|
|
|
|
if (args.show_richheader or args.show_all) and binary.has_rich_header:
|
|
print_rich_header(binary)
|
|
|
|
if (args.show_resources or args.show_all) and binary.has_resources:
|
|
print_resources(binary)
|
|
|
|
if (args.show_loadconfig or args.show_all) and binary.has_configuration:
|
|
print_load_configuration(binary)
|
|
|
|
if args.show_ctor or args.show_all:
|
|
print_ctor(binary)
|
|
|
|
if args.show_functions or args.show_all:
|
|
print_functions(binary)
|
|
|
|
if args.show_pfunctions or args.show_all:
|
|
print_exception_functions(binary)
|
|
|
|
if args.show_delay_imports or args.show_all:
|
|
print_delay_imports(binary)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|