Add tool to identify matching sead RTTI functions

This commit is contained in:
Léo Lam 2020-12-29 14:12:40 +01:00
parent 81b1ec96bb
commit 8b41b83228
No known key found for this signature in database
GPG Key ID: 0DF30F9081000741
2 changed files with 427 additions and 350 deletions

File diff suppressed because it is too large Load Diff

View File

@ -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()