Files
OpenFUT/fifa17-recon/tools/ghidra_queries/q_md_sbc_9.py
T
funman300 8cba70dc90 fifa17-recon: reconcile authoritative tools with running backend (B)
- Add 8 files present in docker/fifa17-python/tools but missing from the
  top-level tree: fut_accounts.py + 7 test_*.py contracts (all committed in
  the server's docker tree; byte-identical to the running image).
- Preserve newer responder work already matching the running container:
  utas_server.py (offlineSeason), lsx_responder_v2.py (OPENFUT_BIND),
  blaze_responder_v3b.py, autopatch.py, pow_server.py, fut_store.py,
  test_fut_contract.py, fifa17-hook-m1.sh.
- Add 30 newer ghidra_queries (draft purchase/state, SBC 9-26, runtime
  registries). Local tree is now a strict superset of B with all shared
  files byte-identical.
2026-08-10 17:08:06 -07:00

62 lines
2.3 KiB
Python

"""Continue the SBC response handoff analysis after the 2026-08-07 passive trace.
Proven live boundary:
request +0x80 factory -> response 0x18022e5b0
response +0x08 -> 0x18017b2b0 returns true
request +0x90 -> parsed response callback returns normally
request +0x88 -> ownership transfer returns normally
The next unknown is the receiving owner's virtual +0x18 consumer called by
0x1801631e0. Recover the concrete receiver, its vtable, and downstream publication.
"""
import traceback
try:
def dump_function(a, label):
f = func(a)
print("\n=== %s @%#x (%s) ===" % (label, a, f.getName() if f else "?"))
if f:
print("entry=%s body=%s" % (f.getEntryPoint(), f.getBody()))
print(dec(a))
def dump_instructions(a, before=0, count=80):
f = func(a)
print("\n=== instructions around %#x ===" % a)
if not f:
return
rows = []
for ad in f.getBody().getAddresses(True):
ins = listing.getInstructionAt(ad)
if ins:
rows.append(ins)
pivot = next((i for i, ins in enumerate(rows)
if int(ins.getAddress().getOffset()) >= a), 0)
for ins in rows[max(0, pivot-before):pivot+count]:
print(" %s %s" % (ins.getAddress(), ins))
dump_function(0x1801631e0, "post-request ownership handoff / owner consumer")
dump_instructions(0x1801631e0, count=120)
print("\n=== callers/xrefs of 0x1801631e0 ===")
for ent, name in callers(0x1801631e0):
print(" caller %#x %s" % (ent, name))
print(dec(ent))
for frm, typ, name, ent in xrefs_to(0x1801631e0):
print(" xref from=%#x type=%s fn=%s entry=%#x" %
(frm, typ, name, ent))
request_vtable = 0x18022e5c0
print("\n=== category request vtable %#x ===" % request_vtable)
for off, target, name in vtable(request_vtable, 40):
print(" +%#04x -> %#x %s" % (off, target, name))
for slot, label in ((0x80, "typed factory"),
(0x88, "ownership transfer"),
(0x90, "completion callback")):
target = qword(request_vtable + slot)
dump_function(target, "request %s slot +%#x" % (label, slot))
dump_instructions(target, count=100)
except Exception:
traceback.print_exc()