#!/usr/bin/env python3 """Find references to an image VA inside a live module's .text/.rdata/.data. xref.py [--exe] Reports: call rel32 (e8) / jmp rel32 (e9) -- direct callers lea rip-rel (48 8d 0x) -- address-taken absolute 8-byte pointer -- vtable / table slot Read-only. Section ranges are recomputed from /proc//maps every run. """ import glob import os import re import struct import sys CARDS_IMG = 0x180000000 EXE_IMG = 0x140000000 def pid(): for d in glob.glob("/proc/[0-9]*"): try: if open(os.path.join(d, "comm")).read().strip() == "FIFA17.exe": return int(os.path.basename(d)) except OSError: pass raise SystemExit("FIFA17.exe not running") P = pid() def module_base(needle): for l in open(f"/proc/{P}/maps"): if needle.lower() in l.lower(): return int(l.split("-")[0], 16) raise SystemExit(f"{needle} not mapped") def spans(base, limit=0x400000): """Contiguous mappings belonging to this module, as (live_lo, live_hi, perms).""" out = [] for l in open(f"/proc/{P}/maps"): m = re.match(r"([0-9a-f]+)-([0-9a-f]+)\s+(\S{4})\s+\S+\s+\S+\s+\S+\s*(.*)", l) if not m: continue lo, hi, perms, path = int(m.group(1), 16), int(m.group(2), 16), m.group(3), m.group(4) if lo == base: out.append((lo, hi, perms)) continue if out and lo == out[-1][1] and not path.strip(): out.append((lo, hi, perms)) elif out and lo > out[-1][1]: break return out def main(): a = [x for x in sys.argv[1:] if x != "--exe"] exe = "--exe" in sys.argv target = int(a[0], 16) img = EXE_IMG if exe else CARDS_IMG base = module_base("FIFA17.exe" if exe else "CardsDLL") tgt_live = base + (target - img) mem = open(f"/proc/{P}/mem", "rb", 0) print(f" pid={P} module_base=0x{base:x} target image 0x{target:x} live 0x{tgt_live:x}") hits = 0 for lo, hi, perms in spans(base): try: mem.seek(lo) buf = mem.read(hi - lo) except (OSError, ValueError): continue img_lo = img + (lo - base) # rel32 call/jmp for op, name in ((0xE8, "call"), (0xE9, "jmp ")): i = buf.find(bytes([op])) while i >= 0: if i + 5 <= len(buf): rel = struct.unpack_from("= 0: if i + 7 <= len(buf): modrm = buf[i + 2] if (modrm & 0xC7) == 0x05: rel = struct.unpack_from("= 0: if i % 8 == 0: print(f" abs ptr slot at image 0x{img_lo+i:x} [{perms}]") hits += 1 i = buf.find(pat, i + 1) print(f" {hits} reference(s)") main()