Files
OpenFUT/fifa17-recon/tools/scan_mt.py
T
funman300 0701ac94e1 tool(fifa17-recon): live native-RE toolkit (disasm, xref, immediate-store, vtable)
Read-only probes for resolving FIFA17 code paths against a running client
without Ghidra, per the live-disassembly method (/proc/<pid>/mem + objdump).
All open /proc/<pid>/mem 'rb' only.

  ldis.py           image-VA disassembler/hexdump for CardsDLL and FIFA17.exe;
                    recomputes the module base from the NAMED PE-header mapping
                    every run, because Wine maps PE sections anonymously and the
                    mapping that merely CONTAINS an address is not the module.
  xref.py           references to an image VA: call/jmp rel32, rip-relative lea,
                    and absolute pointer slots. An absolute-only hit means the
                    function is virtual and reachable solely via its vtable.
  immstore.py       immediate stores (C7 /0) of a constant to a struct offset.
                    Only an immediate store can INTRODUCE a constant; a register
                    store merely propagates one. Zero hits is a real result: it
                    proves the constant arrives from a call, not a literal.
  classify_calls.py splits call sites of a constant-returning stub into STORE
                    (can assign) vs compare (predicate). Turned 81 call sites of
                    the 130000 provider into 17 assignments.
  vtab.py           dumps a vtable as image VAs and looks for sibling vtables
                    holding a different function in the same slot, which is how
                    a type/mode dispatch shows up.
  scan_mt.py        match-team records by the invariant header (11,7,0,0,76).
                    Never filters on +0x18: that word is a per-session handle
                    (-1 on 2026-08-24, 0x54001/0x54000 on 2026-08-25) and
                    filtering on it previously produced a false negative.

Workflow note: dump .text once and cache the objdump output, then query the
cached listing; a full CardsDLL .text linear disassembly is ~563k lines and
re-disassembling per question is wasteful.
2026-08-25 04:23:22 +00:00

68 lines
2.2 KiB
Python
Executable File

#!/usr/bin/env python3
"""Scan for FIFA17 match-team records by the invariant header prefix.
Anchors ONLY on (11,7,0,0,76) at +0x00..+0x10. Never filter on +0x18: it is a
per-record marker whose value varies between sessions (-1 on 2026-08-24,
344065/344064 on 2026-08-25), and filtering on it produced a false negative.
scan_mt.py [pid]
"""
import glob
import os
import re
import struct
import sys
PAT = struct.pack("<5i", 11, 7, 0, 0, 76)
def find_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
return None
pid = int(sys.argv[1]) if len(sys.argv) > 1 else find_pid()
if not pid:
print(" no FIFA17.exe")
raise SystemExit(2)
mem = open(f"/proc/{pid}/mem", "rb", 0)
found = []
for line in open(f"/proc/{pid}/maps"):
m = re.match(r"([0-9a-f]+)-([0-9a-f]+)\s+(\S{4})\s+\S+\s+\S+\s+\S+\s*(.*)", line)
if not m or m.group(3)[0] != "r":
continue
lo, hi, path = int(m.group(1), 16), int(m.group(2), 16), m.group(4)
if path.startswith(("/dev", "/memfd")) or hi - lo > 512 * 1024 * 1024:
continue
try:
mem.seek(lo)
buf = mem.read(hi - lo)
except (OSError, ValueError, OverflowError):
continue
i = buf.find(PAT)
while i >= 0:
rec = buf[i:i + 0x80]
if len(rec) >= 0x80:
tid = struct.unpack_from("<i", rec, 0x14)[0]
m18 = struct.unpack_from("<i", rec, 0x18)[0]
m1c = struct.unpack_from("<i", rec, 0x1c)[0]
xi = list(struct.unpack_from("<11i", rec, 0x20))
subs = list(struct.unpack_from("<12i", rec, 0x4c))
found.append((lo + i, tid, m18, m1c, xi, subs))
i = buf.find(PAT, i + 4)
print(f" pid={pid} {len(found)} match-team record(s)")
for addr, tid, m18, m1c, xi, subs in found:
print(f"\n @0x{addr:x}")
print(f" +0x14 teamId = {tid}")
print(f" +0x18 marker = {m18} +0x1c marker = {m1c}")
print(f" XI = {xi}")
print(f" subs = {subs}")
print(f"\n distinct teamIds: {sorted({t for _a, t, *_r in found})}")