Beispiel #1
0
    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
Beispiel #2
0
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
Beispiel #3
0
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
Beispiel #4
0
    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
Beispiel #5
0
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)
Beispiel #6
0
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
Beispiel #7
0
    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
Beispiel #8
0
    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
Beispiel #9
0
    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
Beispiel #10
0
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))
Beispiel #12
0
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))
Beispiel #13
0
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
Beispiel #14
0
    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()
Beispiel #15
0
    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"