Small factoring and formatting issues
This commit is contained in:
parent
8729f0d385
commit
786decd8cc
1 changed files with 52 additions and 33 deletions
43
iat.py
43
iat.py
|
|
@ -1,53 +1,70 @@
|
||||||
import json
|
import json
|
||||||
|
|
||||||
import lief
|
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
|
# 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()
|
res = set()
|
||||||
for call in calls:
|
for call in calls:
|
||||||
res.add(call["name"].split('!')[0])
|
res.add(call["name"].split("!")[0])
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
|
||||||
# Retrieves all unique function names used for a single DLL name
|
# 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()
|
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:
|
if dll == dllname:
|
||||||
res.add(func)
|
res.add(func)
|
||||||
return res
|
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
|
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]`
|
# 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
|
adress_size = 4 if pe.abstract.header.is_32 else 8
|
||||||
is_little_endian = pe.abstract.header.endianness == lief.Header.ENDIANNESS.LITTLE
|
is_little_endian = pe.abstract.header.endianness == lief.Header.ENDIANNESS.LITTLE
|
||||||
new_value = [0x00] * adress_size
|
new_value = [0x00] * adress_size
|
||||||
hex_adress = hex(rva + pe.imagebase)[::-1][:-2] # reversing order and stripping zero
|
hex_adress = hex(rva + pe.imagebase)[::-1][
|
||||||
|
:-2
|
||||||
|
] # reversing order and stripping zero
|
||||||
for i in range(0, adress_size):
|
for i in range(0, adress_size):
|
||||||
byte_str = hex_adress[i * 2 : (i + 1) * 2][::-1]
|
byte_str = hex_adress[i * 2 : (i + 1) * 2][::-1]
|
||||||
new_value[i] += int(byte_str, 16)
|
new_value[i] += int(byte_str, 16)
|
||||||
if(not is_little_endian):
|
if not is_little_endian:
|
||||||
new_value = new_value[::-1] # reverse byte order for big 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)
|
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}")
|
# print(f"{imp.name}!{entry.name}: 0x{rva:010x}")
|
||||||
for call in filter(lambda x : x["name"] == f"{imp.name.upper()}!{entry.name}" ,calls):
|
for call in filter(
|
||||||
|
lambda x: x["name"] == f"{imp.name.upper()}!{entry.name}", calls
|
||||||
|
):
|
||||||
patch_call_to_new_IAT_entry(pe, call, rva)
|
patch_call_to_new_IAT_entry(pe, call, rva)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# wave dump file to patch
|
# 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)
|
pe = lief.parse(f)
|
||||||
assert isinstance(pe, lief.PE.Binary)
|
assert isinstance(pe, lief.PE.Binary)
|
||||||
|
|
||||||
# JSON generated with the python reader files
|
# 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)
|
iat_data = json.load(iat_json_input)
|
||||||
calls: list[dict[str, str]] = iat_data["calls"]
|
calls: list[dict[str, str]] = iat_data["calls"]
|
||||||
wave_entry = int(iat_data["entry"], 16)
|
wave_entry = int(iat_data["entry"], 16)
|
||||||
|
|
@ -76,6 +93,8 @@ for dll in get_used_dlls(calls):
|
||||||
# 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 = patch_calls_to_new_IAT # callback after the IAT has been written
|
config.resolved_iat_cbk = (
|
||||||
|
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")
|
||||||
Loading…
Add table
Add a link
Reference in a new issue