diff --git a/iat.py b/iat.py index 570855d..36f47c5 100644 --- a/iat.py +++ b/iat.py @@ -1,56 +1,73 @@ import json + import lief -lief.disable_leak_warning() # warnings to disable for the callback + +lief.disable_leak_warning() # warnings to disable for the callback + + +dump_path = "rsc/wave-0001.dump" +# dump_path = "rsc/wave-0002.dump" +iat_json_path = "rsc/upx-hostname.exe.bin_iat_wave1.json" +# iat_json_path = "rsc/000155f2e0360f6ff6cd.exe_iat_wave2.json" + # Retrives all unique DLL names being imported -def get_used_dlls(calls: list[dict[str,str]]) -> set[str]: +def get_used_dlls(calls: list[dict[str, str]]) -> set[str]: res = set() for call in calls: - res.add(call["name"].split('!')[0]) + res.add(call["name"].split("!")[0]) return res + # Retrieves all unique function names used for a single DLL name -def get_used_functions_from_dll(dllname,calls): +def get_used_functions_from_dll(dllname, calls): res = set() - for [dll,func] in map(lambda x: x["name"].split('!'),calls): + for [dll, func] in map(lambda x: x["name"].split("!"), calls): if dll == dllname: res.add(func) return res - -def patch_call_to_new_IAT_entry(pe: lief.PE.Binary, call: dict[str,str], rva: int): + + +def patch_call_to_new_IAT_entry(pe: lief.PE.Binary, call: dict[str, str], rva: int): base = pe.imagebase - instruction_offset = int(call["adress"],16)-base + instruction_offset = int(call["adress"], 16) - base # We can manually patch the instruction here: FF 15 08 10 00 01 represents `call [0x01001080]` - adress_size = 4 if pe.abstract.header.is_32 else 8 is_little_endian = pe.abstract.header.endianness == lief.Header.ENDIANNESS.LITTLE - new_value = [0x00]*adress_size - hex_adress = hex(rva + pe.imagebase)[::-1][:-2] # reversing order and stripping zero - for i in range(0,adress_size): - byte_str = hex_adress[i*2:(i+1)*2][::-1] - new_value[i] += int(byte_str,16) - if(not is_little_endian): - new_value = new_value[::-1] # reverse byte order for big endian - pe.patch_address(instruction_offset, [0xFF,0x15] + new_value, lief.Binary.VA_TYPES.RVA) - + new_value = [0x00] * adress_size + hex_adress = hex(rva + pe.imagebase)[::-1][ + :-2 + ] # reversing order and stripping zero + for i in range(0, adress_size): + byte_str = hex_adress[i * 2 : (i + 1) * 2][::-1] + new_value[i] += int(byte_str, 16) + if not is_little_endian: + new_value = new_value[::-1] # reverse byte order for big endian + pe.patch_address( + instruction_offset, [0xFF, 0x15] + new_value, lief.Binary.VA_TYPES.RVA + ) -def patch_calls_to_new_IAT(pe: lief.PE.Binary, imp: lief.PE.Import, entry:lief.PE.ImportEntry, rva: int): + +def patch_calls_to_new_IAT( + pe: lief.PE.Binary, imp: lief.PE.Import, entry: lief.PE.ImportEntry, rva: int +): # print(f"{imp.name}!{entry.name}: 0x{rva:010x}") - for call in filter(lambda x : x["name"] == f"{imp.name.upper()}!{entry.name}" ,calls): - patch_call_to_new_IAT_entry(pe,call,rva) - - + for call in filter( + lambda x: x["name"] == f"{imp.name.upper()}!{entry.name}", calls + ): + patch_call_to_new_IAT_entry(pe, call, rva) + # wave dump file to patch -with open("rsc/wave-0001.dump", "rb") as f: +with open(dump_path, "rb") as f: pe = lief.parse(f) assert isinstance(pe, lief.PE.Binary) # JSON generated with the python reader files -with open("rsc/upx-hostname.exe.bin_iat_wave1.json", "r") as iat_json_input: +with open(iat_json_path, "r") as iat_json_input: iat_data = json.load(iat_json_input) -calls:list[dict[str,str]] = iat_data["calls"] -wave_entry = int(iat_data["entry"],16) +calls: list[dict[str, str]] = iat_data["calls"] +wave_entry = int(iat_data["entry"], 16) # Define all sections as writeable, to help with some weird stuff we're seeing for section in pe.sections: @@ -58,7 +75,7 @@ for section in pe.sections: section.characteristics_lists.append(lief.PE.Section.CHARACTERISTICS.MEM_EXECUTE) # patch entrypoint -entrypoint_format = int(hex(wave_entry)[-4:],16) +entrypoint_format = int(hex(wave_entry)[-4:], 16) pe.optional_header.addressof_entrypoint = entrypoint_format # remove all current imports @@ -68,14 +85,16 @@ pe.optional_header.addressof_entrypoint = entrypoint_format for dll in get_used_dlls(calls): imported_dll = pe.add_import(dll.lower()) # recreate all function calls related to that dll import - for func in get_used_functions_from_dll(dll,calls): + for func in get_used_functions_from_dll(dll, calls): imported_dll.add_entry(func) - + # At this point, the new IAT will only be constructed when the PE is written. We therefore need to make a callback function to patch calls afterwards. # write result config = lief.PE.Builder.config_t() -config.imports = True # allows the config of the writer to write a new IAT -config.resolved_iat_cbk = patch_calls_to_new_IAT # callback after the IAT has been written +config.imports = True # allows the config of the writer to write a new IAT +config.resolved_iat_cbk = ( + patch_calls_to_new_IAT # callback after the IAT has been written +) pe.write("patched.exe", config) -print("Wrote the patched executable as patched.exe") \ No newline at end of file +print("Wrote the patched executable as patched.exe") diff --git a/rsc/000155f2e0360f6ff6cd.exe_iat_wave2.json b/rsc/000155f2e0360f6ff6cd.exe_iat_wave2.json new file mode 100644 index 0000000..8a1c93e --- /dev/null +++ b/rsc/000155f2e0360f6ff6cd.exe_iat_wave2.json @@ -0,0 +1 @@ +{"entry": "0x40835b", "calls": [{"adress": "0x408269", "name": "KERNEL32.DLL!GetVersion"}, {"adress": "0x40c329", "name": "KERNEL32.DLL!HeapCreate"}, {"adress": "0x40d1fd", "name": "NTDLL.DLL!RtlAllocateHeap"}, {"adress": "0x40b00c", "name": "NTDLL.DLL!RtlInitializeCriticalSection"}, {"adress": "0x40b014", "name": "NTDLL.DLL!RtlInitializeCriticalSection"}, {"adress": "0x40b01c", "name": "NTDLL.DLL!RtlInitializeCriticalSection"}, {"adress": "0x40b024", "name": "NTDLL.DLL!RtlInitializeCriticalSection"}, {"adress": "0x40adc2", "name": "KERNEL32.DLL!TlsAlloc"}, {"adress": "0x40d8e9", "name": "NTDLL.DLL!RtlAllocateHeap"}, {"adress": "0x40d903", "name": "KERNEL32.DLL!VirtualAlloc"}, {"adress": "0x40d98f", "name": "KERNEL32.DLL!VirtualAlloc"}, {"adress": "0x40b102", "name": "NTDLL.DLL!RtlLeaveCriticalSection"}, {"adress": "0x40adea", "name": "KERNEL32.DLL!TlsSetValue"}, {"adress": "0x40adfb", "name": "KERNEL32.DLL!GetCurrentThreadId"}, {"adress": "0x4082c0", "name": "KERNEL32.DLL!GetCommandLineA"}, {"adress": "0x40c201", "name": "KERNEL32.DLL!GetEnvironmentStringsW"}, {"adress": "0x40c279", "name": "KERNEL32.DLL!WideCharToMultiByte"}, {"adress": "0x408cc1", "name": "NTDLL.DLL!RtlAllocateHeap"}, {"adress": "0x40c29b", "name": "KERNEL32.DLL!WideCharToMultiByte"}, {"adress": "0x40c2b4", "name": "KERNEL32.DLL!FreeEnvironmentStringsW"}, {"adress": "0x40bd2e", "name": "KERNEL32.DLL!GetStartupInfoA"}, {"adress": "0x40be4a", "name": "KERNEL32.DLL!GetFileType"}, {"adress": "0x40be3c", "name": "KERNEL32.DLL!GetStdHandle"}, {"adress": "0x40be81", "name": "KERNEL32.DLL!SetHandleCount"}, {"adress": "0x40b0d1", "name": "NTDLL.DLL!RtlInitializeCriticalSection"}, {"adress": "0x40b0ec", "name": "NTDLL.DLL!RtlEnterCriticalSection"}, {"adress": "0x409ef9", "name": "KERNEL32.DLL!GetACP"}, {"adress": "0x409d6e", "name": "KERNEL32.DLL!GetCPInfo"}, {"adress": "0x409f84", "name": "KERNEL32.DLL!GetCPInfo"}, {"adress": "0x40d067", "name": "KERNEL32.DLL!GetStringTypeW"}, {"adress": "0x40d0ed", "name": "KERNEL32.DLL!MultiByteToWideChar"}, {"adress": "0x40d143", "name": "KERNEL32.DLL!MultiByteToWideChar"}, {"adress": "0x40d155", "name": "KERNEL32.DLL!GetStringTypeW"}, {"adress": "0x40b9ed", "name": "KERNEL32.DLL!LCMapStringW"}, {"adress": "0x40ba8a", "name": "KERNEL32.DLL!MultiByteToWideChar"}, {"adress": "0x40bae2", "name": "KERNEL32.DLL!MultiByteToWideChar"}, {"adress": "0x40baf8", "name": "KERNEL32.DLL!LCMapStringW"}, {"adress": "0x40bb93", "name": "KERNEL32.DLL!LCMapStringW"}, {"adress": "0x40bbb8", "name": "KERNEL32.DLL!WideCharToMultiByte"}, {"adress": "0x40bfbc", "name": "KERNEL32.DLL!GetModuleFileNameA"}, {"adress": "0x408d0a", "name": "KERNEL32.DLL!HeapFree"}, {"adress": "0x40b3d1", "name": "KERNEL32.DLL!GetModuleHandleA"}, {"adress": "0x40b3e1", "name": "KERNEL32.DLL!GetProcAddress"}, {"adress": "0x40b3ed", "name": "KERNEL32.DLL!IsProcessorFeaturePresent"}, {"adress": "0x40de75", "name": "NTDLL.DLL!RtlAllocateHeap"}, {"adress": "0x40d1bc", "name": "KERNEL32.DLL!SetUnhandledExceptionFilter"}, {"adress": "0x406e40", "name": "NTDLL.DLL!RtlInitializeCriticalSection"}, {"adress": "0x417c47", "name": "NTDLL.DLL!RtlInitializeCriticalSection"}, {"adress": "0x418173", "name": "USER32.DLL!GetCursorPos"}, {"adress": "0x4183eb", "name": "KERNEL32.DLL!TlsAlloc"}, {"adress": "0x418401", "name": "NTDLL.DLL!RtlInitializeCriticalSection"}, {"adress": "0x418471", "name": "NTDLL.DLL!RtlEnterCriticalSection"}, {"adress": "0x4184c6", "name": "KERNEL32.DLL!GlobalAlloc"}, {"adress": "0x41851d", "name": "KERNEL32.DLL!GlobalLock"}, {"adress": "0x418566", "name": "NTDLL.DLL!RtlLeaveCriticalSection"}, {"adress": "0x41839e", "name": "KERNEL32.DLL!LocalAlloc"}, {"adress": "0x4185dc", "name": "KERNEL32.DLL!TlsGetValue"}, {"adress": "0x41862b", "name": "NTDLL.DLL!RtlEnterCriticalSection"}, {"adress": "0x41863e", "name": "NTDLL.DLL!RtlLeaveCriticalSection"}, {"adress": "0x418654", "name": "KERNEL32.DLL!LocalAlloc"}, {"adress": "0x4186a2", "name": "KERNEL32.DLL!TlsSetValue"}, {"adress": "0x418f2b", "name": "KERNEL32.DLL!GetVersion"}, {"adress": "0x418f50", "name": "NTDLL.DLL!RtlInitializeCriticalSection"}, {"adress": "0x418fe6", "name": "NTDLL.DLL!RtlEnterCriticalSection"}, {"adress": "0x418ff8", "name": "NTDLL.DLL!RtlInitializeCriticalSection"}, {"adress": "0x419001", "name": "NTDLL.DLL!RtlLeaveCriticalSection"}, {"adress": "0x419033", "name": "NTDLL.DLL!RtlLeaveCriticalSection"}, {"adress": "0x418666", "name": "KERNEL32.DLL!LocalReAlloc"}, {"adress": "0x417e13", "name": "KERNEL32.DLL!GetCurrentThread"}, {"adress": "0x417e1c", "name": "KERNEL32.DLL!GetCurrentThreadId"}, {"adress": "0x418849", "name": "KERNEL32.DLL!TlsGetValue"}, {"adress": "0x413cce", "name": "USER32.DLL!RegisterClipboardFormatA"}, {"adress": "0x4194a6", "name": "KERNEL32.DLL!GetVersion"}, {"adress": "0x4194e3", "name": "KERNEL32.DLL!GetProcessVersion"}, {"adress": "0x416321", "name": "USER32.DLL!GetSystemMetrics"}, {"adress": "0x416328", "name": "USER32.DLL!GetSystemMetrics"}, {"adress": "0x419461", "name": "USER32.DLL!GetSystemMetrics"}, {"adress": "0x41946b", "name": "USER32.DLL!GetSystemMetrics"}, {"adress": "0x416341", "name": "USER32.DLL!GetDC"}, {"adress": "0x416352", "name": "GDI32.DLL!GetDeviceCaps"}, {"adress": "0x41635a", "name": "GDI32.DLL!GetDeviceCaps"}, {"adress": "0x416362", "name": "USER32.DLL!ReleaseDC"}, {"adress": "0x4162dc", "name": "USER32.DLL!GetSysColor"}, {"adress": "0x4162e3", "name": "USER32.DLL!GetSysColor"}, {"adress": "0x4162ea", "name": "USER32.DLL!GetSysColor"}, {"adress": "0x4162f1", "name": "USER32.DLL!GetSysColor"}, {"adress": "0x4162f8", "name": "USER32.DLL!GetSysColor"}, {"adress": "0x416305", "name": "USER32.DLL!GetSysColorBrush"}, {"adress": "0x41630c", "name": "USER32.DLL!GetSysColorBrush"}, {"adress": "0x419511", "name": "USER32.DLL!LoadCursorA"}, {"adress": "0x41951c", "name": "USER32.DLL!LoadCursorA"}, {"adress": "0x41960b", "name": "KERNEL32.DLL!GetOEMCP"}, {"adress": "0x419612", "name": "KERNEL32.DLL!GetCPInfo"}, {"adress": "0x418d4b", "name": "KERNEL32.DLL!SetErrorMode"}, {"adress": "0x418d52", "name": "KERNEL32.DLL!SetErrorMode"}, {"adress": "0x418dd6", "name": "KERNEL32.DLL!GetModuleFileNameA"}, {"adress": "0x418f0b", "name": "KERNEL32.DLL!lstrcpyn"}, {"adress": "0x413b53", "name": "USER32.DLL!LoadStringA"}, {"adress": "0x418e77", "name": "KERNEL32.DLL!lstrcpy"}, {"adress": "0x418ea4", "name": "KERNEL32.DLL!lstrcat"}, {"adress": "0x419013", "name": "NTDLL.DLL!RtlEnterCriticalSection"}, {"adress": "0x410d4c", "name": "WS2_32.DLL!WSAStartup"}, {"adress": "0x4186df", "name": "NTDLL.DLL!RtlEnterCriticalSection"}, {"adress": "0x41870d", "name": "NTDLL.DLL!RtlLeaveCriticalSection"}, {"adress": "0x4083cf", "name": "NTDLL.DLL!ntdll_Offset_39930"}, {"adress": "0x4187b9", "name": "NTDLL.DLL!RtlEnterCriticalSection"}, {"adress": "0x4183c0", "name": "KERNEL32.DLL!LocalFree"}, {"adress": "0x418775", "name": "NTDLL.DLL!RtlEnterCriticalSection"}, {"adress": "0x418785", "name": "NTDLL.DLL!RtlLeaveCriticalSection"}, {"adress": "0x41878e", "name": "KERNEL32.DLL!LocalFree"}, {"adress": "0x4187a4", "name": "KERNEL32.DLL!TlsSetValue"}, {"adress": "0x4187ff", "name": "NTDLL.DLL!RtlLeaveCriticalSection"}, {"adress": "0x418f83", "name": "NTDLL.DLL!RtlDeleteCriticalSection"}, {"adress": "0x418f95", "name": "NTDLL.DLL!RtlDeleteCriticalSection"}, {"adress": "0x418417", "name": "KERNEL32.DLL!TlsFree"}, {"adress": "0x41843f", "name": "KERNEL32.DLL!GlobalHandle"}, {"adress": "0x418448", "name": "KERNEL32.DLL!GlobalUnlock"}, {"adress": "0x41844f", "name": "KERNEL32.DLL!GlobalFree"}, {"adress": "0x418459", "name": "NTDLL.DLL!RtlDeleteCriticalSection"}, {"adress": "0x406e68", "name": "NTDLL.DLL!RtlEnterCriticalSection"}, {"adress": "0x406e7f", "name": "NTDLL.DLL!RtlLeaveCriticalSection"}, {"adress": "0x406e58", "name": "NTDLL.DLL!RtlDeleteCriticalSection"}, {"adress": "0x417ca8", "name": "NTDLL.DLL!RtlDeleteCriticalSection"}, {"adress": "0x40d1ce", "name": "KERNEL32.DLL!SetUnhandledExceptionFilter"}, {"adress": "0x40b05c", "name": "NTDLL.DLL!RtlDeleteCriticalSection"}, {"adress": "0x40b077", "name": "NTDLL.DLL!RtlDeleteCriticalSection"}, {"adress": "0x40b07f", "name": "NTDLL.DLL!RtlDeleteCriticalSection"}, {"adress": "0x40b087", "name": "NTDLL.DLL!RtlDeleteCriticalSection"}, {"adress": "0x40b08f", "name": "NTDLL.DLL!RtlDeleteCriticalSection"}, {"adress": "0x40ae20", "name": "KERNEL32.DLL!TlsFree"}, {"adress": "0x40c382", "name": "KERNEL32.DLL!VirtualFree"}, {"adress": "0x40c38d", "name": "KERNEL32.DLL!VirtualFree"}, {"adress": "0x40c39a", "name": "KERNEL32.DLL!HeapFree"}, {"adress": "0x40c3b8", "name": "KERNEL32.DLL!HeapFree"}, {"adress": "0x40c3c0", "name": "KERNEL32.DLL!HeapDestroy"}]} \ No newline at end of file diff --git a/rsc/wave-0002.dump b/rsc/wave-0002.dump new file mode 100644 index 0000000..02d5480 Binary files /dev/null and b/rsc/wave-0002.dump differ