#!/usr/bin/env python3 """Read-only census of FIFA 17's RESIDENT club-item vector. Chain, every link from CardsDLL static RE: [CardsDLL+0x2e6398] -> owner object (FUN_18011a830) owner->vtable[0x4e8] -> getter returning mgr (call *0x4e8(%rdx)) mgr+0x108 .. mgr+0x110 -> club-item vector, stride 24 element+0x10 -> the item record pointer (FUN_1800d73d0) record+0x4c cardtype (derived from cardsubtypeid by FUN_1800d8330: 9/10/11 -> 7) record+0x50 cardsubtypeid record+0x5c itemState (101 activeHomeKit, 102 activeAwayKit) record+0x60 category (clone driver FUN_1801c3480 requires 4) record+0x94 teamid record+0xba teamkittypetechid (u16) Offsets not in that list are labelled UNVERIFIED and only dumped raw. No writes. Ever. """ import re, struct, sys, collections PID = int(sys.argv[1]) if len(sys.argv) > 1 else 44405 mem = open(f"/proc/{PID}/mem", "rb", buffering=0) def rd(a, n): mem.seek(a); return mem.read(n) def q(a): return struct.unpack(" 48 8b 81 off32 c3 or 48 8b 41 off8 c3 b = rd(getter, 12) mgr = None if b[0:3] == bytes.fromhex("488d81"): off = struct.unpack_from(" mgr = {mgr:#x}") elif b[0:3] == bytes.fromhex("488d41"): off = b[3]; mgr = owner + off print(f" getter returns owner+{off:#x} (EMBEDDED subobject) -> mgr = {mgr:#x}") elif b[0:3] == bytes.fromhex("488b81"): off = struct.unpack_from(" mgr = {mgr:#x}") elif b[0:3] == bytes.fromhex("488b41"): off = b[3]; mgr = q(owner + off) print(f" getter returns [owner+{off:#x}] -> mgr = {mgr:#x}") elif b[0:2] == bytes.fromhex("488b") and b[2] == 0xc1: mgr = owner; print(" getter returns owner itself") else: print(" getter shape unrecognised; trying owner as mgr") mgr = owner for label, mgr_try in (("resolved", mgr), ("owner", owner)): try: beg, end = q(mgr_try + 0x108), q(mgr_try + 0x110) except OSError: print(f" [{label}] +0x108/0x110 unreadable"); continue if not (0 < beg <= end) or (end - beg) % 24 or (end - beg) > 24*100000: print(f" [{label}] vector implausible: {beg:#x}..{end:#x}") continue n = (end - beg) // 24 print(f"\n === club-item vector via {label}: {beg:#x}..{end:#x} {n} slot(s) ===") hist = collections.Counter(); rows = [] for k in range(n): try: rec = q(beg + k*24 + 0x10) except OSError: continue if not rec: hist[("", None)] += 1; continue try: r = rd(rec, 0xC0) except OSError: continue if len(r) < 0xC0: continue ct, sub, st, cat = i32(r,0x4c), i32(r,0x50), i32(r,0x5c), i32(r,0x60) team = i32(r,0x94); kt = struct.unpack_from("14} {'ctype':>5} {'subtype':>7} {'state':>5} {'cat':>4} {'team':>5} {'kittype':>7}") for rec, ct, sub, st, cat, team, kt in rows[:12]: print(f" {rec:#14x} {ct:>5} {sub:>7} {st:>5} {cat:>4} {team:>5} {kt:>7}") break