class IMAGE_LOADCONFIG_DIRECTORY64(pstruct.type): _fields_ = [ (uint32, 'Size'), (TimeDateStamp, 'TimeDateStamp'), (uint16, 'MajorVersion'), (uint16, 'MinorVersion'), (uint32, 'GlobalFlagsClear'), (uint32, 'GlobalFlagsSet'), (uint32, 'CriticalSectionDefaultTimeout'), (uint64, 'DeCommitFreeBlockThreshold'), (uint64, 'DeCommitTotalFreeThreshold'), (realaddress(ptype.undefined, type=uint64), 'LockPrefixTable'), (uint64, 'MaximumAllocationSize'), (uint64, 'VirtualMemoryThreshold'), (uint64, 'ProcessAffinityMask'), (uint32, 'ProcessHeapFlags'), (uint16, 'CSDVersion'), (uint16, 'Reserved1'), (realaddress(ptype.undefined, type=uint64), 'EditList'), (realaddress(uint64, type=uint64), 'SecurityCookie'), (realaddress( lambda s: dyn.array(uint64, s.parent['SEHandlerCount'].li.int()), type=uint64), 'SEHandlerTable'), (uint64, 'SEHandlerCount'), (realaddress(uint64, type=uint64), 'GuardCFCheckFunctionPointer'), (realaddress(uint64, type=uint64), 'GuardCFDispatchFunctionPointer'), (realaddress(lambda s: dyn.array( uint64, s.parent['GuardCFFunctionCount'].li.int()), type=uint64), 'GuardCFFunctionTable'), (uint64, 'GuardCFFunctionCount'), (pbinary.littleendian(IMAGE_GUARD_), 'GuardFlags'), (IMAGE_LOAD_CONFIG_CODE_INTEGRITY, 'CodeIntegrity'), (realaddress(lambda s: dyn.array( uint64, s.parent['GuardAddressTakenIatEntryCount'].li.int()), type=uint64), 'GuardAddressTakenIatEntryTable'), (uint64, 'GuardAddressTakenIatEntryCount'), (realaddress(lambda s: dyn.array( uint64, s.parent['GuardLongJumpTargetCount'].li.int()), type=uint64), 'GuardLongJumpTargetTable'), (uint64, 'GuardLongJumpTargetCount'), (realaddress(ptype.undefined, type=uint64), 'DynamicValueRelocTable'), (realaddress(ptype.undefined, type=uint64), 'CHPEMetadataPointer'), (realaddress(uint64, type=uint64), 'GuardRFFailureRoutine'), (realaddress(uint64, type=uint64), 'GuardRFFailureRoutineFunctionPointer'), (uint32, 'DynamicValueRelocTableOffset'), (uint16, 'DynamicValueRelocTableSection'), (uint16, 'Reserved2'), (realaddress(uint64, type=uint64), 'GuardRFVerifyStackPointerFunctionPointer'), (uint32, 'HotPatchTableOffset'), (uint32, 'Reserved3'), (realaddress(pstr.szwstring, type=uint64), 'AddressOfSomeUnicodeString'), ]
class IMAGE_RESOURCE_DIRECTORY_ENTRY_RVA_DATA(IMAGE_RESOURCE_DIRECTORY_ENTRY_RVA): class RVAType(pbinary.struct): _fields_ = [(1, 'DataIsDirectory'), (31, 'OffsetToDirectory')] def get(self): return self['OffsetToDirectory'] def set(self, value): self['DataIsDirectory'] = 0 self['OffsetToDirecotry'] = value return self _value_ = pbinary.littleendian(RVAType) def _object_(self): return IMAGE_RESOURCE_DIRECTORY if self.object['DataIsDirectory'] else IMAGE_RESOURCE_DATA_ENTRY
class MetaDataRoot(pstruct.type): class _Signature(pint.uint32_t): def properties(self): res = super(MetaDataRoot._Signature, self).properties() res['valid'] = self.valid() return res def valid(self): return self.int() == 0x424a5342 class _StreamHeaders(parray.type): _object_ = StreamHdr def Get(self, name): res = next((stream for stream in self if stream.Name() == name), None) if res is None: raise NameError(name) return res def __StreamHeaders(self): res = self['Streams'].li.int() return dyn.clone(self._StreamHeaders, length=res) def __StreamData(self): cb = self.getparent(IMAGE_DATA_DIRECTORY)['Size'].int() total = sum(self[n].li.size() for _, n in self._fields_[:-1]) res = max((0, cb - total)) return dyn.block(res) class StorageFlags(pbinary.flags): _fields_ = [ (15, 'Reserved'), (1, 'ExtraData'), ] _fields_ = [ (_Signature, 'Signature'), (pint.uint16_t, 'MajorVersion'), (pint.uint16_t, 'MinorVersion'), (pint.uint32_t, 'Reserved'), (pint.uint32_t, 'Length'), (lambda s: dyn.clone(pstr.string, length=s['Length'].li.int()), 'Version'), (dyn.align(4), 'aligned(Version)'), (pbinary.littleendian(StorageFlags), 'Flags'), (pint.uint16_t, 'Streams'), (__StreamHeaders, 'StreamHeaders'), (__StreamData, 'StreamData'), ]
class IMAGE_RESOURCE_DIRECTORY_ENTRY_RVA_NAME(IMAGE_RESOURCE_DIRECTORY_ENTRY_RVA): class RVAType(pbinary.struct): _fields_ = [(1, 'NameIsString'), (31, 'NameOffset')] def get(self): return self['NameOffset'] def set(self, value): self['NameIsString'] = 0 self['NameOffset'] = value return self _value_ = pbinary.littleendian(RVAType) def _object_(self): return IMAGE_RESOURCE_DIRECTORY_STRING_U if self.object['NameIsString'] else ptype.undefined def get(self): if self.object['NameIsString'] == 0: return self.object['NameOffset'] return self.d.li.str()
class IMAGE_RESOURCE_DIRECTORY_ENTRY_RVA(ptype.rpointer_t): class RVAType(pbinary.struct): _fields_ = [(1, 'type'), (31, 'offset')] def get(self): return self['offset'] def set(self, value): self['type'] = 0 self['offset'] = value return self _value_ = pbinary.littleendian(RVAType) def _baseobject_(self): base = self.getparent(headers.IMAGE_DATA_DIRECTORY)['Address'] if base.int() == 0: raise ValueError("No Resource Data Directory Entry") return base.d def encode(self, object, **attrs): raise NotImplementedError def summary(self, **attrs): return self.object.summary(**attrs)
class IMAGE_OPTIONAL_HEADER(pstruct.type): """PE Executable Optional Header""" def is64(self): '''Returns True if a 64-bit executable''' if len(self.v) > 0: magic = self['Magic'] return magic.li.int() == 0x20b return False _fields_ = [ ( IMAGE_NT_OPTIONAL_MAGIC, 'Magic' ), ( uint8, 'MajorLinkerVersion' ), ( uint8, 'MinorLinkerVersion' ), ( uint32, 'SizeOfCode' ), ( uint32, 'SizeOfInitializedData' ), ( uint32, 'SizeOfUninitializedData' ), ( virtualaddress(ptype.undefined, type=uint32), 'AddressOfEntryPoint' ), ( uint32, 'BaseOfCode' ), ( lambda s: pint.uint_t if s.is64() else uint32, 'BaseOfData' ), ( lambda s: uint64 if s.is64() else uint32, 'ImageBase' ), ( uint32, 'SectionAlignment' ), ( uint32, 'FileAlignment' ), ( uint16, 'MajorOperatingSystemVersion' ), ( uint16, 'MinorOperatingSystemVersion' ), ( uint16, 'MajorImageVersion' ), ( uint16, 'MinorImageVersion' ), ( uint16, 'MajorSubsystemVersion' ), ( uint16, 'MinorSubsystemVersion' ), ( uint32, 'Win32VersionValue' ), ( uint32, 'SizeOfImage' ), ( uint32, 'SizeOfHeaders' ), ( uint32, 'CheckSum' ), ( IMAGE_SUBSYSTEM_, 'Subsystem' ), ( pbinary.littleendian(IMAGE_DLLCHARACTERISTICS), 'DllCharacteristics' ), ( lambda s: uint64 if s.is64() else uint32, 'SizeOfStackReserve' ), ( lambda s: uint64 if s.is64() else uint32, 'SizeOfStackCommit' ), ( lambda s: uint64 if s.is64() else uint32, 'SizeOfHeapReserve' ), ( lambda s: uint64 if s.is64() else uint32, 'SizeOfHeapCommit' ), ( uint32, 'LoaderFlags' ), ( uint32, 'NumberOfRvaAndSizes' ), ]
class IMAGE_FILE_HEADER(pstruct.type): """PE Executable File Header""" class Characteristics(pbinary.flags): _fields_ = [ (1, 'BYTES_REVERSED_HI'), (1, 'UP_SYSTEM_ONLY'), (1, 'DLL'), (1, 'SYSTEM'), (1, 'NET_RUN_FROM_SWAP'), (1, 'REMOVABLE_RUN_FROM_SWAP'), (1, 'DEBUG_STRIPPED'), (1, '32BIT_MACHINE'), (1, 'BYTES_REVERSED_LO'), (1, 'reserved_9'), (1, 'LARGE_ADDRESS_AWARE'), (1, 'AGGRESSIVE_WS_TRIM'), (1, 'LOCAL_SYMS_STRIPPED'), (1, 'LINE_NUMS_STRIPPED'), (1, 'EXECUTABLE_IMAGE'), (1, 'RELOCS_STRIPPED'), ] _fields_ = [ (Machine, 'Machine'), (uint16, 'NumberOfSections'), (TimeDateStamp, 'TimeDateStamp'), (fileoffset(symbols.SymbolTableAndStringTable, type=uint32), 'PointerToSymbolTable'), (uint32, 'NumberOfSymbols'), (word, 'SizeOfOptionalHeader'), (pbinary.littleendian(Characteristics), 'Characteristics') ]
class IMAGE_SECTION_HEADER(pstruct.type): """PE Executable Section Table Entry""" class IMAGE_SCN(pbinary.flags): _fields_ = [ (1, 'MEM_WRITE'), # 0x80000000 (1, 'MEM_READ'), # 0x40000000 (1, 'MEM_EXECUTE'), # 0x20000000 (1, 'MEM_SHARED'), # 0x10000000 (1, 'MEM_NOT_PAGED'), # 0x08000000 (1, 'MEM_NOT_CACHED'), # 0x04000000 (1, 'MEM_DISCARDABLE'), # 0x02000000 (1, 'LNK_NRELOC_OVFL'), # 0x01000000 # (1, 'ALIGN_8192BYTES'), # 0x00e00000 # (1, 'ALIGN_4096BYTES'), # 0x00d00000 # (1, 'ALIGN_2048BYTES'), # 0x00c00000 # (1, 'ALIGN_1024BYTES'), # 0x00b00000 # (1, 'ALIGN_512BYTES'), # 0x00a00000 # (1, 'ALIGN_256BYTES'), # 0x00900000 # (1, 'ALIGN_128BYTES'), # 0x00800000 # (1, 'ALIGN_64BYTES'), # 0x00700000 # (1, 'ALIGN_32BYTES'), # 0x00600000 # (1, 'ALIGN_16BYTES'), # 0x00500000 # (1, 'ALIGN_8BYTES'), # 0x00400000 # (1, 'ALIGN_4BYTES'), # 0x00300000 # (1, 'ALIGN_2BYTES'), # 0x00200000 # (1, 'ALIGN_1BYTES'), # 0x00100000 (4, 'ALIGN'), # 0x00?00000 (1, 'MEM_PRELOAD'), # 0x00080000 (1, 'MEM_LOCKED'), # 0x00040000 # (1, 'MEM_16BIT'), # 0x00020000 # ARM (1, 'MEM_PURGEABLE'), # 0x00020000 (1, 'reserved_16'), (1, 'GPREL'), # 0x00008000 (2, 'reserved_14'), (1, 'LNK_COMDAT'), # 0x00001000 (1, 'LNK_REMOVE'), # 0x00000800 (1, 'reserved_11'), (1, 'LNK_INFO'), # 0x00000200 (1, 'LNK_OTHER'), # 0x00000100 (1, 'CNT_UNINITIALIZED_DATA'), # 0x00000080 (1, 'CNT_INITIALIZED_DATA'), # 0x00000040 (1, 'CNT_CODE'), # 0x00000020 (1, 'reserved_4'), (1, 'TYPE_NO_PAD'), # 0x00000008 (3, 'reserved_0'), ] # FIXME: we can store a longer than 8 byte Name if we want to implement code that navigates to the string table # apparently executables don't care though... _fields_ = [ (dyn.clone(pstr.string, length=8), 'Name'), (uint32, 'VirtualSize'), (virtualaddress(lambda s:dyn.block(s.parent.getloadedsize()), type=uint32), 'VirtualAddress'), (uint32, 'SizeOfRawData'), (fileoffset(lambda s:dyn.block(s.parent.getreadsize()), type=uint32), 'PointerToRawData'), (fileoffset(lambda s:dyn.array(relocations.MachineRelocation.lookup(s.getparent(Header).Machine().int()), s.parent['NumberOfRelocations'].li.int()), type=uint32), 'PointerToRelocations'), (fileoffset(lambda s:dyn.array(linenumbers.LineNumber, s.parent['NumberOfLinenumbers'].li.int()), type=uint32), 'PointerToLinenumbers'), (uint16, 'NumberOfRelocations'), (uint16, 'NumberOfLinenumbers'), (pbinary.littleendian(IMAGE_SCN), 'Characteristics'), ] def getreadsize(self): portable = self.getparent(SectionTableArray) # if it's a portable executable, then apply the alignment try: nt = portable.p alignment = nt['OptionalHeader']['FileAlignment'].int() mask = alignment - 1 # otherwise, there's no alignment necessary except KeyError: mask = 0 res = (self['SizeOfRawData'].int() + mask) & ~mask return min((self.source.size() - self['PointerToRawData'].int(), res)) if hasattr(self.source, 'size') else res def getloadedsize(self): # XXX: even though the loadedsize is aligned to SectionAlignment, # the loader doesn't actually map data there and thus the # actual mapped size is rounded to pagesize # nt = self.getparent(Header) # alignment = nt['OptionalHeader']['SectionAlignment'].int() alignment = 0x1000 # pagesize mask = alignment - 1 return (self['VirtualSize'].int() + mask) & ~mask def containsaddress(self, address): start = self['VirtualAddress'].int() return True if (address >= start) and (address < start + self.getloadedsize()) else False def containsoffset(self, offset): start = self['PointerToRawData'].int() return True if (offset >= start) and (offset < start + self.getreadsize()) else False def data(self): return self['PointerToRawData'].d getrelocations = lambda self: self['PointerToRelocations'].d getlinenumbers = lambda self: self['NumberOfLinenumbers'].d ## offset means file offset def getoffsetbyaddress(self, address): return address - self['VirtualAddress'].int() + self['PointerToRawData'].int() def getaddressbyoffset(self, offset): return offset - self['PointerToRawData'].int() + self['VirtualAddress'].int()
class IMAGE_LOADCONFIG_DIRECTORY(pstruct.type): # FIXME: The size field in the DataDirectory is used to determine which # IMAGE_LOADCONFIG_DIRECTORY to use. Instead we're cheating and # using the size specified in the data-directory entry and a # feature of pstruct.type when defining a custom .blocksize(). A # proper implementation should check the 'Size' field and then # use this to determine which IMAGE_LOADCONFIG_DIRECTORY # should be used. Once that's done, then we can define a # sub-object that chooses the correct IMAGE_LOADCONFIG_DIRECTORY # to use. _fields_ = [ (uint32, 'Size'), (TimeDateStamp, 'TimeDateStamp'), (uint16, 'MajorVersion'), (uint16, 'MinorVersion'), (uint32, 'GlobalFlagsClear'), # FIXME (uint32, 'GlobalFlagsSet'), # FIXME (uint32, 'CriticalSectionDefaultTimeout'), (uint32, 'DeCommitFreeBlockThreshold'), (uint32, 'DeCommitTotalFreeThreshold'), (realaddress(ptype.undefined, type=uint32), 'LockPrefixTable'), # XXX: NULL-terminated list of VAs (uint32, 'MaximumAllocationSize'), (uint32, 'VirtualMemoryThreshold'), (uint32, 'ProcessAffinityMask'), (uint32, 'ProcessHeapFlags'), # FIXME: where are these flags at? (uint16, 'CSDVersion'), (uint16, 'Reserved'), (realaddress(ptype.undefined, type=uint32), 'EditList'), # XXX: also probably a NULL-terminated list of VAs (realaddress(uint32, type=uint32), 'SecurityCookie'), (realaddress( lambda s: dyn.array(uint32, s.parent['SEHandlerCount'].li.int()), type=uint32), 'SEHandlerTable'), (uint32, 'SEHandlerCount'), (realaddress(uint32, type=uint32), 'GuardCFCheckFunctionPointer'), (realaddress(uint32, type=uint32), 'GuardCFDispatchFunctionPointer'), (realaddress(lambda s: dyn.array( uint32, s.parent['GuardCFFunctionCount'].li.int()), type=uint32), 'GuardCFFunctionTable'), (uint32, 'GuardCFFunctionCount'), (pbinary.littleendian(IMAGE_GUARD_), 'GuardFlags'), (IMAGE_LOAD_CONFIG_CODE_INTEGRITY, 'CodeIntegrity'), (realaddress(lambda s: dyn.array( uint32, s.parent['GuardAddressTakenIatEntryCount'].li.int()), type=uint32), 'GuardAddressTakenIatEntryTable'), (uint32, 'GuardAddressTakenIatEntryCount'), (realaddress(lambda s: dyn.array( uint32, s.parent['GuardLongJumpTargetCount'].li.int()), type=uint32), 'GuardLongJumpTargetTable'), (uint32, 'GuardLongJumpTargetCount'), (realaddress(ptype.undefined, type=uint32), 'DynamicValueRelocTable' ), # XXX: Probably another NULL-terminated list of VAs (realaddress(ptype.undefined, type=uint32), 'CHPEMetadataPointer'), # FIXME (realaddress(uint32, type=uint32), 'GuardRFFailureRoutine'), (realaddress(uint32, type=uint32), 'GuardRFFailureRoutineFunctionPointer'), (uint32, 'DynamicValueRelocTableOffset' ), # XXX: depends on DynamicValueRelocTableSection (uint16, 'DynamicValueRelocTableSection'), (uint16, 'Reserved2'), (realaddress(uint32, type=uint32), 'GuardRFVerifyStackPointerFunctionPointer'), (uint32, 'HotPatchTableOffset'), (realaddress(pstr.wstring, type=uint32), 'AddressOfSomeUnicodeString'), (uint32, 'Reserved3'), ]
class IMAGE_LOAD_CONFIG_DIRECTORY64(IMAGE_LOAD_CONFIG_DIRECTORY): _fields_ = [ (DWORD, 'Size'), (TimeDateStamp, 'TimeDateStamp'), (WORD, 'MajorVersion'), (WORD, 'MinorVersion'), (DWORD, 'GlobalFlagsClear'), (DWORD, 'GlobalFlagsSet'), (DWORD, 'CriticalSectionDefaultTimeout'), (ULONGLONG, 'DeCommitFreeBlockThreshold'), (ULONGLONG, 'DeCommitTotalFreeThreshold'), (realaddress(VOID, type=ULONGLONG), 'LockPrefixTable'), (ULONGLONG, 'MaximumAllocationSize'), (ULONGLONG, 'VirtualMemoryThreshold'), (ULONGLONG, 'ProcessAffinityMask'), (DWORD, 'ProcessHeapFlags'), (WORD, 'CSDVersion'), (LOAD_LIBRARY_SEARCH_, 'DependentLoadFlags'), (realaddress(VOID, type=ULONGLONG), 'EditList'), (realaddress(ULONGLONG, type=ULONGLONG), 'SecurityCookie'), (realaddress(lambda self: dyn.array( ULONGLONG, self.parent['SEHandlerCount'].li.int()), type=ULONGLONG), 'SEHandlerTable'), (ULONGLONG, 'SEHandlerCount'), (realaddress(realaddress(VOID, type=ULONGLONG), type=ULONGLONG), 'GuardCFCheckFunctionPointer'), (realaddress(realaddress(VOID, type=ULONGLONG), type=ULONGLONG), 'GuardCFDispatchFunctionPointer'), (realaddress(lambda self: dyn.array( virtualaddress(VOID, type=DWORD), self.parent[ 'GuardCFFunctionCount'].li.int()), type=ULONGLONG), 'GuardCFFunctionTable'), (ULONGLONG, 'GuardCFFunctionCount'), (pbinary.littleendian(IMAGE_GUARD_), 'GuardFlags'), (IMAGE_LOAD_CONFIG_CODE_INTEGRITY, 'CodeIntegrity'), (realaddress(lambda self: dyn.array( ULONGLONG, self.parent['GuardAddressTakenIatEntryCount'].li.int()), type=ULONGLONG), 'GuardAddressTakenIatEntryTable'), (ULONGLONG, 'GuardAddressTakenIatEntryCount'), (realaddress(lambda self: dyn.array( ULONGLONG, self.parent['GuardLongJumpTargetCount'].li.int()), type=ULONGLONG), 'GuardLongJumpTargetTable'), (ULONGLONG, 'GuardLongJumpTargetCount'), (realaddress(IMAGE_DYNAMIC_RELOCATION_TABLE, type=ULONGLONG), 'DynamicValueRelocTable'), (realaddress(VOID, type=ULONGLONG), 'CHPEMetadataPointer'), (realaddress(VOID, type=ULONGLONG), 'GuardRFFailureRoutine'), (realaddress(VOID, type=ULONGLONG), 'GuardRFFailureRoutineFunctionPointer'), (DWORD, 'DynamicValueRelocTableOffset'), (WORD, 'DynamicValueRelocTableSection'), (WORD, 'Reserved2'), (realaddress(ULONGLONG, type=ULONGLONG), 'GuardRFVerifyStackPointerFunctionPointer'), (DWORD, 'HotPatchTableOffset'), (DWORD, 'Reserved3'), (realaddress(IMAGE_ENCLAVE_CONFIG64, type=ULONGLONG), 'EnclaveConfigurationPointer'), (realaddress(VOID, type=ULONGLONG), 'VolatileMetadataPointer'), (realaddress(lambda self: dyn.array( ULONGLONG, self.parent['GuardEHContinuationCount'].li.int()), type=ULONGLONG), 'GuardEHContinuationTable'), (ULONGLONG, 'GuardEHContinuationCount'), (realaddress(VOID, type=ULONGLONG), 'GuardXFGCheckFunctionPointer'), (realaddress(VOID, type=ULONGLONG), 'GuardXFGDispatchFunctionPointer'), (realaddress(VOID, type=ULONGLONG), 'GuardXFGTableDispatchFunctionPointer'), (ULONGLONG, 'CastGuardOsDeterminedFailureMode'), ]
class HTables(pstruct.type): type = "#~" class HeapSizes(pbinary.flags): _fields_ = [ (5, 'Unused'), (1, 'HBlob'), (1, 'HGUID'), (1, 'HStrings'), ] class BitVector(pbinary.array): _object_ = 1 def index(self, index): res = len(self) - index return self[res - 1] def indices(self, crit): return [ index for index, value in enumerate(reversed(self)) if crit(value) ] class _Valid(BitVector): length = 64 def indices(self): return super(HTables._Valid, self).indices(bool) def summary(self): return ', '.join(map('{:d}'.format, self.indices())) class _Sorted(BitVector): length = 64 def indices(self): return super(HTables._Sorted, self).indices(bool) class _RowLengths(parray.type): length = 64 def _object_(self): res, index = self.getparent(HTables), len(self.value) present = res['Valid'].li.index return pint.uint32_t if present(index) else pint.uint_t def __padding_Tables(self): hdr = self.getparent(StreamHdr) cb = hdr['Size'].li.int() total = sum(self[n].blocksize() for _, n in self._fields_[:-1]) return dyn.block(max((0, cb - total))) _fields_ = [ (pint.uint32_t, 'Reserved'), (pint.uint8_t, 'MajorVersion'), (pint.uint8_t, 'MinorVersion'), (HeapSizes, 'HeapSizes'), (pint.uint8_t, 'Reserved'), (pbinary.littleendian(_Valid), 'Valid'), (pbinary.littleendian(_Sorted), 'Sorted'), (_RowLengths, 'Rows'), (Tables, 'Tables'), (__padding_Tables, 'padding(Tables)'), ]