Added patching of xrefs to addresses obtained with getprocaddr (the code
is not yet cleaned up)
This commit is contained in:
parent
b8f201cbab
commit
efc8da2ff8
2 changed files with 147 additions and 6 deletions
125
iat.py
125
iat.py
|
|
@ -4,6 +4,8 @@ import lief
|
||||||
|
|
||||||
lief.disable_leak_warning() # warnings to disable for the callback
|
lief.disable_leak_warning() # warnings to disable for the callback
|
||||||
|
|
||||||
|
with open("lib/WindowsDllsExport/win10-19043-exports.json", "rb") as f:
|
||||||
|
api_info = json.load(f)
|
||||||
|
|
||||||
dump_path = "rsc/wave-0001.dump"
|
dump_path = "rsc/wave-0001.dump"
|
||||||
# dump_path = "rsc/wave-0002.dump"
|
# dump_path = "rsc/wave-0002.dump"
|
||||||
|
|
@ -76,7 +78,64 @@ def patch_instr_to_new_IAT_entry(pe: lief.PE.Binary, call: dict[str, str], rva:
|
||||||
patch_direct_adress_jump(pe, rva, instruction_offset)
|
patch_direct_adress_jump(pe, rva, instruction_offset)
|
||||||
|
|
||||||
|
|
||||||
def patch_calls_to_new_IAT(
|
def patch_addr_found_in_mem(pe: lief.PE.Binary, rva: int, old_addr: str):
|
||||||
|
is_32 = pe.abstract.header.is_32
|
||||||
|
little_endian = pe.abstract.header.endianness == lief.Header.ENDIANNESS.LITTLE
|
||||||
|
# scan memory for reference to old addr
|
||||||
|
old_addr_mem_repr = hex_address_to_memory_representation(
|
||||||
|
old_addr,
|
||||||
|
is_32,
|
||||||
|
pe.abstract.header.endianness == lief.Header.ENDIANNESS.LITTLE,
|
||||||
|
)
|
||||||
|
new_addr = hex_address_to_memory_representation(
|
||||||
|
hex(rva + pe.imagebase),
|
||||||
|
is_32,
|
||||||
|
little_endian,
|
||||||
|
)
|
||||||
|
adresses_to_patch = []
|
||||||
|
for section in pe.sections:
|
||||||
|
for i in range(len(section.content)):
|
||||||
|
found = True
|
||||||
|
for j in range(len(old_addr_mem_repr)):
|
||||||
|
if (
|
||||||
|
i + j >= len(section.content)
|
||||||
|
or section.content[i + j] != old_addr_mem_repr[j]
|
||||||
|
):
|
||||||
|
found = False
|
||||||
|
break
|
||||||
|
if found:
|
||||||
|
old_addr_ref = hex_address_to_memory_representation(
|
||||||
|
hex(
|
||||||
|
section.virtual_address + i + pe.imagebase,
|
||||||
|
),
|
||||||
|
is_32,
|
||||||
|
little_endian,
|
||||||
|
)
|
||||||
|
# print(
|
||||||
|
# f"ref= {
|
||||||
|
# hex(
|
||||||
|
# section.virtual_address + i + pe.imagebase,
|
||||||
|
# )
|
||||||
|
# }"
|
||||||
|
# )
|
||||||
|
for section in pe.sections:
|
||||||
|
for k in range(len(section.content)):
|
||||||
|
foundxref = True
|
||||||
|
for l in range(len(old_addr_ref)):
|
||||||
|
if (
|
||||||
|
k + l < len(section.content)
|
||||||
|
and section.content[k + l] != old_addr_ref[l]
|
||||||
|
):
|
||||||
|
foundxref = False
|
||||||
|
break
|
||||||
|
if foundxref:
|
||||||
|
adresses_to_patch.append(section.virtual_address + k)
|
||||||
|
for addr in adresses_to_patch:
|
||||||
|
print(f"patched {hex(addr)}")
|
||||||
|
pe.patch_address(addr, new_addr, lief.Binary.VA_TYPES.RVA)
|
||||||
|
|
||||||
|
|
||||||
|
def patch_to_new_IAT(
|
||||||
pe: lief.PE.Binary, imp: lief.PE.Import, entry: lief.PE.ImportEntry, rva: int
|
pe: lief.PE.Binary, imp: lief.PE.Import, entry: lief.PE.ImportEntry, rva: int
|
||||||
):
|
):
|
||||||
# print(f"{imp.name}!{entry.name}: 0x{rva:010x}")
|
# print(f"{imp.name}!{entry.name}: 0x{rva:010x}")
|
||||||
|
|
@ -84,6 +143,44 @@ def patch_calls_to_new_IAT(
|
||||||
lambda x: x["name"] == f"{imp.name.upper()}!{entry.name}", calls
|
lambda x: x["name"] == f"{imp.name.upper()}!{entry.name}", calls
|
||||||
):
|
):
|
||||||
patch_instr_to_new_IAT_entry(pe, call, rva)
|
patch_instr_to_new_IAT_entry(pe, call, rva)
|
||||||
|
# patch additional non-call related info
|
||||||
|
print(entry.name)
|
||||||
|
for func in filter(
|
||||||
|
lambda x: x["name"] == entry.name and x["dll"] == imp.name, procaddr_list
|
||||||
|
):
|
||||||
|
# print(func["name"])
|
||||||
|
patch_addr_found_in_mem(pe, rva, func["addr"])
|
||||||
|
|
||||||
|
|
||||||
|
def get_list_of_procaddr_functions(prevwave_info):
|
||||||
|
res = []
|
||||||
|
for call in prevwave_info:
|
||||||
|
# first only including imported dlls
|
||||||
|
res_new = {}
|
||||||
|
for export in api_info:
|
||||||
|
if (
|
||||||
|
export["dllname"] in dll_calls_list
|
||||||
|
and export["exportname"] == call["function"]
|
||||||
|
):
|
||||||
|
res_new = {
|
||||||
|
"name": export["exportname"],
|
||||||
|
"dll": export["dllname"],
|
||||||
|
"addr": call["func_addr"],
|
||||||
|
}
|
||||||
|
break
|
||||||
|
if res_new == {}:
|
||||||
|
# try adding a new dll
|
||||||
|
for export in api_info:
|
||||||
|
if export["exportname"] == call["function"]:
|
||||||
|
res_new = {
|
||||||
|
"name": export["exportname"],
|
||||||
|
"dll": export["dllname"],
|
||||||
|
"addr": call["func_addr"],
|
||||||
|
}
|
||||||
|
break
|
||||||
|
if res_new != {}:
|
||||||
|
res.append(res_new)
|
||||||
|
return res
|
||||||
|
|
||||||
|
|
||||||
# wave dump file to patch
|
# wave dump file to patch
|
||||||
|
|
@ -150,13 +247,33 @@ pe.optional_header.addressof_entrypoint = entrypoint_format
|
||||||
# remove all current imports
|
# remove all current imports
|
||||||
pe.remove_all_imports()
|
pe.remove_all_imports()
|
||||||
|
|
||||||
# recreate all DLL imports
|
# recreate all DLL imports from calls detected
|
||||||
|
dll_calls_list = []
|
||||||
|
imported_dll_list = []
|
||||||
|
func_calls_list = []
|
||||||
for dll in get_used_dlls(calls):
|
for dll in get_used_dlls(calls):
|
||||||
|
dll_calls_list.append(dll.lower())
|
||||||
imported_dll = pe.add_import(dll.lower())
|
imported_dll = pe.add_import(dll.lower())
|
||||||
|
imported_dll_list.append(imported_dll)
|
||||||
# recreate all function calls related to that dll import
|
# 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):
|
||||||
|
func_calls_list.append(func)
|
||||||
imported_dll.add_entry(func)
|
imported_dll.add_entry(func)
|
||||||
|
|
||||||
|
# get list of functions called with getprocaddr
|
||||||
|
procaddr_list = get_list_of_procaddr_functions(iat_data["prevwave_getprocaddr"])
|
||||||
|
for func in procaddr_list:
|
||||||
|
if func["name"] in func_calls_list: # call already added
|
||||||
|
continue
|
||||||
|
if func["dll"] in dll_calls_list: # dll already added
|
||||||
|
imported_dll_list[dll_calls_list.index(func["dll"])].add_entry(func["name"])
|
||||||
|
else: # we need to import the new DLL
|
||||||
|
dll_calls_list.append(func["dll"])
|
||||||
|
imported_dll = pe.add_import(func["dll"])
|
||||||
|
imported_dll_list.append(imported_dll)
|
||||||
|
func_calls_list.append(func["name"])
|
||||||
|
imported_dll.add_entry(func["name"])
|
||||||
|
|
||||||
# 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.
|
# 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.
|
||||||
|
|
||||||
# Define all sections as writeable, to help with some weird stuff we're seeing
|
# Define all sections as writeable, to help with some weird stuff we're seeing
|
||||||
|
|
@ -171,8 +288,6 @@ for section in pe.sections:
|
||||||
# write result
|
# write result
|
||||||
config = lief.PE.Builder.config_t()
|
config = lief.PE.Builder.config_t()
|
||||||
config.imports = True # allows the config of the writer to write a new IAT
|
config.imports = True # allows the config of the writer to write a new IAT
|
||||||
config.resolved_iat_cbk = (
|
config.resolved_iat_cbk = patch_to_new_IAT # callback after the IAT has been written
|
||||||
patch_calls_to_new_IAT # callback after the IAT has been written
|
|
||||||
)
|
|
||||||
pe.write("patched.exe", config)
|
pe.write("patched.exe", config)
|
||||||
print("Wrote the patched executable as patched.exe")
|
print("Wrote the patched executable as patched.exe")
|
||||||
|
|
|
||||||
|
|
@ -24,5 +24,31 @@
|
||||||
"EBP": "0x000cff94 ",
|
"EBP": "0x000cff94 ",
|
||||||
"ESP": "0x000cff8c",
|
"ESP": "0x000cff8c",
|
||||||
"eflags": "0x00000203"
|
"eflags": "0x00000203"
|
||||||
}
|
},
|
||||||
|
"prevwave_getprocaddr": [
|
||||||
|
{ "function": "FormatMessageA", "func_addr": "0x75985fbd" },
|
||||||
|
{ "function": "LocalFree", "func_addr": "0x75962d3c" },
|
||||||
|
{ "function": "GetModuleHandleA", "func_addr": "0x75961245" },
|
||||||
|
{ "function": "GetLastError", "func_addr": "0x759611c0" },
|
||||||
|
{ "function": "__p__commode", "func_addr": "0x752c27c3" },
|
||||||
|
{ "function": "__p__fmode", "func_addr": "0x752c27ce" },
|
||||||
|
{ "function": "__set_app_type", "func_addr": "0x752c2804" },
|
||||||
|
{ "function": "_controlfp", "func_addr": "0x752be1e1" },
|
||||||
|
{ "function": "_cexit", "func_addr": "0x752c37d4" },
|
||||||
|
{ "function": "_adjust_fdiv", "func_addr": "0x753532ec" },
|
||||||
|
{ "function": "_except_handler3", "func_addr": "0x752dd770" },
|
||||||
|
{ "function": "_XcptFilter", "func_addr": "0x752ddc75" },
|
||||||
|
{ "function": "_exit", "func_addr": "0x7531b2c0" },
|
||||||
|
{ "function": "_c_exit", "func_addr": "0x7531b2db" },
|
||||||
|
{ "function": "__setusermatherr", "func_addr": "0x753477ad" },
|
||||||
|
{ "function": "_initterm", "func_addr": "0x752bc151" },
|
||||||
|
{ "function": "__getmainargs", "func_addr": "0x752c2bc0" },
|
||||||
|
{ "function": "__initenv", "func_addr": "0x753504e8" },
|
||||||
|
{ "function": "_write", "func_addr": "0x752c4078" },
|
||||||
|
{ "function": "strchr", "func_addr": "0x752bdbeb" },
|
||||||
|
{ "function": "puts", "func_addr": "0x75328d04" },
|
||||||
|
{ "function": "exit", "func_addr": "0x752c36aa" },
|
||||||
|
{ "function": "s_perror", "func_addr": "0x6c8a1be4" },
|
||||||
|
{ "function": "CharToOemBuffA", "func_addr": "0x76aeb1b0" }
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue