def _dump_section_headers(pe): """ Small internal function to dump the section headers in a table. Returns a string to do so. """ section_string = '' section_flags = pefile.retrieve_flags(pefile.SECTION_CHARACTERISTICS, 'IMAGE_SCN_') section_string += '\nNumber of Sections: %d\n' % pe.FILE_HEADER.NumberOfSections section_string += '{0:15} {1:8} {2:40}\n'.format( 'Section Name', 'Entropy', 'Flags') section_string += '-' * 65 + '\n' for section in pe.sections: # thanks to the pefile example code for this flags = [] for flag in section_flags: if getattr(section, flag[0]): flags.append(flag[0]) # the following line was taken from Didier Steven's pecheck.py code section_string += '{0:15} {1:<8.5} {2:40}\n'.format(''.join(filter(lambda c:c != '\0', str(section.Name))), \ section.get_entropy(), ', '.join(flags)) section_string += '\n' return section_string
def __repr__(self): fobj = "\n\n" fobj += "---- File Summary ----\n" fobj += "\n" fobj += ' General\n' fobj += ' {:4}{:<16} {}\n'.format('', "Filename", self.filename) fobj += ' {:4}{:<16} {}\n'.format('', "Magic Type", self.magic_type(self.filename)) fobj += ' {:4}{:<16} {}\n'.format('', "Size", self.filesize) fobj += ' {:4}{:<16} {}\n\n'.format('', "First Bytes", self.getbytestring(0, 16)) fobj += ' Hashes\n' fobj += ' {:4}{:<16} {}\n'.format('', "MD5", self.gethash('md5')) fobj += ' {:4}{:<16} {}\n'.format('', "SHA1", self.gethash('sha1')) fobj += ' {:4}{:<16} {}\n'.format('', "SHA256", self.gethash('sha256')) fobj += ' {:4}{:<16} {}\n'.format('', "Import Hash", self.getimphash()) fobj += ' {:4}{:<16} {}\n\n'.format('', "ssdeep", self.getfuzzyhash()) fobj += ' Headers\n' if self.pe is not None: for str_key in self.metadata: fobj += ' {:4}{:<16} {}\n'.format('', str_key, self.metadata[str_key]) fobj += ' {:4}{:<16} {}\n'.format('', "PDB Path", self.get_pdb_path()) iflags = pefile.retrieve_flags(pefile.IMAGE_CHARACTERISTICS, 'IMAGE_FILE_') fobj += ' {:4}{:<16} \n'.format('', "Characteristics") for flag in iflags: if getattr(self.pe.FILE_HEADER, flag[0]): fobj += " {:20s} {:<20s}\n".format('', str(flag[0])) return fobj
def get_image_flags(self, imageflags='IMAGE_FILE_'): iflags = pefile.retrieve_flags(pefile.IMAGE_CHARACTERISTICS, imageflags) flags = [] for flag in iflags: if getattr(self.pe.FILE_HEADER, flag[0]): flags.append(flag[0]) return flags
def _main(): if len(sys.argv) != 2: usage() fn = sys.argv[1] # Retrieve code section(s') contents code = list() pe = pefile.PE(fn) for section in pe.sections: section_flags = pefile.retrieve_flags(pefile.SECTION_CHARACTERISTICS, 'IMAGE_SCN_') isCode = False for flag, value in section_flags: if section.__dict__[flag] is True: if flag == 'IMAGE_SCN_CNT_CODE' or flag == 'IMAGE_SCN_MEM_EXECUTE': isCode = True break if isCode: offset = section.PointerToRawData end = offset + section.SizeOfRawData code.extend(pe.__data__[offset:end]) # Print out code seciton bytes #print(code) for sec in code: print(str(hex(sec))[1:], end="")
def dump_sections(): print('\n---------- sections ----------') if pe.sections: print('{:<10}{:<16}{:<16}{:<16}{:<16}{:<16}'.format( 'name', 'virtual addr', 'virtual size', 'raw size', 'entropy', 'flags')) section_flags = pefile.retrieve_flags(pefile.SECTION_CHARACTERISTICS, 'IMAGE_SCN_') for section in pe.sections: s_name = section.Name.rstrip(b'\x00').decode() s_vaddr = hex(section.VirtualAddress) s_vsize = hex(section.Misc_VirtualSize) s_rsize = hex(section.SizeOfRawData) s_entropy = section.get_entropy() flags = [] for flag in sorted(section_flags): if getattr(section, flag[0]): flags.append(flag[0][10:]) s_flags = ', '.join(flags) print('{:<10}{:<16}{:<16}{:<16}{:<16f}{:<}'.format( s_name, s_vaddr, s_vsize, s_rsize, s_entropy, s_flags))
def _dump_section_headers(pe): """ Small internal function to dump the section headers in a table. Returns a string to do so. """ section_string = '' section_flags = pefile.retrieve_flags(pefile.SECTION_CHARACTERISTICS, 'IMAGE_SCN_') section_string += '\nNumber of Sections: %d\n' % pe.FILE_HEADER.NumberOfSections section_string += '{0:15} {1:8} {2:40}\n'.format('Section Name', 'Entropy', 'Flags') section_string += '-'*65 + '\n' for section in pe.sections: # thanks to the pefile example code for this flags = [] for flag in section_flags: if getattr(section, flag[0]): flags.append(flag[0]) # the following line was taken from Didier Steven's pecheck.py code section_string += '{0:15} {1:<8.5} {2:40}\n'.format(''.join(filter(lambda c:c != '\0', str(section.Name))), \ section.get_entropy(), ', '.join(flags)) section_string += '\n' return section_string
def getSampleFeatures(self): try: self.pe = pefile.PE(self.exePath) except OSError as e: print(e) except pefile.PEFormatError as e: print("---PEFormatError: %s---" % e.value) try: self.peSignature = hex( self.pe.NT_HEADERS.Signature) #get signature except: print('No Signature') self.peNumberOfSections = self.pe.FILE_HEADER.NumberOfSections #get number of sections self.peEntryAddress = hex( self.pe.OPTIONAL_HEADER.AddressOfEntryPoint) #get address of entry self.peImageBase = hex( self.pe.OPTIONAL_HEADER.ImageBase) #get Image Base #pe section data '''fix for issue where object data would be kept even after the object was deleted''' self.peSectionDict.clear() self.peSectionArray = [] sectionPermissions = pefile.retrieve_flags( pefile.SECTION_CHARACTERISTICS, 'IMAGE_SCN_' ) #returns list of section flags from dict defined in pefile.py for section in self.pe.sections: #loop through all sections try: self.stringHolder = section.Name.decode( 'utf-8') #name data is in utf-8 format self.peSectionName = self.stringHolder.replace( '\x00', '') #remove extra zero hex values from name except: self.peSectionName = section.Name self.peSectionVirtualAddress = hex( section.VirtualAddress) #get VA of section #check if section is at entry point, this is a heuristic explained in (1) if self.peSectionVirtualAddress == (self.peEntryAddress + self.peImageBase): self.peSectionIsEntryPoint = True self.peSectionVirtualSize = hex( section.Misc_VirtualSize) #get virtual size of section self.peSectionRawSize = hex( section.SizeOfRawData) #get size of raw data #Add descriptions for section names if known, check for common packer names and non-packer names. This is a heuristic explained in (1) if self.peSectionName in self.packerSections: self.peSectionNameDescription = self.packerSections[ self.peSectionName] self.packerSectionName = True elif self.peSectionName in self.commonSections: self.peSectionNameDescription = self.commonSections[ self.peSectionName] else: self.peSectionNameDescription = 'unknown' self.unknownSectionName = True self.numberOfUnknownSections += 1 '''adds permissions to list for each section but not used as a feature in ES document, object flags are set accordingly and used as features''' permissions = [] for permission in sorted(sectionPermissions): if getattr(section, permission[0]): permissions.append(permission[0]) if (permission[0] == 'IMAGE_SCN_MEM_READ'): self.peSectionRead = True else: self.peSectionRead = False if (permission[0] == 'IMAGE_SCN_MEM_WRITE'): self.peSectionWrite = True else: self.peSectionWrite = False if (permission[0] == 'IMAGE_SCN_MEM_EXECUTE'): self.peSectionExecute = True else: self.peSectionExecute = False if (permission[0] == 'IMAGE_SCN_CNT_CODE'): self.peSectionContainsCode = True else: self.peSectionContainsCode = False if (permission[0] == 'IMAGE_SCN_CNT_INITIALIZED_DATA'): self.peSectionContainsInitData = True else: self.peSectionContainsInitData = False '''If a section contains code but is not executable, this is a sign of packing. This is a heuristic explained in (1)''' if (self.peSectionContainsCode == True & self.peSectionExecute == False): self.nonExecutableCodeSection = True elif self.nonExecutableCodeSection == False: self.nonExecutableCodeSection = False '''If a section contains initialized data and is executable, this is a sign of packing. This is a heuristic explained in (1)''' if (self.peSectionContainsInitData == True & self.peSectionExecute == True): self.executableDataSection = True elif self.executableDataSection == False: self.executableDataSection = False self.peSectionEntropy = section.get_entropy() #get entropy (0-8) #check for the code section, this is a heuristic explained in (1) if self.peSectionName == 'CODE': self.containsNamedCodeSection = True elif self.containsNamedCodeSection == False: self.containsNamedCodeSection = False #create dict and add that to an array self.peSectionDict = { 'sectionName': self.peSectionName, 'sectionVirtualAddress': self.peSectionVirtualAddress, 'sectionVirtualSize': self.peSectionVirtualSize, 'sectionRawSize': self.peSectionRawSize, 'sectionIsEntryPoint': self.peSectionIsEntryPoint, 'sectionDescription': self.peSectionNameDescription, 'sectionEntropy': self.peSectionEntropy, 'sectionRead': self.peSectionRead, 'sectionWrite': self.peSectionWrite, 'sectionExecute': self.peSectionExecute, 'sectionContainsCode': self.peSectionContainsCode, 'sectionContainsData': self.peSectionContainsInitData } self.peSectionArray.append(dict(self.peSectionDict)) try: #import data self.peNumberOfImports = 0 for entry in self.pe.DIRECTORY_ENTRY_IMPORT: self.stringHolder = entry.dll.decode( 'utf-8') #name data is in utf-8 format self.peLibraryName = self.stringHolder.replace( '\x00', '') #remove extra zero hex values from name for func in entry.imports: #loop through all imports self.stringHolder = func.name.decode( 'utf-8') #name data is in utf-8 format self.peFunctionName = self.stringHolder.replace( '\x00', '') #remove extra zero hex values from name #self.peFunctionAddress = hex(func.address)#get address self.peImportDict = { 'libraryName': self.peLibraryName, 'functionName': self.peFunctionName } self.peImportArray.append(dict(self.peImportDict)) self.peNumberOfImports += 1 except: print('No Import Data') self.peNumberOfImports = 0 try: #export data self.peNumberOfExports = 0 for exp in self.pe.DIRECTORY_ENTRY_EXPORT.symbols: #loop through exports self.stringHolder = exp.name.decode( 'utf-8') #name data is in utf-8 format self.peExportName = self.stringHolder.replace( '\x00', '') #remove extra zero hex values from name #self.peExportAddress = hex(self.pe.OPTIONAL_HEADER.ImageBase + exp.address)#get export address self.peExportDict = {'exportName': self.peExportName} self.peExportArray.append(dict(self.peExportDict)) self.peNumberOfExports += 1 except: print('No Export Data') self.peNumberOfExports = 0 #build features for the body of ES document self.features = { 'ID': self.sampleIDCounter, 'fileName': self.fileName, 'md5': self.md5, 'numberOfSections': self.peNumberOfSections, 'addressOfEntry': self.peEntryAddress, 'imageBase': self.peImageBase } self.features.update( {'sectionData': self.peSectionArray} ) #sectionData is a nested object, peSectionArray is an array of dictionary entries self.features.update({'packerSectionName': self.packerSectionName}) self.features.update({'unknownSectionName': self.unknownSectionName}) self.features.update( {'containsNamedCodeSection': self.containsNamedCodeSection}) self.features.update( {'nonExecutableCodeSection': self.nonExecutableCodeSection}) self.features.update( {'executableDataSection': self.executableDataSection}) self.features.update({'importData': self.peImportArray}) #nested object self.features.update({'numberOfImports': self.peNumberOfImports}) self.features.update({'exportData': self.peExportArray}) #nested object self.features.update({'numberOfExports': self.peNumberOfExports}) #print (self.features) self.es.create(index='samples', doc_type='sample', id=self.sampleIDCounter, body=self.features ) #create document with attributes pulled from sample
def dump_info(self): """This is a simplified version of PE.dumpinfo(self)""" dump = pefile.Dump() warnings = self.get_warnings() if warnings: dump.add_header('Parsing Warnings') for warning in warnings: dump.add_line(warning) dump.add_header('PE Sections') section_flags = pefile.retrieve_flags(pefile.SECTION_CHARACTERISTICS, 'IMAGE_SCN_') for section in self.sections: dump.add_lines(section.dump()) dump.add('Flags: ') flags = [] for flag in section_flags: if getattr(section, flag[0]): flags.append(flag[0]) dump.add_line(', '.join(flags)) dump.add_line('Entropy: %f (Min=0.0, Max=8.0)' % section.get_entropy() ) if pefile.md5 is not None: dump.add_line('MD5 hash: %s' % section.get_hash_md5() ) dump.add_newline() if hasattr(self, 'DIRECTORY_ENTRY_IMPORT'): dump.add_header('Imported symbols') for module in self.DIRECTORY_ENTRY_IMPORT: for symbol in module.imports: if symbol.import_by_ordinal is True: dump.add('%s Ordinal[%s] (Imported by Ordinal)' % ( module.dll, str(symbol.ordinal))) else: dump.add('%s.%s Hint[%s]' % ( module.dll, symbol.name, str(symbol.hint))) if symbol.bound: dump.add_line(' Bound: 0x%08X' % (symbol.bound)) else: dump.add_newline() dump.add_newline() if hasattr(self, 'DIRECTORY_ENTRY_BOUND_IMPORT'): dump.add_header('Bound imports') for bound_imp_desc in self.DIRECTORY_ENTRY_BOUND_IMPORT: dump.add_line('DLL: %s' % bound_imp_desc.name) dump.add_newline() for bound_imp_ref in bound_imp_desc.entries: dump.add_lines(bound_imp_ref.struct.dump(), 4) dump.add_line('DLL: %s' % bound_imp_ref.name, 4) dump.add_newline() if hasattr(self, 'DIRECTORY_ENTRY_DELAY_IMPORT'): dump.add_header('Delay Imported symbols') for module in self.DIRECTORY_ENTRY_DELAY_IMPORT: for symbol in module.imports: if symbol.import_by_ordinal is True: dump.add('%s Ordinal[%s] (Imported by Ordinal)' % ( module.dll, str(symbol.ordinal))) else: dump.add('%s.%s Hint[%s]' % ( module.dll, symbol.name, str(symbol.hint))) if symbol.bound: dump.add_line(' Bound: 0x%08X' % (symbol.bound)) else: dump.add_newline() dump.add_newline() return dump.get_text()
def print_sections(target, dumprva=None): try: dump_address = dumprva[0] except: dump_address = 0 # Get overlay start overlay = target.detect_overlay() if not target.verbose: sdata = "\n ---- Section Overview (use -v for detailed section info) ---- \n\n" sdata += " {:12}{:12}{:18}{:20}{:20}{:20}{:20}\n".format( "Name", "Raw Size", "Raw Data Pointer", "Virtual Address", "Virtual Size", "Entropy", "Hash") for section in target.pe.sections: sdata += " {:12}".format(section.Name.strip('\0')) sdata += "{:12}".format("{0:#0{1}x}".format( section.SizeOfRawData, 10)) sdata += "{:18}".format("{0:#0{1}x}".format( section.PointerToRawData, 10)) sdata += "{:20}".format("{0:#0{1}x}".format( section.VirtualAddress, 10)) sdata += "{:20}".format("{0:#0{1}x}".format( section.Misc_VirtualSize, 10)) sdata += "{:<20}".format(section.get_entropy()) sdata += "{:<20}".format( hashlib.md5(section.get_data()).hexdigest()) if dump_address == 'ALL' or dump_address == '{0:#0{1}x}'.format( section.VirtualAddress, 10): sdata += " [Exported]" with open( 'exported-%s-%s' % (section.Name.strip('\0'), '{0:#0{1}x}'.format( section.VirtualAddress, 10)), 'wb') as out: out.write(section.get_data()) sdata += "\n" # Check for overlay if overlay > 0: overlay_size = target.filesize - overlay sdata += " {:12}".format('.overlay') sdata += "{:12}".format("{0:#0{1}x}".format(overlay_size, 10)) sdata += "{:18}".format(hex(overlay)) sdata += "{:20}".format('0x00000000') sdata += "{:20}".format('0x00000000') sdata += "{:<20}".format('0') sdata += "{:<20}".format('N/A') sdata += "\n" else: cflags = pefile.retrieve_flags(pefile.SECTION_CHARACTERISTICS, 'IMAGE_SCN_') sdata = '\n ---- Detailed Section Info ---- \n\n' for section in target.pe.sections: sdata += " {:10}\n".format(section.Name.strip('\0')) sdata += " {:24} {:>10}\n".format("|-Entropy:", section.get_entropy()) sdata += " {:24} {:>10}\n".format( "|-MD5 Hash:", hashlib.md5(section.get_data()).hexdigest()) sdata += " {:24} {:>10} ({:})\n".format( "|-Raw Data Size:", "{0:#0{1}x}".format(section.SizeOfRawData, 10), section.SizeOfRawData) sdata += " {:24} {:>10}\n".format( "|-Raw Data Pointer:", "{0:#0{1}x}".format(section.PointerToRawData, 10)) sdata += " {:24} {:>10}\n".format( "|-Virtual Address:", "{0:#0{1}x}".format(section.VirtualAddress, 10)) sdata += " {:24} {:>10} ({:})\n".format( "|-Virtual Size:", "{0:#0{1}x}".format(section.Misc_VirtualSize, 10), section.Misc_VirtualSize) sdata += " {:24} {:>10}\n".format( "|-Characteristics:", "{0:#0{1}x}".format(section.Characteristics, 10)) for flag in cflags: if getattr(section, flag[0]): sdata += " {:24}{:>5}{:<24}\n".format( '|', '|-', str(flag[0])) sdata += " {:24} {:<10}\n".format("|-Number Of Relocations:", section.NumberOfRelocations) sdata += " {:24} {:<10}\n".format("|-Line Numbers:", section.NumberOfLinenumbers) if dump_address == 'ALL' or dump_address == '{0:#0{1}x}'.format( section.VirtualAddress, 10): sdata += " |-[Exported]\n" with open( 'exported-%s-%s' % (section.Name.strip('\0'), '{0:#0{1}x}'.format( section.VirtualAddress, 10)), 'wb') as out: out.write(section.get_data()) sdata += '\n' if overlay > 0: sdata += " {:10}\n".format(".overlay") sdata += " {:24} {:>10} ({:})\n".format( "|-Raw Data Size:", "{0:#0{1}x}".format(target.filesize - overlay, 10), target.filesize - overlay) sdata += " {:24} {:>10}\n".format( "|-Raw Data Pointer:", "{0:#0{1}x}".format(overlay, 10)) print sdata