Files
OpenFUT/fifa17-recon/tools/ghidra_queries/q_md_gates_4.py
T

78 lines
3.4 KiB
Python

"""DIMENSION 2 Q3/Q4 finish: draft-tile gating in FUN_1800b2680; SBC/Objectives
accessor slots and whether any native code reads them.
HYPOTHESIS: IS_DRAFT_MODE_ENABLED (cVar7) gates whether the draft hub tile is drawn
/ enabled. SBC(0x1fd2c,0x1fd42) and Objectives(0x1fd44) have accessor stubs at some
model vtable slots but NO IS_* publisher name; either a vtable-slot caller reads
them or they are consumed only by their own accessor (i.e. no native mode gate).
CONTROL: draft accessor is model slot 0x2c8 (proven). Walking the vtable and
matching disp must reproduce 0x2c8->0x1fd3d and 0x270->0x1fd2e.
"""
import traceback
try:
MODEL_VT = 0x18021c2a0
# find slots for the SBC/objectives displacements by walking vtable
want = {0x1fd2c: "allowUntradeableForSBC", 0x1fd42: "allowGracePeriodForSBC",
0x1fd44: "enableObjectives", 0x1fd28: "sbcGracePeriodMinutes",
0x1fd3e: "offlineDraft(0x2d0?)", 0x1fd2e: "trading(ctl)",
0x1fd3d: "draft(ctl)"}
slot_for_disp = {}
print("=" * 70)
print("vtable walk: slot -> accessor disp (0x200..0x340)")
print("=" * 70)
for slot in range(0x200, 0x340, 8):
tgt = qword(MODEL_VT + slot)
if not (0x180000000 <= tgt < 0x181000000):
continue
stub = read_bytes(tgt, 8)
disp = None
if stub[0:3] == b"\x0f\xb6\x81" and stub[7] == 0xc3:
disp = int.from_bytes(stub[3:7], "little")
elif stub[0:2] == b"\x8b\x81" and stub[6] == 0xc3:
disp = int.from_bytes(stub[2:6], "little")
if disp in want:
slot_for_disp[disp] = slot
print("slot +%#05x -> %#011x disp %#x %s"
% (slot, tgt, disp, want[disp]))
# scan slot-callers for the objectives + SBC slots
print()
print("=" * 70)
print("slot-call readers for SBC/Objectives accessor slots")
print("=" * 70)
call_modrm = [0x90, 0x91, 0x92, 0x93, 0x95, 0x96, 0x97]
for disp in (0x1fd44, 0x1fd2c, 0x1fd42):
slot = slot_for_disp.get(disp)
if slot is None:
print("\ndisp %#x: no vtable slot found in range" % disp)
continue
pat_disp = slot.to_bytes(4, "little")
found = []
for pre in ([], [0x41]):
for mrm in call_modrm:
pat = bytes(pre + [0xff, mrm]) + pat_disp
for h in find_all(pat, blocks=(".text",)):
f = fm.getFunctionContaining(addr(h))
found.append((h, f.getName() if f else "?",
int(f.getEntryPoint().getOffset()) if f else 0))
print("\ndisp %#x slot +%#05x %-24s (%d call-site(s))"
% (disp, slot, want[disp], len(found)))
for h, fn, ent in found:
print(" %#011x in %-16s (%#x)" % (h, fn, ent))
# rest of the draft hub-tile builder: how cVar7/8/9 gate the tile
print()
print("=" * 70)
print("FUN_1800b2680 draft/tile gating region (search cVar / DRAFT in decompile)")
print("=" * 70)
d = dec(0x1800b2680)
lines = d.splitlines()
for i, ln in enumerate(lines):
if any(k in ln for k in ("cVar7", "cVar8", "cVar9", "DRAFT", "0x70", "0x60",
"DESTINATION", "GOTO_", "SBC", "OBJECTIVE", "case 0xc",
"caseD_")):
print("%4d: %s" % (i, ln.strip()))
except Exception:
traceback.print_exc()