#!/usr/bin/env python3 """Dump a CardsDLL vtable as image VAs, and find sibling vtables that hold a different function in the same slot (a type/mode dispatch). vtab.py [before] [after] """ import glob import os import re import struct import sys CARDS_IMG = 0x180000000 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("no FIFA17.exe") P = pid() BASE = [int(l.split("-")[0], 16) for l in open(f"/proc/{P}/maps") if "CardsDLL" in l][0] def img2live(va): return BASE + (va - CARDS_IMG) def live2img(la): return CARDS_IMG + (la - BASE) slot = int(sys.argv[1], 16) before = int(sys.argv[2]) if len(sys.argv) > 2 else 10 after = int(sys.argv[3]) if len(sys.argv) > 3 else 10 mem = open(f"/proc/{P}/mem", "rb", 0) start = slot - before * 8 mem.seek(img2live(start)) buf = mem.read((before + after) * 8) print(f" vtable neighbourhood of image 0x{slot:x}") target = None for k in range(0, len(buf) - 7, 8): a = start + k p = struct.unpack_from(" " + (f"image 0x{ivа:x}" if ivа else f"raw 0x{p:x}") + mark) # Find every other .rdata slot pointing at a DIFFERENT function but whose # neighbours overlap this vtable -> sibling implementations of the same slot. print("\n === sibling vtables: same neighbour, different slot function ===") mem.seek(img2live(0x1801e5000)) rdata = mem.read(0x28a000 - 0x1e5000) # take the two neighbours around the slot as a signature sig_prev = struct.unpack_from("= 0: if i % 8 == 0: here = 0x1801e5000 + i # the slot in THIS vtable at the same relative position off = i + (8 if name == "preceding" else -8) if 0 <= off <= len(rdata) - 8: fn = struct.unpack_from(" image 0x{fimg:x} DIFFERENT") found += 1 i = rdata.find(pat, i + 1) print(f" {found} sibling implementation(s)")