mirror of https://github.com/zeldaret/botw.git
Add tool to identify matching sead RTTI functions
This commit is contained in:
parent
81b1ec96bb
commit
8b41b83228
File diff suppressed because it is too large
Load Diff
|
|
@ -0,0 +1,77 @@
|
|||
#!/usr/bin/env python3
|
||||
import struct
|
||||
from typing import Dict, Set
|
||||
|
||||
import capstone as cs
|
||||
import cxxfilt
|
||||
from colorama import Fore
|
||||
|
||||
from util import utils, elf
|
||||
|
||||
|
||||
def main() -> None:
|
||||
new_matches: Dict[int, str] = dict()
|
||||
functions_by_addr: Dict[int, utils.FunctionInfo] = {fn.addr: fn for fn in utils.get_functions()}
|
||||
|
||||
md = cs.Cs(cs.CS_ARCH_ARM64, cs.CS_MODE_ARM)
|
||||
md.detail = True
|
||||
decomp_addr_to_symbol = elf.build_addr_to_symbol_table(elf.my_symtab)
|
||||
decomp_glob_data_table = elf.build_glob_data_table(elf.my_elf)
|
||||
|
||||
processed: Set[int] = set()
|
||||
for fn in functions_by_addr.values():
|
||||
if fn.status != utils.FunctionStatus.Matching:
|
||||
continue
|
||||
|
||||
if fn.size != 0x5C or (not fn.decomp_name.endswith("8getRuntimeTypeInfoEv") and not fn.name.endswith("rtti2")):
|
||||
continue
|
||||
|
||||
base_fn = elf.get_fn_from_base_elf(fn.addr, fn.size)
|
||||
try:
|
||||
my_fn = elf.get_fn_from_my_elf(fn.decomp_name)
|
||||
except KeyError:
|
||||
utils.warn(f"could not find function {fn.decomp_name}")
|
||||
continue
|
||||
|
||||
assert len(base_fn.data) == len(my_fn.data)
|
||||
|
||||
vtable_ptr1 = 0
|
||||
vtable_ptr2 = 0
|
||||
for j, (i1, i2) in enumerate(zip(md.disasm(base_fn.data, base_fn.addr), md.disasm(my_fn.data, my_fn.addr))):
|
||||
assert i1.mnemonic == i2.mnemonic
|
||||
if j == 10:
|
||||
assert i1.mnemonic == "adrp"
|
||||
assert i1.operands[0].reg == i2.operands[0].reg
|
||||
vtable_ptr1 = i1.operands[1].imm
|
||||
vtable_ptr2 = i2.operands[1].imm
|
||||
elif j == 11:
|
||||
assert i1.mnemonic == "ldr"
|
||||
assert i1.operands[0].reg == i2.operands[0].reg
|
||||
assert i1.operands[1].value.mem.base == i2.operands[1].value.mem.base
|
||||
vtable_ptr1 += i1.operands[1].value.mem.disp
|
||||
vtable_ptr2 += i2.operands[1].value.mem.disp
|
||||
break
|
||||
|
||||
assert vtable_ptr1 != 0 and vtable_ptr2 != 0
|
||||
if vtable_ptr1 in processed:
|
||||
continue
|
||||
processed.add(vtable_ptr1)
|
||||
ptr1, = struct.unpack("<Q", elf.read_from_elf(elf.base_elf, vtable_ptr1, 8))
|
||||
ptr2 = decomp_glob_data_table[vtable_ptr2]
|
||||
|
||||
vtable1 = elf.get_vtable_fns_from_base_elf(ptr1 + 0x10, num_entries=1)
|
||||
vtable2 = elf.unpack_vtable_fns(elf.read_from_elf(elf.my_elf, addr=ptr2 + 0x10, size=8), num_entries=1)
|
||||
|
||||
if functions_by_addr[vtable1[0]].status == utils.FunctionStatus.Matching:
|
||||
continue
|
||||
|
||||
name = decomp_addr_to_symbol[vtable2[0]]
|
||||
new_matches[vtable1[0]] = name
|
||||
utils.print_note(f"new match: {Fore.BLUE}{cxxfilt.demangle(name)}{Fore.RESET}")
|
||||
|
||||
# overwrite the original names because they are likely to be incorrect
|
||||
utils.add_decompiled_functions(new_matches, new_orig_names=new_matches)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Loading…
Reference in New Issue