def get_group_icons(self): rt_base_dir = self.find_resource_base('RT_GROUP_ICON') groups = list() for res_index in xrange(0, len(rt_base_dir.directory.entries)): grp_icon_dir_entry = self.find_resource('RT_GROUP_ICON', res_index) if not grp_icon_dir_entry: continue data_rva = grp_icon_dir_entry.data.struct.OffsetToData size = grp_icon_dir_entry.data.struct.Size data = self.pe.get_memory_mapped_image()[data_rva:data_rva + size] file_offset = self.pe.get_offset_from_rva(data_rva) grp_icon_dir = pefile.Structure(self.GRPICONDIR_format, file_offset=file_offset) grp_icon_dir.__unpack__(data) if grp_icon_dir.Reserved != 0 or grp_icon_dir.Type != self.RES_ICON: continue offset = grp_icon_dir.sizeof() entries = list() for idx in xrange(0, grp_icon_dir.Count): grp_icon = pefile.Structure(self.GRPICONDIRENTRY_format, file_offset=file_offset + offset) grp_icon.__unpack__(data[offset:]) offset += grp_icon.sizeof() entries.append(grp_icon) groups.append(entries) return groups
def GetPDBInfoFromImg(filename): """Returns the PDB fingerprint and the pdb filename given an image file""" pe = pefile.PE(filename) for dbg in pe.DIRECTORY_ENTRY_DEBUG: if dbg.struct.Type == 2: # IMAGE_DEBUG_TYPE_CODEVIEW off = dbg.struct.AddressOfRawData size = dbg.struct.SizeOfData data = pe.get_memory_mapped_image()[off:off + size] cv = pefile.Structure(__CV_INFO_PDB70_format__) cv.__unpack__(data) cv.PdbFileName = data[cv.sizeof():] guid = pefile.Structure(__GUID_format__) guid.__unpack__(cv.Signature) if not isinstance(guid.Data4[0], int): # In non-py3 pefile, this is a list of bytes. guid.Data4 = map(ord, guid.Data4) guid.Data4_0 = ''.join("%02X" % x for x in guid.Data4[0:2]) guid.Data4_1 = ''.join("%02X" % x for x in guid.Data4[2:]) return ("%08X%04X%04X%s%s%d" % (guid.Data1, guid.Data2, guid.Data3, guid.Data4_0, guid.Data4_1, cv.Age), str(cv.PdbFileName.split(b'\x00', 1)[0].decode())) break
def get_icon_group(pe_file: pefile.PE, data_entry: pefile.Structure) -> Optional[list]: try: data_rva = data_entry.OffsetToData size = data_entry.Size data = pe_file.get_memory_mapped_image()[data_rva:data_rva + size] file_offset = pe_file.get_offset_from_rva(data_rva) grp_icon_dir = pefile.Structure(GRPICONDIR_format, file_offset=file_offset) grp_icon_dir.__unpack__(data) if grp_icon_dir.Reserved == 0 or grp_icon_dir.Type == 1: offset = grp_icon_dir.sizeof() entries = list() for idx in range(0, grp_icon_dir.Count): grp_icon = pefile.Structure(GRPICONDIRENTRY_format, file_offset=file_offset + offset) grp_icon.__unpack__(data[offset:]) offset += grp_icon.sizeof() entries.append(grp_icon) return entries except pefile.PEFormatError: pass return None
def cast_section(self, offset=None): ''' Get a section from a given offset ''' if offset is None: offset = self.get_current_offset() data = pefile.Structure( self.basepe.__IMAGE_SECTION_HEADER_format__).sizeof() * b'\x00' else: data = self.basepe.get_data( offset, pefile.Structure(self.basepe.__IMAGE_SECTION_HEADER_format__ ).sizeof()) # noqa sect = self.basepe.__unpack_data__( self.basepe.__IMAGE_SECTION_HEADER_format__, data, offset) return sect
def new_reloc_entry(addr, type): entry = pefile.Structure(pe.__IMAGE_BASE_RELOCATION_ENTRY_format__) assert (0 <= type <= 11), 'invalid type' setattr(entry, 'Data', (addr & 0xFFF) + (type << 12)) entry.set_file_offset(0) return pefile.RelocationData(struct=entry, type=type, base_rva=addr & ~0xFFF, rva=addr)
def add_section(pe, name, size, characteristics=DEFAULT_CHARACTERISTICS): # Sanity checks if len(name) > SECTION_NAME: raise Exception('[!] Section name is too long') section_header_size = pefile.Structure( pefile.PE.__IMAGE_SECTION_HEADER_format__).sizeof() section_header_off = pe.sections[-1].get_file_offset( ) + section_header_size if section_header_off + section_header_size > pe.OPTIONAL_HEADER.SizeOfHeaders: raise Exception('[!] Not enough room for another SECTION_HEADER') # Calculate/Align sizes virtual_size = align_up(size, pe.OPTIONAL_HEADER.SectionAlignment) virtual_addr = align_up( pe.sections[-1].VirtualAddress + pe.sections[-1].Misc_VirtualSize, pe.OPTIONAL_HEADER.SectionAlignment) raw_size = align_up(size, pe.OPTIONAL_HEADER.FileAlignment) raw_ptr = align_up( pe.sections[-1].PointerToRawData + pe.sections[-1].SizeOfRawData, pe.OPTIONAL_HEADER.FileAlignment) # Configure section properties section = pefile.SectionStructure(pe.__IMAGE_SECTION_HEADER_format__, pe=pe) section.set_file_offset(section_header_off) section.Name = name.encode().ljust(SECTION_NAME, b'\x00') section.VirtualAddress = virtual_addr section.PointerToRawData = raw_ptr section.Misc = section.Misc_VirtualSize = virtual_size section.SizeOfRawData = raw_size section.Characteristics = characteristics section.PointerToRelocations = 0 section.NumberOfRelocations = 0 section.NumberOfLinenumbers = 0 section.PointerToLinenumbers = 0 # Correct headers pe.FILE_HEADER.NumberOfSections += 1 pe.OPTIONAL_HEADER.SizeOfImage = virtual_addr + virtual_size # Add buffer padding pe.__data__ += b'\x00' * raw_size # Append to ensure overwrite pe.__structures__.append(section) # Recreate to save our changes pe = pefile.PE(data=pe.write()) return pe, section
def structure(self, rva, format): """ Get internal pefile Structure from specified rva :param format: :class:`pefile.Structure` format (e.g. :py:attr:`pefile.PE.__IMAGE_LOAD_CONFIG_DIRECTORY64_format__`) :rtype: :class:`pefile.Structure` """ structure = pefile.Structure(format) structure.__unpack__(self.pe.get_data(rva, structure.sizeof())) return structure
def get_exports_size(self, name, exports): ''' Get the total size of the export directory ''' # Get the total size needed for the new export section exp_size = pefile.Structure( self.basepe.__IMAGE_EXPORT_DIRECTORY_format__).sizeof() exp_size += (len(name) + 1) for exp in exports: exp_size += len(exp) + 1 exp_size += (0x4 + 0x4 + 0x4) return exp_size
def add_section(self, name, chars=0x40000040): ''' Add a section to the decoy PE ''' new_sect = self.cast_section() new_sect.Name = name.encode('utf-8') new_sect.Characteristics = chars hdr_size = pefile.Structure( self.basepe.__IMAGE_SECTION_HEADER_format__).sizeof() self.basepe.OPTIONAL_HEADER.SizeOfHeaders += hdr_size self.basepe.OPTIONAL_HEADER.SizeOfImage += hdr_size self.basepe.FILE_HEADER.NumberOfSections += 1 self.update() return new_sect
def add_to_reloc(addr, type): for x in updated_reloc: if (addr & ~0xFFF) == x.struct.VirtualAddress: # insert new entry into existed base reloc x.entries.append(new_reloc_entry(addr, type)) x.struct.SizeOfBlock += 2 return # new a entry s = pefile.Structure(pe.__IMAGE_BASE_RELOCATION_format__) setattr(s, 'VirtualAddress', addr & ~0xFFF) setattr(s, 'SizeOfBlock', 8 + 2) s.set_file_offset(0) # insert new base reloc entries = [] entries.append(new_reloc_entry(addr, type)) updated_reloc.append(pefile.BaseRelocationData(struct=s, entries=entries))
def get_relocations(pe, image, image_base): try: relocations = [] relocation_table = pe.NT_HEADERS.OPTIONAL_HEADER.DATA_DIRECTORY[ pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_BASERELOC']] rva = relocation_table.VirtualAddress size = relocation_table.Size if size == 0: return [] rlc_size = pefile.Structure( pe.__IMAGE_BASE_RELOCATION_format__).sizeof() end = rva + size while rva < end: try: rlc = pe.__unpack_data__( pe.__IMAGE_BASE_RELOCATION_format__, image[rva:rva + rlc_size], file_offset=pe.get_offset_from_rva(rva)) except pefile.PEFormatError: rlc = None if not rlc: break print("rlc.VirtualAddress: %x, rlc.SizeOfBlock: %x" % (rlc.VirtualAddress, rlc.SizeOfBlock)) relocation_entries = parse_relocations(image, image_base, pe, rva + rlc_size, rlc.VirtualAddress, rlc.SizeOfBlock - rlc_size) relocations.append( pefile.BaseRelocationData(struct=rlc, entries=relocation_entries)) if not rlc.SizeOfBlock: break rva += rlc.SizeOfBlock return relocations except Exception as ex: print(str(ex))
def get_relocations(pe, proc, moduleBaseAddress): try: relocations = [] relocTable = pe.NT_HEADERS.OPTIONAL_HEADER.DATA_DIRECTORY[pefile.DIRECTORY_ENTRY['IMAGE_DIRECTORY_ENTRY_BASERELOC']] rva = relocTable.VirtualAddress size = relocTable.Size if (size == 0): return [] rlc_size = pefile.Structure(pe.__IMAGE_BASE_RELOCATION_format__).sizeof() end = rva + size while rva<end: try: rlc = pe.__unpack_data__( pe.__IMAGE_BASE_RELOCATION_format__, proc.read(moduleBaseAddress + rva, rlc_size), file_offset = pe.get_offset_from_rva(rva) ) except PEFormatError: rlc = None if not rlc: break reloc_entries = parse_relocations(proc, moduleBaseAddress, pe, rva+rlc_size, rlc.VirtualAddress, rlc.SizeOfBlock-rlc_size ) relocations.append( pefile.BaseRelocationData( struct = rlc, entries = reloc_entries)) if not rlc.SizeOfBlock: break rva += rlc.SizeOfBlock return relocations except Exception as ex: print(str(ex))
def _clone_exports(tgt, ref, ref_path, new_section_name='.rdata2'): # Forwards don't typically supply the extension ref_path = ref_path.replace('.dll', '') ref = copy.deepcopy(ref) tgt = copy.deepcopy(tgt) tgt_export_dir = tgt.OPTIONAL_HEADER.DATA_DIRECTORY[0] ref_export_dir = ref.OPTIONAL_HEADER.DATA_DIRECTORY[0] if not ref_export_dir.Size: raise Exception('Reference binary has no exports') exp_names = [ ref_path.encode() + b'.' + e.name if e.name else ref_path.encode() + b'.#' + str(e.ordinal).encode() for e in sorted(ref.DIRECTORY_ENTRY_EXPORT.symbols, key=lambda x: x.ordinal) ] exp_names_blob = b'\x00'.join(exp_names) + b'\x00' new_section_size = ref_export_dir.Size + len(exp_names_blob) tgt, section = add_section(tgt, new_section_name, new_section_size) final_rva = section.VirtualAddress # Capture the reference export directory export_dir = ref.__unpack_data__( pefile.PE.__IMAGE_EXPORT_DIRECTORY_format__, ref.get_data( ref_export_dir.VirtualAddress, pefile.Structure( pefile.PE.__IMAGE_EXPORT_DIRECTORY_format__).sizeof()), file_offset=0 # we don't need this ) # Calculate our delta delta = final_rva - ref_export_dir.VirtualAddress # Apply RVA delta to export names for i in range(export_dir.NumberOfNames): ref.set_dword_at_rva( export_dir.AddressOfNames + 4 * i, ref.get_dword_at_rva(export_dir.AddressOfNames + 4 * i) + delta) # Link function addresses to forward names forward_offset = ref_export_dir.VirtualAddress + ref_export_dir.Size + delta true_offset = 0 for i in range(export_dir.NumberOfFunctions): if not ref.get_dword_at_rva(export_dir.AddressOfFunctions + 4 * i): continue # This function is hollow (never used) forward_name = exp_names[true_offset] ref.set_dword_at_rva(export_dir.AddressOfFunctions + 4 * i, forward_offset) forward_offset += len(forward_name) + 1 # +1 for null byte true_offset += 1 # Apply RVA delta to directory export_dir.AddressOfFunctions += delta export_dir.AddressOfNames += delta export_dir.AddressOfNameOrdinals += delta # Write in our new export directory tgt.set_bytes_at_rva( final_rva, ref.get_data(ref_export_dir.VirtualAddress, ref_export_dir.Size) + exp_names_blob) tgt.set_bytes_at_rva(final_rva, export_dir.__pack__()) # Rebuild from bytes to save back tgt = pefile.PE(data=tgt.__data__) # Update directory specs tgt_export_dir = tgt.OPTIONAL_HEADER.DATA_DIRECTORY[0] tgt_export_dir.VirtualAddress = section.VirtualAddress tgt_export_dir.Size = new_section_size tgt = pefile.PE(data=tgt.write()) return tgt
def init_export_section(self, name, exports): ''' Initialize and add the export table to the PE ''' exports_size = self.get_exports_size(name, exports) dest_exp_sect = self.get_section_by_name(self.basepe, '.edata') dest_exp_sect.Misc_VirtualSize = exports_size dest_exp_sect.Misc_PhysicalAddress = 0 dest_exp_sect.VirtualAddress = self.get_current_offset() dest_exp_sect.SizeOfRawData = exports_size dest_exp_sect.PointerToRawData = self.get_current_offset() self.basepe.OPTIONAL_HEADER.SizeOfInitializedData += exports_size export_dir = self.basepe.OPTIONAL_HEADER.DATA_DIRECTORY[0] export_dir.VirtualAddress = dest_exp_sect.VirtualAddress export_dir.Size = exports_size offset = self.get_current_offset() self.append_data(b'\x00' * exports_size) dest_export_dir = self.basepe.__unpack_data__( self.basepe.__IMAGE_EXPORT_DIRECTORY_format__, # noqa pefile.Structure( self.basepe.__IMAGE_EXPORT_DIRECTORY_format__).sizeof() * b'\x00', # noqa offset) offset += pefile.Structure( self.basepe.__IMAGE_EXPORT_DIRECTORY_format__).sizeof() dest_export_dir.Characteristics = 0 dest_export_dir.TimeDateStamp = 0xD1234567 dest_export_dir.MajorVersion = 0 dest_export_dir.MinorVersion = 0 dest_export_dir.Base = 1 dest_export_dir.NumberOfFunctions = len(exports) dest_export_dir.NumberOfNames = len(exports) # Set the address of functions array num_funcs = dest_export_dir.NumberOfFunctions funcs_offset = offset names_offset = funcs_offset + (4 * num_funcs) ord_offset = names_offset + (4 * num_funcs) strings_offset = ord_offset + (2 * num_funcs) dest_export_dir.Name = strings_offset dest_export_dir.AddressOfFunctions = offset dest_export_dir.AddressOfNames = names_offset dest_export_dir.AddressOfNameOrdinals = ord_offset # Set the export name self.basepe.set_bytes_at_offset(strings_offset, name) strings_offset += len(name) + 1 ep = self.basepe.OPTIONAL_HEADER.AddressOfEntryPoint for i, exp in enumerate(exports): exp = exp.encode('utf-8') # Add fluff to pass forwarded export checks self.append_data(b'\x00' * len(exports)) # Add the function addresses self.basepe.set_dword_at_offset(funcs_offset, ep) funcs_offset += 4 if funcs_offset > self.get_current_offset(): raise Exception('Functions offset exceeds total PE size') # Add the ordinals self.basepe.set_word_at_offset(ord_offset, (i + 1) - dest_export_dir.Base) ord_offset += 2 if ord_offset > self.get_current_offset(): raise Exception('Ordinals offset exceeds total PE size') # Add the function names in if strings_offset > self.get_current_offset(): raise Exception('Export string offset exceeds total PE size') self.basepe.set_dword_at_offset(names_offset, strings_offset) names_offset += 4 self.basepe.set_bytes_at_offset(strings_offset, exp) strings_offset += len(exp) + 1 ep += self.pattern_size if strings_offset: self.basepe.__data__ = self.basepe.__data__[:strings_offset] self.update()
def __parse__(self, file_name, nr=0): print "__parser__", "begin" xmldoc = minidom.parse(file_name) cofffile = xmldoc.getElementsByTagName("cofffile")[nr] # Image File Header image_file_header = cofffile.getElementsByTagName("image_file_header")[0] self.image_file_header = pefile.Structure(pefile.PE.__IMAGE_FILE_HEADER_format__) self.image_file_header.__unpacked_data_elms__ = (0, 0, 0, 0, 0, 0, 0) self.image_file_header.Machine = self.__parse_machine_type__(image_file_header.attributes['Machine'].value) self.image_file_header.NumberOfSections = int(image_file_header.attributes['NumberOfSections'].value, 0) self.image_file_header.TimeDateStamp = int(image_file_header.attributes['TimeDateStamp'].value, 0) self.image_file_header.PointerToSymbolTable = int(image_file_header.attributes['PointerToSymbolTable'].value, 0) self.image_file_header.NumberOfSymbols = int(image_file_header.attributes['NumberOfSymbols'].value, 0) self.image_file_header.SizeOfOptionalHeader = int(image_file_header.attributes['SizeOfOptionalHeader'].value, 0) self.image_file_header.Characteristics = int(image_file_header.attributes['Characteristics'].value, 0) # Image Section Header image_section_headers = cofffile.getElementsByTagName("image_section_header") for image_section_header in image_section_headers: new_image_section_header = pefile.Structure(pefile.PE.__IMAGE_SECTION_HEADER_format__) new_image_section_header.__unpacked_data_elms__ = ('', 0, 0, 0, 0, 0, 0, 0, 0, 0) new_image_section_header.Name = str(image_section_header.attributes['Name'].value) new_image_section_header.Misc = int(image_section_header.attributes['Misc'].value, 0) new_image_section_header.Misc_PhysicalAddress = int(image_section_header.attributes['Misc_PhysicalAddress'].value, 0) new_image_section_header.Misc_VirtualSize = int(image_section_header.attributes['Misc_VirtualSize'].value, 0) new_image_section_header.VirtualAddress = int(image_section_header.attributes['VirtualAddress'].value, 0) new_image_section_header.SizeOfRawData = int(image_section_header.attributes['SizeOfRawData'].value, 0) new_image_section_header.PointerToRawData = int(image_section_header.attributes['PointerToRawData'].value, 0) new_image_section_header.PointerToRelocations = int(image_section_header.attributes['PointerToRelocations'].value, 0) new_image_section_header.PointerToLinenumbers = int(image_section_header.attributes['PointerToLinenumbers'].value, 0) new_image_section_header.NumberOfRelocations = int(image_section_header.attributes['NumberOfRelocations'].value, 0) new_image_section_header.NumberOfLinenumbers = int(image_section_header.attributes['NumberOfLinenumbers'].value, 0) new_image_section_header.Characteristics = int(image_section_header.attributes['Characteristics'].value, 0) self.image_section_headers.append(new_image_section_header) # Image sections image_sections = cofffile.getElementsByTagName("image_section") for image_section in image_sections: if(image_section.attributes['Type'].value.upper() == "FILE"): with open(image_section.attributes['Filename'].value, "rb") as f: section_body = f.read() self.image_sections.append(section_body) # Image Relocation image_relocations = cofffile.getElementsByTagName("image_relocation") for image_relocation in image_relocations: new_image_relocation = pefile.Structure(self.__IMAGE_RELOCATION_format__) new_image_relocation.__unpacked_data_elms__ = (0, 0, 0) new_image_relocation.RVA = int(image_relocation.attributes['RVA'].value, 0) new_image_relocation.SymbolTableIndex = int(image_relocation.attributes['SymbolTableIndex'].value, 0) new_image_relocation.Type = int(image_relocation.attributes['Type'].value, 0) self.image_relocations.append(new_image_relocation) # Image Symbol Table image_symbol_table = cofffile.getElementsByTagName("image_symbol_table_item") for image_symbol_table_item in image_symbol_table: new_image_symbol_table_item = pefile.Structure(self.__IMAGE_SYMBOL_TABLE_format__) new_image_symbol_table_item.__unpacked_data_elms__ = ('', 0, 0, 0, 0, 0) new_image_symbol_table_item.Name = str(image_symbol_table_item.attributes['Name'].value) new_image_symbol_table_item.Value = int(image_symbol_table_item.attributes['Value'].value, 0) new_image_symbol_table_item.SectionNumber = int(image_symbol_table_item.attributes['SectionNumber'].value, 0) new_image_symbol_table_item.Type = int(image_symbol_table_item.attributes['Type'].value, 0) new_image_symbol_table_item.StorageClass = chr(int(image_symbol_table_item.attributes['StorageClass'].value, 0)) new_image_symbol_table_item.NumberOfAuxSymbols = chr(int(image_symbol_table_item.attributes['NumberOfAuxSymbols'].value, 0)) self.image_symbol_table.append(new_image_symbol_table_item) # Image Symbol String Table - in the future #image_symbol_string_table = cofffile.getElementsByTagName("image_symbol_string_table") self.image_symbol_string_table = pefile.Structure(pefile.PE.__StringTable_format__) self.image_symbol_string_table.__unpacked_data_elms__ = (0, 0, 0) self.image_symbol_string_table.Length = 0 self.image_symbol_string_table.ValueLength = 0 self.image_symbol_string_table.Type = 0 print "__parser__", "end"