summaryrefslogtreecommitdiff
path: root/external/construct/formats/executable/pe32.py
diff options
context:
space:
mode:
Diffstat (limited to 'external/construct/formats/executable/pe32.py')
-rw-r--r--external/construct/formats/executable/pe32.py420
1 files changed, 420 insertions, 0 deletions
diff --git a/external/construct/formats/executable/pe32.py b/external/construct/formats/executable/pe32.py
new file mode 100644
index 0000000..1463ec3
--- /dev/null
+++ b/external/construct/formats/executable/pe32.py
@@ -0,0 +1,420 @@
+"""
+Portable Executable (PE) 32 bit, little endian
+Used on MSWindows systems (including DOS) for EXEs and DLLs
+
+1999 paper:
+http://download.microsoft.com/download/1/6/1/161ba512-40e2-4cc9-843a-923143f3456c/pecoff.doc
+
+2006 with updates relevant for .NET:
+http://download.microsoft.com/download/9/c/5/9c5b2167-8017-4bae-9fde-d599bac8184a/pecoff_v8.doc
+"""
+from construct import *
+import time
+import six
+
+
+class UTCTimeStampAdapter(Adapter):
+ def _decode(self, obj, context):
+ return time.ctime(obj)
+ def _encode(self, obj, context):
+ return int(time.mktime(time.strptime(obj)))
+
+def UTCTimeStamp(name):
+ return UTCTimeStampAdapter(ULInt32(name))
+
+class NamedSequence(Adapter):
+ """
+ creates a mapping between the elements of a sequence and their respective
+ names. this is useful for sequences of a variable length, where each
+ element in the sequence has a name (as is the case with the data
+ directories of the PE header)
+ """
+ __slots__ = ["mapping", "rev_mapping"]
+ prefix = "unnamed_"
+ def __init__(self, subcon, mapping):
+ Adapter.__init__(self, subcon)
+ self.mapping = mapping
+ self.rev_mapping = dict((v, k) for k, v in mapping.items())
+ def _encode(self, obj, context):
+ d = obj.__dict__
+ obj2 = [None] * len(d)
+ for name, value in d.items():
+ if name in self.rev_mapping:
+ index = self.rev_mapping[name]
+ elif name.startswith("__"):
+ obj2.pop(-1)
+ continue
+ elif name.startswith(self.prefix):
+ index = int(name.split(self.prefix)[1])
+ else:
+ raise ValueError("no mapping defined for %r" % (name,))
+ obj2[index] = value
+ return obj2
+ def _decode(self, obj, context):
+ obj2 = Container()
+ for i, item in enumerate(obj):
+ if i in self.mapping:
+ name = self.mapping[i]
+ else:
+ name = "%s%d" % (self.prefix, i)
+ setattr(obj2, name, item)
+ return obj2
+
+
+msdos_header = Struct("msdos_header",
+ Magic("MZ"),
+ ULInt16("partPag"),
+ ULInt16("page_count"),
+ ULInt16("relocation_count"),
+ ULInt16("header_size"),
+ ULInt16("minmem"),
+ ULInt16("maxmem"),
+ ULInt16("relocation_stackseg"),
+ ULInt16("exe_stackptr"),
+ ULInt16("checksum"),
+ ULInt16("exe_ip"),
+ ULInt16("relocation_codeseg"),
+ ULInt16("table_offset"),
+ ULInt16("overlay"),
+ Padding(8),
+ ULInt16("oem_id"),
+ ULInt16("oem_info"),
+ Padding(20),
+ ULInt32("coff_header_pointer"),
+ Anchor("_assembly_start"),
+ OnDemand(
+ HexDumpAdapter(
+ Field("code",
+ lambda ctx: ctx.coff_header_pointer - ctx._assembly_start
+ )
+ )
+ ),
+)
+
+symbol_table = Struct("symbol_table",
+ String("name", 8, padchar = six.b("\x00")),
+ ULInt32("value"),
+ Enum(ExprAdapter(SLInt16("section_number"),
+ encoder = lambda obj, ctx: obj + 1,
+ decoder = lambda obj, ctx: obj - 1,
+ ),
+ UNDEFINED = -1,
+ ABSOLUTE = -2,
+ DEBUG = -3,
+ _default_ = Pass,
+ ),
+ Enum(ULInt8("complex_type"),
+ NULL = 0,
+ POINTER = 1,
+ FUNCTION = 2,
+ ARRAY = 3,
+ ),
+ Enum(ULInt8("base_type"),
+ NULL = 0,
+ VOID = 1,
+ CHAR = 2,
+ SHORT = 3,
+ INT = 4,
+ LONG = 5,
+ FLOAT = 6,
+ DOUBLE = 7,
+ STRUCT = 8,
+ UNION = 9,
+ ENUM = 10,
+ MOE = 11,
+ BYTE = 12,
+ WORD = 13,
+ UINT = 14,
+ DWORD = 15,
+ ),
+ Enum(ULInt8("storage_class"),
+ END_OF_FUNCTION = 255,
+ NULL = 0,
+ AUTOMATIC = 1,
+ EXTERNAL = 2,
+ STATIC = 3,
+ REGISTER = 4,
+ EXTERNAL_DEF = 5,
+ LABEL = 6,
+ UNDEFINED_LABEL = 7,
+ MEMBER_OF_STRUCT = 8,
+ ARGUMENT = 9,
+ STRUCT_TAG = 10,
+ MEMBER_OF_UNION = 11,
+ UNION_TAG = 12,
+ TYPE_DEFINITION = 13,
+ UNDEFINED_STATIC = 14,
+ ENUM_TAG = 15,
+ MEMBER_OF_ENUM = 16,
+ REGISTER_PARAM = 17,
+ BIT_FIELD = 18,
+ BLOCK = 100,
+ FUNCTION = 101,
+ END_OF_STRUCT = 102,
+ FILE = 103,
+ SECTION = 104,
+ WEAK_EXTERNAL = 105,
+ ),
+ ULInt8("number_of_aux_symbols"),
+ Array(lambda ctx: ctx.number_of_aux_symbols,
+ Bytes("aux_symbols", 18)
+ )
+)
+
+coff_header = Struct("coff_header",
+ Magic("PE\x00\x00"),
+ Enum(ULInt16("machine_type"),
+ UNKNOWN = 0x0,
+ AM33 = 0x1d3,
+ AMD64 = 0x8664,
+ ARM = 0x1c0,
+ EBC = 0xebc,
+ I386 = 0x14c,
+ IA64 = 0x200,
+ M32R = 0x9041,
+ MIPS16 = 0x266,
+ MIPSFPU = 0x366,
+ MIPSFPU16 = 0x466,
+ POWERPC = 0x1f0,
+ POWERPCFP = 0x1f1,
+ R4000 = 0x166,
+ SH3 = 0x1a2,
+ SH3DSP = 0x1a3,
+ SH4 = 0x1a6,
+ SH5= 0x1a8,
+ THUMB = 0x1c2,
+ WCEMIPSV2 = 0x169,
+ _default_ = Pass
+ ),
+ ULInt16("number_of_sections"),
+ UTCTimeStamp("time_stamp"),
+ ULInt32("symbol_table_pointer"),
+ ULInt32("number_of_symbols"),
+ ULInt16("optional_header_size"),
+ FlagsEnum(ULInt16("characteristics"),
+ RELOCS_STRIPPED = 0x0001,
+ EXECUTABLE_IMAGE = 0x0002,
+ LINE_NUMS_STRIPPED = 0x0004,
+ LOCAL_SYMS_STRIPPED = 0x0008,
+ AGGRESSIVE_WS_TRIM = 0x0010,
+ LARGE_ADDRESS_AWARE = 0x0020,
+ MACHINE_16BIT = 0x0040,
+ BYTES_REVERSED_LO = 0x0080,
+ MACHINE_32BIT = 0x0100,
+ DEBUG_STRIPPED = 0x0200,
+ REMOVABLE_RUN_FROM_SWAP = 0x0400,
+ SYSTEM = 0x1000,
+ DLL = 0x2000,
+ UNIPROCESSOR_ONLY = 0x4000,
+ BIG_ENDIAN_MACHINE = 0x8000,
+ ),
+
+ # symbol table
+ Pointer(lambda ctx: ctx.symbol_table_pointer,
+ Array(lambda ctx: ctx.number_of_symbols, symbol_table)
+ )
+)
+
+def PEPlusField(name):
+ return IfThenElse(name, lambda ctx: ctx.pe_type == "PE32_plus",
+ ULInt64(None),
+ ULInt32(None),
+ )
+
+optional_header = Struct("optional_header",
+ # standard fields
+ Enum(ULInt16("pe_type"),
+ PE32 = 0x10b,
+ PE32_plus = 0x20b,
+ ),
+ ULInt8("major_linker_version"),
+ ULInt8("minor_linker_version"),
+ ULInt32("code_size"),
+ ULInt32("initialized_data_size"),
+ ULInt32("uninitialized_data_size"),
+ ULInt32("entry_point_pointer"),
+ ULInt32("base_of_code"),
+
+ # only in PE32 files
+ If(lambda ctx: ctx.pe_type == "PE32",
+ ULInt32("base_of_data")
+ ),
+
+ # WinNT-specific fields
+ PEPlusField("image_base"),
+ ULInt32("section_aligment"),
+ ULInt32("file_alignment"),
+ ULInt16("major_os_version"),
+ ULInt16("minor_os_version"),
+ ULInt16("major_image_version"),
+ ULInt16("minor_image_version"),
+ ULInt16("major_subsystem_version"),
+ ULInt16("minor_subsystem_version"),
+ Padding(4),
+ ULInt32("image_size"),
+ ULInt32("headers_size"),
+ ULInt32("checksum"),
+ Enum(ULInt16("subsystem"),
+ UNKNOWN = 0,
+ NATIVE = 1,
+ WINDOWS_GUI = 2,
+ WINDOWS_CUI = 3,
+ POSIX_CIU = 7,
+ WINDOWS_CE_GUI = 9,
+ EFI_APPLICATION = 10,
+ EFI_BOOT_SERVICE_DRIVER = 11,
+ EFI_RUNTIME_DRIVER = 12,
+ EFI_ROM = 13,
+ XBOX = 14,
+ _default_ = Pass
+ ),
+ FlagsEnum(ULInt16("dll_characteristics"),
+ NO_BIND = 0x0800,
+ WDM_DRIVER = 0x2000,
+ TERMINAL_SERVER_AWARE = 0x8000,
+ ),
+ PEPlusField("reserved_stack_size"),
+ PEPlusField("stack_commit_size"),
+ PEPlusField("reserved_heap_size"),
+ PEPlusField("heap_commit_size"),
+ ULInt32("loader_flags"),
+ ULInt32("number_of_data_directories"),
+
+ NamedSequence(
+ Array(lambda ctx: ctx.number_of_data_directories,
+ Struct("data_directories",
+ ULInt32("address"),
+ ULInt32("size"),
+ )
+ ),
+ mapping = {
+ 0 : 'export_table',
+ 1 : 'import_table',
+ 2 : 'resource_table',
+ 3 : 'exception_table',
+ 4 : 'certificate_table',
+ 5 : 'base_relocation_table',
+ 6 : 'debug',
+ 7 : 'architecture',
+ 8 : 'global_ptr',
+ 9 : 'tls_table',
+ 10 : 'load_config_table',
+ 11 : 'bound_import',
+ 12 : 'import_address_table',
+ 13 : 'delay_import_descriptor',
+ 14 : 'complus_runtime_header',
+ }
+ ),
+)
+
+section = Struct("section",
+ String("name", 8, padchar = six.b("\x00")),
+ ULInt32("virtual_size"),
+ ULInt32("virtual_address"),
+ ULInt32("raw_data_size"),
+ ULInt32("raw_data_pointer"),
+ ULInt32("relocations_pointer"),
+ ULInt32("line_numbers_pointer"),
+ ULInt16("number_of_relocations"),
+ ULInt16("number_of_line_numbers"),
+ FlagsEnum(ULInt32("characteristics"),
+ TYPE_REG = 0x00000000,
+ TYPE_DSECT = 0x00000001,
+ TYPE_NOLOAD = 0x00000002,
+ TYPE_GROUP = 0x00000004,
+ TYPE_NO_PAD = 0x00000008,
+ TYPE_COPY = 0x00000010,
+ CNT_CODE = 0x00000020,
+ CNT_INITIALIZED_DATA = 0x00000040,
+ CNT_UNINITIALIZED_DATA = 0x00000080,
+ LNK_OTHER = 0x00000100,
+ LNK_INFO = 0x00000200,
+ TYPE_OVER = 0x00000400,
+ LNK_REMOVE = 0x00000800,
+ LNK_COMDAT = 0x00001000,
+ MEM_FARDATA = 0x00008000,
+ MEM_PURGEABLE = 0x00020000,
+ MEM_16BIT = 0x00020000,
+ MEM_LOCKED = 0x00040000,
+ MEM_PRELOAD = 0x00080000,
+ ALIGN_1BYTES = 0x00100000,
+ ALIGN_2BYTES = 0x00200000,
+ ALIGN_4BYTES = 0x00300000,
+ ALIGN_8BYTES = 0x00400000,
+ ALIGN_16BYTES = 0x00500000,
+ ALIGN_32BYTES = 0x00600000,
+ ALIGN_64BYTES = 0x00700000,
+ ALIGN_128BYTES = 0x00800000,
+ ALIGN_256BYTES = 0x00900000,
+ ALIGN_512BYTES = 0x00A00000,
+ ALIGN_1024BYTES = 0x00B00000,
+ ALIGN_2048BYTES = 0x00C00000,
+ ALIGN_4096BYTES = 0x00D00000,
+ ALIGN_8192BYTES = 0x00E00000,
+ LNK_NRELOC_OVFL = 0x01000000,
+ MEM_DISCARDABLE = 0x02000000,
+ MEM_NOT_CACHED = 0x04000000,
+ MEM_NOT_PAGED = 0x08000000,
+ MEM_SHARED = 0x10000000,
+ MEM_EXECUTE = 0x20000000,
+ MEM_READ = 0x40000000,
+ MEM_WRITE = 0x80000000,
+ ),
+
+ OnDemandPointer(lambda ctx: ctx.raw_data_pointer,
+ HexDumpAdapter(Field("raw_data", lambda ctx: ctx.raw_data_size))
+ ),
+
+ OnDemandPointer(lambda ctx: ctx.line_numbers_pointer,
+ Array(lambda ctx: ctx.number_of_line_numbers,
+ Struct("line_numbers",
+ ULInt32("type"),
+ ULInt16("line_number"),
+ )
+ )
+ ),
+
+ OnDemandPointer(lambda ctx: ctx.relocations_pointer,
+ Array(lambda ctx: ctx.number_of_relocations,
+ Struct("relocations",
+ ULInt32("virtual_address"),
+ ULInt32("symbol_table_index"),
+ ULInt16("type"),
+ )
+ )
+ ),
+)
+
+pe32_file = Struct("pe32_file",
+ # headers
+ msdos_header,
+ coff_header,
+ Anchor("_start_of_optional_header"),
+ optional_header,
+ Anchor("_end_of_optional_header"),
+ Padding(lambda ctx: min(0,
+ ctx.coff_header.optional_header_size -
+ ctx._end_of_optional_header +
+ ctx._start_of_optional_header
+ )
+ ),
+
+ # sections
+ Array(lambda ctx: ctx.coff_header.number_of_sections, section)
+)
+
+
+if __name__ == "__main__":
+ print (pe32_file.parse_stream(open("../../../tests/NOTEPAD.EXE", "rb")))
+ print (pe32_file.parse_stream(open("../../../tests/sqlite3.dll", "rb")))
+
+
+
+
+
+
+
+
+
+
+