Esempio n. 1
0
def restore_pe(file):
    from pefile import PE
    pe = PE(file,fast_load=True)
    # Helpers
    find_section = lambda name:next(filter(lambda x:name in x.Name,pe.sections))
    find_data_directory = lambda name:next(filter(lambda x:name in x.name,pe.OPTIONAL_HEADER.DATA_DIRECTORY))
    # Remove .enigma sections
    pe.__data__ = pe.__data__[:find_section(b'.enigma1').PointerToRawData]
    pe.FILE_HEADER.NumberOfSections -= 2
    # Restore rdata & idata sections
    find_data_directory('TLS').VirtualAddress = find_section(b'.rdata').VirtualAddress
    find_data_directory('ENTRY_IMPORT').VirtualAddress = find_section(b'.idata').VirtualAddress
    # Write to new file
    pe_name = os.path.basename(file)[:-4] + ORIGINAL_PE_SUFFIX
    pe_name = os.path.join(output,pe_name).replace('\\','/')
    pe.write(pe_name)
    print('[-] Original PE saved:',pe_name)
Esempio n. 2
0
def restore_pe(file,output):
    # PEfile isn't the best for this job, but we'll get it done ;)
    # TODO : Recaluclate SizeOfImage to match the acutal file
    from pefile import PE,OPTIONAL_HEADER_MAGIC_PE_PLUS
    print('[-] Loading PE...')
    pe = PE(file,fast_load=True)
    PE64 = pe.PE_TYPE == OPTIONAL_HEADER_MAGIC_PE_PLUS
    pe.__data__ = bytearray(pe.__data__) # This allows us to apply slicing on the PE data
    # Helpers    
    find_section = lambda name:next(filter(lambda x:name in x.Name,pe.sections))
    find_data_directory = lambda name:next(filter(lambda x:name in x.name,pe.OPTIONAL_HEADER.DATA_DIRECTORY))    
    # Data
    enigma1 = pe.__data__[find_section(b'.enigma1').PointerToRawData:]
    hdr = unpack(EVB_ENIGMA1_HEADER,enigma1,104 if PE64 else 76)
    # Restore section with built-in offsets. All these ADDRESSes are VAs
    find_data_directory('IMPORT').VirtualAddress = hdr['IMPORT_ADDRESS']
    find_data_directory('IMPORT').Size = hdr['IMPORT_SIZE']
    find_data_directory('RELOC').VirtualAddress = hdr['RELOC_ADDRESS']
    find_data_directory('RELOC').Size = hdr['RELOC_SIZE']
    print('[-] Rebuilding Exception directory...')
    # Rebuild the exception directory
    exception_dir = find_data_directory('EXCEPTION')    
    exception_raw_ptr = pe.get_offset_from_rva(exception_dir.VirtualAddress)
    exception_data = pe.__data__[exception_raw_ptr:exception_raw_ptr + exception_dir.Size]    
    exception_struct = PE64_EXCEPTION if PE64 else PE_EXCEPTION
    exception_end = 0
    for i in range(0,exception_dir.Size,get_size_by_struct(exception_struct)):
        block = unpack(exception_struct,exception_data[i:])
        block['section'] = pe.get_section_by_rva(block['BEGIN_ADDRESS'])
        exception_end = i
        if b'.enigma' in block['section'].Name: 
            break
    exception_data = exception_data[:exception_end]
    # Prepare partial TLS data for searching
    tls_dir = find_data_directory('TLS')    
    tls_raw_ptr = pe.get_offset_from_rva(tls_dir.VirtualAddress)
    tls_data = bytearray(pe.__data__[tls_raw_ptr:tls_raw_ptr + tls_dir.Size])    
    original_callback = hdr['TLS_CALLBACK_RVA'] + pe.OPTIONAL_HEADER.ImageBase
    original_callback = struct.pack('<' + ('Q' if PE64 else 'I'),original_callback)
    if (PE64): 
        tls_data += original_callback       # AddressOfCallBacks
    else:
        tls_data[12:16] = original_callback # AddressOfCallBacks
        tls_data = tls_data[:16]
    # Destory .enigma* sections
    pe.__data__ = pe.__data__[:find_section(b'.enigma1').PointerToRawData] + pe.__data__[find_section(b'.enigma2').PointerToRawData + find_section(b'.enigma2').SizeOfRawData:]
    # If original program has a overlay, this will perserve it. Otherwise it's okay to remove them anyway.
    assert pe.sections.pop().Name == b'.enigma2'
    assert pe.sections.pop().Name == b'.enigma1'
    pe.FILE_HEADER.NumberOfSections -= 2    
    # NOTE: .enigma1 contains the VFS, as well as some Optional PE Header info as descrbied above
    # NOTE: .enigma2 is a aplib compressed loader DLL. You can decompress it with aplib provided in this repo  
    if (exception_data):
        # Reassign the RVA & sizes    
        print('[-] Rebuilt Exception directory. Size=0x%x' % len(exception_data))
        # Find where this could be placed at...since EVB clears the original exception directory listings
        # PEs with overlays won't work at all if EVB packed them.
        # We must remove the sections and do NOT append anything new
        offset = 0
        for section in pe.sections:
            offset_ = pe.__data__.find(b'\x00' * len(exception_data),section.PointerToRawData, section.PointerToRawData + section.SizeOfRawData)
            if offset_ > 0: 
                # Check for references in the Optional Data Directory
                # The offset should not be referenced otherwise we would overwrite existing data
                for header in pe.OPTIONAL_HEADER.DATA_DIRECTORY:
                    if pe.get_rva_from_offset(offset_) in range(header.VirtualAddress,header.VirtualAddress+header.Size):                        
                        offset = 0
                        break
                    else:
                        offset = offset_                        
            if offset > 0:
                break
        assert offset > 0,"Cannot place Exceptions Directory!"
        section = pe.get_section_by_rva(pe.get_rva_from_offset(offset))
        print('[-] Found suitable section to place Exception Directory. Name=%s RVA=0x%x' % (section.Name.decode(),offset - section.PointerToRawData))
        pe.__data__[offset:offset+len(exception_data)] = exception_data
        section.SizeOfRawData = max(section.SizeOfRawData,len(exception_data))
        exception_dir.VirtualAddress = pe.get_rva_from_offset(offset)
        exception_dir.Size = len(exception_data)
    else:
        print('[-] Original program does not contain Exception Directory.')
        exception_dir.VirtualAddress = 0
        exception_dir.Size = 0
    offset = pe.__data__.find(tls_data)
    # Append the exception section and assign the pointers
    # Serach for TLS in memory map since it's not removed.
    tls_dir = find_data_directory('TLS')
    if (offset > 0):
        print('[-] TLS Directory found. Offset=0x%x' % offset)
        tls_dir.VirtualAddress = pe.get_rva_from_offset(offset)
        tls_dir.Size = 40 if PE64 else 24
    else:
        print('[-] Original program does not utilize TLS.')
        tls_dir.VirtualAddress = 0
        tls_dir.Size = 0
    # Write to new file
    pe_name = os.path.basename(file)[:-4] + ORIGINAL_PE_SUFFIX
    pe_name = os.path.join(output,pe_name).replace('\\','/')    
    new_file_data = pe.write()
    write_bytes(BytesIO(new_file_data),open(pe_name,'wb+'),len(new_file_data),desc='Saving PE')
    print('[-] Original PE saved:',pe_name)