|
| 1 | +from dataclasses import dataclass |
| 2 | +from memmod import Process, Module |
| 3 | +from capstone import Cs, CS_ARCH_X86, CS_MODE_64, CsInsn |
| 4 | + |
| 5 | +import cxxfilt |
| 6 | +import sys |
| 7 | + |
| 8 | +proc = Process(name=sys.argv[1]) |
| 9 | +base = proc.find_module(proc.name) |
| 10 | +base_proc = proc.find_module(proc.name, mode='r-xp') |
| 11 | +assert base != None, "Failed to load base module!" |
| 12 | +assert base_proc != None, "Failed to load base module!" |
| 13 | + |
| 14 | +symbols = base.get_symbols() |
| 15 | +symbols_f = list(filter(lambda x: x.entry['st_info']['type'] == 'STT_FUNC' and x.entry['st_value'] != 0, symbols)) |
| 16 | +symbols_f = list(reversed(sorted(symbols_f, key=lambda x: x.entry['st_value']))) |
| 17 | +symbols = list(filter(lambda x: x.entry['st_info']['type'] == 'STT_OBJECT', symbols)) |
| 18 | + |
| 19 | + |
| 20 | +binary = proc.read(base_proc.start, base_proc.size) |
| 21 | +md = Cs(CS_ARCH_X86, CS_MODE_64) |
| 22 | + |
| 23 | +func = {} |
| 24 | + |
| 25 | +def get_function_name(address) -> str: |
| 26 | + for f in symbols_f: |
| 27 | + if f.entry['st_value'] < address - base.start: |
| 28 | + return cxxfilt.demangle(f.name) |
| 29 | + return "" |
| 30 | + |
| 31 | + |
| 32 | +""" |
| 33 | +for instruction in md.disasm(binary, base_proc.start): |
| 34 | + if instruction.mnemonic != 'call': |
| 35 | + continue |
| 36 | + if '[' not in instruction.op_str: |
| 37 | + continue |
| 38 | + if 'rip' not in instruction.op_str: |
| 39 | + continue |
| 40 | + if '+' not in instruction.op_str: |
| 41 | + continue |
| 42 | +
|
| 43 | + offset = int(instruction.op_str[instruction.op_str.find('+')+1:instruction.op_str.find(']')], 16) |
| 44 | + rip = instruction.address+instruction.size |
| 45 | + got = rip + offset |
| 46 | +
|
| 47 | + address = int.from_bytes(proc.read(got, 8), sys.byteorder) |
| 48 | + if address not in func: |
| 49 | + mod = proc.find_module_with_address(address) |
| 50 | +
|
| 51 | + if mod == None: |
| 52 | + continue |
| 53 | +
|
| 54 | + func[address] = { |
| 55 | + "module": mod, |
| 56 | + "got": got, |
| 57 | + "address": address, |
| 58 | + "offset": address - mod.start, |
| 59 | + "calls": [ instruction.address ] |
| 60 | + } |
| 61 | + else: |
| 62 | + func[address]["calls"].append(instruction.address) |
| 63 | +
|
| 64 | +for f in func.values(): |
| 65 | + print(f["module"].path, '+', hex(f["offset"]), hex(f["address"]), len(f["calls"])) |
| 66 | +""" |
| 67 | + |
| 68 | + |
| 69 | +for instruction in md.disasm(binary, base_proc.start): |
| 70 | + if instruction.mnemonic != 'call': |
| 71 | + continue |
| 72 | + |
| 73 | + op_str = instruction.op_str |
| 74 | + if '[' in op_str: |
| 75 | + continue |
| 76 | + if '+' in op_str: |
| 77 | + continue |
| 78 | + if not op_str[0].isdigit(): |
| 79 | + continue |
| 80 | + |
| 81 | + address = int(op_str, 16) |
| 82 | + |
| 83 | + if not base_proc.contains_address(address): |
| 84 | + continue |
| 85 | + |
| 86 | + if address not in func: |
| 87 | + func[address] = { |
| 88 | + "address": address, |
| 89 | + "offset": address - base_proc.start, |
| 90 | + "calls": [ instruction.address ] |
| 91 | + } |
| 92 | + else: |
| 93 | + func[address]["calls"].append(instruction.address) |
| 94 | + |
| 95 | +for f in func.values(): |
| 96 | + print("%s+%x (%x) %d %s" % (base_proc.path, f["offset"], f["address"], len(f["calls"]), get_function_name(f["address"]))) |
| 97 | +print(len(func)) |
| 98 | + |
| 99 | +# /usr/bin/supertux2+1b4930 (5573d99e4930) 6 Player::set_on_ground(bool) |
0 commit comments