1# coding=utf-8 2# Copyright 2018 Sascha Schirra 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are met: 6# 7# 1. Redistributions of source code must retain the above copyright notice, this 8# list of conditions and the following disclaimer. 9# 10# 2. Redistributions in binary form must reproduce the above copyright notice, 11# this list of conditions and the following disclaimer in the documentation 12# and/or other materials provided with the distribution. 13# 14# 3. Neither the name of the copyright holder nor the names of its contributors 15# may be used to endorse or promote products derived from this software without 16# specific prior written permission. 17# 18# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" A ND 19# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21# DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 22# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 24# SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 25# CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26# OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 27# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 29 30from .enum import Enum 31from .binary import * 32 33###################### PE General ################# 34 35class IMAGE_FILE_MACHINE(Enum): 36 UKNOWN = 0 37 AM33 = 0x1d3 38 AMD64 = 0x8664 39 ARM = 0x1c0 40 ARMV = 0x1c4 41 EBC = 0xebc 42 I386 = 0x14c 43 IA64 = 0x200 44 M32R = 0x9041 45 MIPS16 = 0x266 46 MIPSFPU = 0x366 47 MIPSFPU16 = 0x466 48 POWERPC = 0x1f0 49 POWERPCFP = 0x1f1 50 THUMB = 0x1c2 51 WCEMIPSV2 = 0x169 52 ARM64 = 0xaa64 53 54class IMAGE_SCN(Enum): 55 TYPE_NO_PAD = 0x00000008 56 CNT_CODE = 0x00000020 57 CNT_INITIALIZED_DATA = 0x00000040 58 CNT_UNINITIALIZED_DATA = 0x00000080 59 LNK_OTHER = 0x00000100 60 LNK_INFO = 0x00000200 61 LNK_REMOVE = 0x00000800 62 LNK_COMDAT = 0x00001000 63 GPREL = 0x00008000 64 MEM_PURGEABLE = 0x00020000 65 MEM_LOCKED = 0x00040000 66 MEM_PRELOAD = 0x00080000 67 ALIGN_1BYTES = 0x00100000 68 ALIGN_2BYTES = 0x00200000 69 ALIGN_4BYTES = 0x00300000 70 ALIGN_8BYTES = 0x00400000 71 ALIGN_16BYTES = 0x00500000 72 ALIGN_32BYTES = 0x00600000 73 ALIGN_64BYTES = 0x00700000 74 ALIGN_128BYTES = 0x00800000 75 ALIGN_256BYTES = 0x00900000 76 ALIGN_512BYTES = 0x00A00000 77 ALIGN_1024BYTES = 0x00B00000 78 ALIGN_2048BYTES = 0x00C00000 79 ALIGN_4096BYTES = 0x00D00000 80 ALIGN_8192BYTES = 0x00E00000 81 LNK_NRELOC_OVFL = 0x01000000 82 MEM_WRITE = 0x80000000 83 MEM_READ = 0x4000000 84 85 86 87class ImageDllCharacteristics(Enum): 88 DYNAMIC_BASE = 0x0040 89 FORCE_INTEGRITY = 0x0080 90 NX_COMPAT = 0x0100 91 NO_ISOLATION = 0x0200 92 NO_SEH = 0x0400 93 NO_BIND = 0x0800 94 APP_CONTAINER = 0x1000 95 WDM_DRIVER = 0x2000 96 CONTROL_FLOW_GUARD = 0x4000 97 TERMINAL_SERVER_AWARE = 0x8000 98 99 100class ImageDirectoryEntry(Enum): 101 EXPORT = 0 102 IMPORT = 1 103 RESOURCE = 2 104 EXCEPTION = 3 105 SECURITY = 4 106 BASERELOC = 5 107 DEBUG = 6 108 COPYRIGHT = 7 109 GLOBALPTR = 8 110 TLS = 9 111 LOAD_CONFIG = 10 112 BOUND_IMPORT = 11 113 IAT = 12 114 DELAY_IMPORT = 13 115 COM_DESCRIPTOR = 14 116 NUMBER_OF_DIRECTORY_ENTRIES = 16 117 118 119class IMAGE_DOS_HEADER(Structure): 120 _fields_ = [('e_magic', c_char * 2), 121 ('e_cblp', c_ushort), 122 ('e_cp', c_ushort), 123 ('e_crlc', c_ushort), 124 ('e_cparhdr', c_ushort), 125 ('e_minalloc', c_ushort), 126 ('e_maxalloc', c_ushort), 127 ('e_ss', c_ushort), 128 ('e_sp', c_ushort), 129 ('e_csum', c_ushort), 130 ('e_ip', c_ushort), 131 ('e_cs', c_ushort), 132 ('e_lfarlc', c_ushort), 133 ('e_ovno', c_ushort), 134 ('e_res', c_ushort * 4), 135 ('e_oemid', c_ushort), 136 ('e_oeminfo', c_ushort), 137 ('e_res2', c_ushort * 10), 138 ('e_lfanew', c_uint)] # Offset zum PE-Header 139 140 141class IMAGE_FILE_HEADER(Structure): 142 _fields_ = [('Machine', c_ushort), 143 ('NumberOfSections', c_ushort), 144 ('TimeDateStamp', c_uint), 145 ('PointerToSymbolTable', c_uint), 146 ('NumberOfSymbols', c_uint), 147 ('SizeOfOptionalHeader', c_ushort), 148 ('Characteristics', c_ushort) 149 ] 150 151 152class IMAGE_DATA_DIRECTORY(Structure): 153 _fields_ = [('VirtualAddress', c_uint), 154 ('Size', c_uint)] 155 156 157class IMAGE_SECTION_HEADER(Structure): 158 _fields_ = [('Name', c_char * 8), 159 ('PhysicalAddress_or_VirtualSize', c_uint), 160 ('VirtualAddress', c_uint), 161 ('SizeOfRawData', c_uint), 162 ('PointerToRawData', c_uint), 163 ('PointerToRelocations', c_uint), 164 ('PointerToLinenumbers', c_uint), 165 ('NumberOfRelocations', c_ushort), 166 ('NumberOfLinenumbers', c_ushort), 167 ('Characteristics', c_uint)] 168 169 170class IMAGE_IMPORT_BY_NAME(Structure): 171 _fields_ = [('Hint', c_ushort), 172 ('Name', c_char)] 173 174 175class IMAGE_THUNK_DATA(Union): 176 _fields_ = [('ForwarderString', c_uint), 177 ('Function', c_uint), 178 ('Ordinal', c_uint), 179 ('AddressOfData', c_uint)] 180 181 182class IMAGE_IMPORT_DESCRIPTOR(Structure): 183 _fields_ = [('OriginalFirstThunk', c_uint), 184 ('TimeDateStamp', c_uint), 185 ('ForwarderChain', c_uint), 186 ('Name', c_uint), 187 ('FirstThunk', c_uint)] 188 189class IMAGE_EXPORT_DIRECTORY(Structure): 190 _fields_ = [('Characteristics',c_uint), 191 ('TimeDateStamp',c_uint), 192 ('MajorVersion', c_ushort), 193 ('MinorVersion', c_ushort), 194 ('Name',c_uint), 195 ('Base',c_uint), 196 ('NumberOfFunctions',c_uint), 197 ('NumberOfNames',c_uint), 198 ('AddressOfFunctions',c_uint), 199 ('AddressOfNames',c_uint), 200 ('AddressOfNameOrdinals',c_uint) 201 ] 202 203class GUARD_CFF_ENTRY(Structure): 204 _fields_ = [('rva',c_uint), 205 ('flag', c_byte)] 206 207##################### PE32 ######################## 208 209class IMAGE_OPTIONAL_HEADER(Structure): 210 _fields_ = [('Magic', c_ushort), 211 ('MajorLinkerVersion', c_byte), 212 ('MinorLinkerVersion', c_byte), 213 ('SizeOfCode', c_uint), 214 ('SizeOfInitializedData', c_uint), 215 ('SizeOfUninitializedData', c_uint), 216 ('AddressOfEntryPoint', c_uint), 217 ('BaseOfCode', c_uint), 218 ('BaseOfData', c_uint), 219 ('ImageBase', c_uint), 220 ('SectionAlignment', c_uint), 221 ('FileAlignment', c_uint), 222 ('MajorOperatingSystemVersion', c_ushort), 223 ('MinorOperatingSystemVersion', c_ushort), 224 ('MajorImageVersion', c_ushort), 225 ('MinorImageVersion', c_ushort), 226 ('MajorSubsystemVersion', c_ushort), 227 ('MinorSubsystemVersion', c_ushort), 228 ('Win32VersionValue', c_uint), 229 ('SizeOfImage', c_uint), 230 ('SizeOfHeaders', c_uint), 231 ('CheckSum', c_uint), 232 ('Subsystem', c_ushort), 233 ('DllCharacteristics', c_ushort), 234 ('SizeOfStackReserve', c_uint), 235 ('SizeOfStackCommit', c_uint), 236 ('SizeOfHeapReserve', c_uint), 237 ('SizeOfHeapCommit', c_uint), 238 ('LoaderFlags', c_uint), 239 ('NumberOfRvaAndSizes', c_uint), 240 ('DataDirectory', IMAGE_DATA_DIRECTORY * 16)] 241 242 243class PE32_IMAGE_NT_HEADERS(Structure): 244 _fields_ = [('Signature', c_char * 4), 245 ('FileHeader', IMAGE_FILE_HEADER), 246 ('OptionalHeader', IMAGE_OPTIONAL_HEADER)] 247 248class PE32(object): 249 IMAGE_NT_HEADERS = PE32_IMAGE_NT_HEADERS 250 251 252class IMAGE_LOAD_CONFIG_DIRECTORY32(Structure): 253 _fields_ = [('Size', c_uint), 254 ('TimeDateStamp', c_uint), 255 ('MajorVersion', c_ushort), 256 ('MinorVersion', c_ushort), 257 ('GlobalFlagsClear', c_uint), 258 ('GlobalFlagsSet', c_uint), 259 ('CriticalSectionDefaultTimeout', c_uint), 260 ('DeCommitFreeBLockThreshold', c_uint), 261 ('DeCommitTotalFreeThreshold', c_uint), 262 ('LockPrefixTable', c_uint), 263 ('MaximumAllocationSize', c_uint), 264 ('VirtualMemoryThreshold', c_uint), 265 ('ProcessHeapFlags', c_uint), 266 ('ProcessAffinityMask', c_uint), 267 ('CSDVersion', c_ushort), 268 ('Reserved1', c_ushort), 269 ('EditList', c_uint), 270 ('SecurityCookie', c_uint), 271 ('SEHandlerTable', c_uint), 272 ('SEHandlerCount', c_uint), 273 ('GuardCFCheckFunctionPointer', c_uint), 274 ('Reserved2', c_uint), 275 ('GuardCFFunctionTable', c_uint), 276 ('GuardCFFunctionCount', c_uint), 277 ('GuardFlags', c_uint)] 278 279 280######################### PE64 ######################## 281 282class IMAGE_OPTIONAL_HEADER_PE32_PLUS(Structure): 283 _fields_ = [('Magic', c_ushort), 284 ('MajorLinkerVersion', c_ubyte), 285 ('MinorLinkerVersion', c_ubyte), 286 ('SizeOfCode', c_uint), 287 ('SizeOfInitializedData', c_uint), 288 ('SizeOfUninitializedData', c_uint), 289 ('AddressOfEntryPoint', c_uint), 290 ('BaseOfCode', c_uint), 291 ('ImageBase', c_ulonglong), 292 ('SectionAlignment', c_uint), 293 ('FileAlignment', c_uint), 294 ('MajorOperatingSystemVersion', c_ushort), 295 ('MinorOperatingSystemVersion', c_ushort), 296 ('MajorImageVersion', c_ushort), 297 ('MinorImageVersion', c_ushort), 298 ('MajorSubsystemVersion', c_ushort), 299 ('MinorSubsystemVersion', c_ushort), 300 ('Win32VersionValue', c_uint), 301 ('SizeOfImage', c_uint), 302 ('SizeOfHeaders', c_uint), 303 ('CheckSum', c_uint), 304 ('Subsystem', c_ushort), 305 ('DllCharacteristics', c_ushort), 306 ('SizeOfStackReserve', c_ulonglong), 307 ('SizeOfStackCommit', c_ulonglong), 308 ('SizeOfHeapReserve', c_ulonglong), 309 ('SizeOfHeapCommit', c_ulonglong), 310 ('LoaderFlags', c_uint), 311 ('NumberOfRvaAndSizes', c_uint), 312 ('DataDirectory', IMAGE_DATA_DIRECTORY * 16)] 313 314 315class PE64_IMAGE_NT_HEADERS(Structure): 316 _fields_ = [('Signature', c_char * 4), 317 ('FileHeader', IMAGE_FILE_HEADER), 318 ('OptionalHeader', IMAGE_OPTIONAL_HEADER_PE32_PLUS)] 319 320class PE64(object): 321 IMAGE_NT_HEADERS = PE64_IMAGE_NT_HEADERS 322 323 324class IMAGE_LOAD_CONFIG_DIRECTORY64(Structure): 325 _fields_ = [('Size', c_uint), 326 ('TimeDateStamp', c_uint), 327 ('MajorVersion', c_ushort), 328 ('MinorVersion', c_ushort), 329 ('GlobalFlagsClear', c_uint), 330 ('GlobalFlagsSet', c_uint), 331 ('CriticalSectionDefaultTimeout', c_uint), 332 ('DeCommitFreeBLockThreshold', c_ulonglong), 333 ('DeCommitTotalFreeThreshold', c_ulonglong), 334 ('LockPrefixTable', c_ulonglong), 335 ('MaximumAllocationSize', c_ulonglong), 336 ('VirtualMemoryThreshold', c_ulonglong), 337 ('ProcessAffinityMask', c_ulonglong), 338 ('ProcessHeapFlags', c_uint), 339 ('CSDVersion', c_ushort), 340 ('Reserved1', c_ushort), 341 ('EditList', c_ulonglong), 342 ('SecurityCookie', c_ulonglong), 343 ('SEHandlerTable', c_ulonglong), 344 ('SEHandlerCount', c_ulonglong), 345 ('GuardCFCheckFunctionPointer', c_ulonglong), 346 ('Reserved2', c_ulonglong), 347 ('GuardCFFunctionTable', c_ulonglong), 348 ('GuardCFFunctionCount', c_ulonglong), 349 ('GuardFlags', c_uint)] 350 351##################### Container ################### 352 353 354def to_offset(addr, section): 355 return addr - section.header.VirtualAddress 356 357def to_raw_address(addr, section): 358 """Converts the addr from a rva to a pointer to raw data in the file""" 359 return addr - section.header.VirtualAddress + section.header.PointerToRawData 360 361class ImageDosHeaderData(Container): 362 """ 363 header = IMAGE_DOS_HEADER 364 """ 365 366class ImageNtHeaderData(Container): 367 """ 368 header = IMAGE_NT_HEADERS 369 """ 370 371class SectionData(Container): 372 """ 373 header = IMAGE_SECTION_HEADER 374 name = name of the section (str) 375 bytes = bytes of section (bytearray) 376 raw = bytes of section (c_ubyte_array) 377 """ 378 379class DataDirectoryData(Container): 380 """ 381 header = IMAGE_DATA_DIRECTORY 382 """ 383 384class ImportDescriptorData(Container): 385 """ 386 header = IMAGE_IMPORT_DESCRIPTOR 387 dllName = name of dll (str) 388 importNameTable = list of IMAGE_THUNK_DATA 389 importAddressTable = list of IMAGE_THUNK_DATA 390 """ 391 392class ImportByNameData(Container): 393 """ 394 header = IMAGE_IMPORT_BY_NAME 395 name = name of function (str) 396 """ 397 398 399class ThunkData(Container): 400 """ 401 header = IMAGE_THUNK_DATA 402 rva = relative virtual address of thunk 403 ordinal = None | Ordinal 404 importByName = None| ImportByNameData 405 """ 406 407class ExportDirectoryData(Container): 408 """ 409 header = IMAGE_EXPORT_DIRECTORY 410 name = name of dll (str) 411 functions = list of FunctionData 412 """ 413 414class LoadConfigData(Container): 415 """" 416 header = IMAGE_LOAD_CONFIG_DIRECTORY32/IMAGE_LOAD_CONFIG_DIRECTORY64 417 cfGuardedFunctions = list of relative virtual addresses (RVA) of cfg allowed call/jmp targets. Empty if CFG not supported 418 """ 419 420class FunctionData(Container): 421 """ 422 name = name of the function (str) 423 ordinal = ordinal (int) 424 rva = relative virtual address of function (int) 425 """ 426 427def checkOffset(offset, section): 428 size = len(section.raw) 429 if offset < 0 or offset > size: 430 raise BinaryError('Invalid offset: {} (data size: {})'.format(offset, size)) 431 432class PE(Binary): 433 434 def __init__(self, fileName, fileContent=None, parse_header_only=False): 435 super(PE, self).__init__(fileName, fileContent) 436 437 438 439 self.__imageDosHeader = self._parseImageDosHeader(self._bytes) 440 self.__classes = self._getSuitableClasses(self._bytes, self.imageDosHeader) 441 442 if not self.__classes: 443 raise BinaryError('Bad architecture') 444 445 self.__imageNtHeaders = self._parseImageNtHeaders(self._bytes, self.imageDosHeader) 446 self.__sections = self._parseSections(self._bytes, self.imageDosHeader, self.imageNtHeaders, parse_header_only=parse_header_only) 447 448 if parse_header_only: 449 self.__dataDirectory = None 450 else: 451 self.__dataDirectory = self._parseDataDirectory(self._bytes, self.sections, self.imageNtHeaders) 452 453 454 @property 455 def _classes(self): 456 return self.__classes 457 458 @property 459 def imageDosHeader(self): 460 return self.__imageDosHeader 461 462 @property 463 def imageNtHeaders(self): 464 return self.__imageNtHeaders 465 466 @property 467 def sections(self): 468 return self.__sections 469 470 @property 471 def dataDirectory(self): 472 return self.__dataDirectory 473 474 475 @property 476 def entryPoint(self): 477 return self.imageNtHeaders.header.OptionalHeader.ImageBase + self.imageNtHeaders.header.OptionalHeader.AddressOfEntryPoint 478 479 @property 480 def imageBase(self): 481 return self.imageNtHeaders.header.OptionalHeader.ImageBase 482 483 @property 484 def type(self): 485 return 'PE' 486 487 def _getSuitableClasses(self, data, imageDosHeader): 488 """Returns the class which holds the suitable classes for the loaded file""" 489 classes = None 490 machine = IMAGE_FILE_MACHINE[c_ushort.from_buffer(data,imageDosHeader.header.e_lfanew+4).value] 491 492 if machine == IMAGE_FILE_MACHINE.I386: 493 classes = PE32 494 elif machine == IMAGE_FILE_MACHINE.AMD64: 495 classes = PE64 496 497 return classes 498 499 def _parseImageDosHeader(self, data): 500 """Returns the ImageDosHeader""" 501 ioh = IMAGE_DOS_HEADER.from_buffer(data) 502 if ioh.e_magic != b'MZ': 503 raise BinaryError('No valid PE/COFF file') 504 505 return ImageDosHeaderData(header=ioh) 506 507 def _parseImageNtHeaders(self, data, imageDosHeader): 508 """Returns the ImageNtHeaders""" 509 inth = self._classes.IMAGE_NT_HEADERS.from_buffer(data, imageDosHeader.header.e_lfanew) 510 511 if inth.Signature != b'PE': 512 raise BinaryError('No valid PE/COFF file') 513 514 return ImageNtHeaderData(header=inth) 515 516 def _parseSections(self, data, imageDosHeader, imageNtHeaders, parse_header_only=False): 517 """Parses the sections in the memory and returns a list of them""" 518 sections = [] 519 520 optional_header_offset = imageDosHeader.header.e_lfanew + 4 + sizeof(IMAGE_FILE_HEADER) 521 offset = optional_header_offset + imageNtHeaders.header.FileHeader.SizeOfOptionalHeader # start reading behind the dos- and ntheaders 522 523 image_section_header_size = sizeof(IMAGE_SECTION_HEADER) 524 IMAGE_SIZEOF_SYMBOL = 18 525 strtable_offset = imageNtHeaders.header.FileHeader.PointerToSymbolTable + IMAGE_SIZEOF_SYMBOL * imageNtHeaders.header.FileHeader.NumberOfSymbols 526 527 for sectionNo in range(imageNtHeaders.header.FileHeader.NumberOfSections): 528 ishdr = IMAGE_SECTION_HEADER.from_buffer(data, offset) 529 530 if parse_header_only: 531 raw = None 532 bytes_ = bytearray() 533 else: 534 size = ishdr.SizeOfRawData 535 raw = (c_ubyte * size).from_buffer(data, ishdr.PointerToRawData) 536 bytes_ = bytearray(raw) 537 538 secname = ishdr.Name.decode('ASCII', errors='ignore') 539 if secname.startswith('/'): 540 name_offset = int(secname[1:]) + strtable_offset 541 s = bytearray() 542 while self._bytes[name_offset] != 0: 543 s.append(self._bytes[name_offset]) 544 name_offset += 1 545 secname = bytes(s).decode('ASCII', errors='ignore') 546 547 sections.append(SectionData(header=ishdr, name=secname, bytes=bytes_, raw=raw)) 548 549 offset += image_section_header_size 550 551 return sections 552 553 def _getSectionForDataDirectoryEntry(self, data_directory_entry, sections): 554 """Returns the section which contains the data of DataDirectory""" 555 for section in sections: 556 if data_directory_entry.VirtualAddress >= section.header.VirtualAddress and \ 557 data_directory_entry.VirtualAddress < section.header.VirtualAddress + section.header.SizeOfRawData : 558 559 return section 560 561 def _parseDataDirectory(self, data, sections, imageNtHeaders): 562 """Parses the entries of the DataDirectory and returns a list of the content""" 563 data_directory_data_list = [None for i in range(15)] 564 565 # parse DataDirectory[Export] 566 export_data_directory = imageNtHeaders.header.OptionalHeader.DataDirectory[ImageDirectoryEntry.EXPORT] 567 export_section = self._getSectionForDataDirectoryEntry(export_data_directory, sections) 568 export_data_directory_data = self._parseDataDirectoryExport(data, export_data_directory, export_section) 569 data_directory_data_list[ImageDirectoryEntry.EXPORT] = export_data_directory_data 570 571 # parse DataDirectory[Import] 572 import_data_directory = imageNtHeaders.header.OptionalHeader.DataDirectory[ImageDirectoryEntry.IMPORT] 573 import_section = self._getSectionForDataDirectoryEntry(import_data_directory, sections) 574 import_data_directory_data = self._parseDataDirectoryImport(import_data_directory, import_section) 575 data_directory_data_list[ImageDirectoryEntry.IMPORT] = import_data_directory_data 576 577 # parse DataDirectory[LOAD_CONFIG] 578 loadconfig_data_directory = imageNtHeaders.header.OptionalHeader.DataDirectory[ImageDirectoryEntry.LOAD_CONFIG] 579 loadconfig_section = self._getSectionForDataDirectoryEntry(loadconfig_data_directory, sections) 580 loadconfig_data = self._parseLoadConfig(loadconfig_data_directory, loadconfig_section) 581 data_directory_data_list[ImageDirectoryEntry.LOAD_CONFIG] = loadconfig_data 582 583 return data_directory_data_list 584 585 def _parseDataDirectoryExport(self, data, dataDirectoryEntry, exportSection): 586 """Parses the EmportDataDirectory and returns an instance of ExportDirectoryData""" 587 if not exportSection: 588 return 589 functions = [] 590 export_directory = IMAGE_EXPORT_DIRECTORY.from_buffer(exportSection.raw, to_offset(dataDirectoryEntry.VirtualAddress, exportSection)) 591 offset = to_offset(export_directory.Name, exportSection) 592 593 checkOffset(offset, exportSection) 594 name = get_str(exportSection.raw, offset) 595 596 offsetOfNames = to_offset(export_directory.AddressOfNames, exportSection) 597 offsetOfAddress = to_offset(export_directory.AddressOfFunctions, exportSection) 598 offsetOfNameOrdinals = to_offset(export_directory.AddressOfNameOrdinals, exportSection) 599 for i in range(export_directory.NumberOfNames): 600 name_address = c_uint.from_buffer(exportSection.raw, offsetOfNames).value 601 name_offset = to_offset(name_address, exportSection) 602 603 checkOffset(name_offset, exportSection) 604 func_name = get_str(exportSection.raw, name_offset) 605 ordinal = c_ushort.from_buffer(exportSection.raw, offsetOfNameOrdinals).value 606 func_addr = c_uint.from_buffer(exportSection.raw, offsetOfAddress).value 607 608 offsetOfNames += 4 609 offsetOfAddress += 4 610 offsetOfNameOrdinals += 2 611 functions.append(FunctionData(name=func_name, rva=func_addr, ordinal=ordinal)) 612 613 return ExportDirectoryData(header=export_directory, name=name, functions=functions) 614 615 def _parseDataDirectoryImport(self, dataDirectoryEntry, importSection): 616 """Parses the ImportDataDirectory and returns a list of ImportDescriptorData""" 617 if not importSection: 618 return 619 620 621 raw_bytes = (c_ubyte * dataDirectoryEntry.Size).from_buffer(importSection.raw, to_offset(dataDirectoryEntry.VirtualAddress, importSection)) 622 offset = 0 623 import_descriptors = [] 624 while True: 625 import_descriptor = IMAGE_IMPORT_DESCRIPTOR.from_buffer(raw_bytes, offset) 626 627 628 if import_descriptor.OriginalFirstThunk == 0: 629 break 630 else: 631 nameOffset = to_offset(import_descriptor.Name, importSection) 632 633 checkOffset(nameOffset, importSection) 634 dllName = get_str(importSection.raw, nameOffset) 635 636 import_name_table = self.__parseThunks(import_descriptor.OriginalFirstThunk, importSection) 637 import_address_table = self.__parseThunks(import_descriptor.FirstThunk, importSection) 638 639 import_descriptors.append(ImportDescriptorData(header=import_descriptor, dllName=dllName, importNameTable=import_name_table, importAddressTable=import_address_table)) 640 offset += sizeof(IMAGE_IMPORT_DESCRIPTOR) 641 return import_descriptors 642 643 def _getSectionByRVA(self, va): 644 for section in self.sections: 645 address = section.header.VirtualAddress 646 SizeOfRawData = section.header.SizeOfRawData 647 if address <= va and va < (address + SizeOfRawData): 648 return section 649 650 return 651 652 def _parseLoadConfig(self, loadConfigEntry, loadconfigSection): 653 if not loadconfigSection: 654 return 655 656 if self._classes == PE64: 657 load_config_directory = IMAGE_LOAD_CONFIG_DIRECTORY64.from_buffer( 658 loadconfigSection.raw, to_offset(loadConfigEntry.VirtualAddress, loadconfigSection)) 659 660 pass 661 662 elif self._classes == PE32: 663 load_config_directory = IMAGE_LOAD_CONFIG_DIRECTORY32.from_buffer( 664 loadconfigSection.raw, to_offset(loadConfigEntry.VirtualAddress, loadconfigSection)) 665 666 pass 667 else: 668 pass 669 670 guardCFTableRVA = load_config_directory.GuardCFFunctionTable - self.imageBase 671 section = self._getSectionByRVA(guardCFTableRVA) 672 CfGuardedFunctions = set() 673 if section: 674 sectionOffset = guardCFTableRVA - section.header.VirtualAddress 675 676 # loop through the ControlFlow Guard Function table 677 for i in range(0, load_config_directory.GuardCFFunctionCount): 678 cffEntry = GUARD_CFF_ENTRY.from_buffer(section.raw, sectionOffset) 679 CfGuardedFunctions.add(cffEntry.rva) 680 sectionOffset += 5 681 682 return LoadConfigData(header=load_config_directory, cfGuardedFunctions=CfGuardedFunctions ) 683 684 def __parseThunks(self, thunkRVA, importSection): 685 """Parses the thunks and returns a list""" 686 offset = to_offset(thunkRVA, importSection) 687 table_offset = 0 688 thunks = [] 689 while True: 690 thunk = IMAGE_THUNK_DATA.from_buffer(importSection.raw, offset) 691 offset += sizeof(IMAGE_THUNK_DATA) 692 if thunk.Ordinal == 0: 693 break 694 thunkData = ThunkData(header=thunk, rva=table_offset+thunkRVA,ordinal=None, importByName=None) 695 if to_offset(thunk.AddressOfData, importSection) > 0 and to_offset(thunk.AddressOfData, importSection) < len(self._bytes): 696 self.__parseThunkData(thunkData, importSection) 697 thunks.append(thunkData) 698 table_offset += 4 699 return thunks 700 701 def __parseThunkData(self, thunk,importSection): 702 """Parses the data of a thunk and sets the data""" 703 offset = to_offset(thunk.header.AddressOfData, importSection) 704 if 0xf0000000 & thunk.header.AddressOfData == 0x80000000: 705 thunk.ordinal = thunk.header.AddressOfData & 0x0fffffff 706 else: 707 ibn = IMAGE_IMPORT_BY_NAME.from_buffer(importSection.raw, offset) 708 709 checkOffset(offset+2, importSection) 710 name = get_str(importSection.raw, offset+2) 711 thunk.importByName = ImportByNameData(header=ibn, hint=ibn.Hint, name=name) 712 713 @classmethod 714 def isSupportedContent(cls, fileContent): 715 """Returns if the files are valid for this filetype""" 716 return bytearray(fileContent)[:2] == b'MZ' 717