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

71 lines
2.9 KiB
Python

"""DIMENSION 3 SEASONS q4.
ESTABLISHED: SeasonList deser 0x1801683f0 clears+repopulates the model season-list
vector (model vtable +0x898). FUN_180057330 reads that vector; empty -> NOSEASONS.
NOW: (a) confirm +0x898 getter returns this+0x5c68 and +0x588 getter -> this+0x7138;
(b) find WHO ISSUES the GET /season (SEASONLIST) RPC and its callers -- is the
request reachable, or is it never issued; (c) find every writer of the count short
at this+0x7138+0x96/+0x98 via a disp32 scan (form-independent).
CONTROL for disp32 scan: also scan for a KNOWN-written model offset (0x1fd2e, the
trading gate byte, known to have exactly one writer FUN_18011dc50) -> must find >=1
hit, else the scan form is broken.
"""
import traceback, struct
try:
MODEL_VT = 0x18021c2a0
print("### model vtable getters ###")
for slot in (0x588, 0x898, 0x850):
t = qword(MODEL_VT + slot)
print("slot +%#x -> %#x %s" % (slot, t, fname(t)))
print(dec(t)[:600])
print("-" * 40)
def disp32_scan(off, label, blocks=(".text",)):
le = struct.pack("<i", off)
hits = find_all(le, blocks=blocks)
print("DISP32", label, hex(off), "->", len(hits), "hits")
for h in hits:
f = fm.getFunctionContaining(addr(h))
print(" ", hex(h), f.getName() if f else "?")
return hits
print("\n### disp32 scans (form-independent) ###")
disp32_scan(0x1fd2e, "CONTROL trading gate byte")
disp32_scan(0x5c68, "season list vector base")
disp32_scan(0x7138, "season sub-struct base")
# the +0x96 / +0x98 short lives INSIDE the +0x7138 struct; its writers deref a
# pointer to that struct then +0x96. Hard to disp32-scan directly; instead show
# readers/writers of the +0x7138 getter result are the callers of slot +0x588.
# SEASONLIST RPC: descriptor row 69, stride 0x30, base 0x1802caa28
print("\n### RPC descriptor row 69 (SEASONLIST) ###")
base = 0x1802caa28
row = base + 69 * 0x30
print("row addr", hex(row), "bytes:", read_bytes(row, 0x30).hex())
# first qword often a name ptr, look for a char* to 'season'
for o in range(0, 0x30, 8):
v = qword(row + o)
s = ""
if 0x180000000 <= v < 0x181000000:
try:
s = rd_str(v, 40)
except Exception:
s = ""
print(" +%#x %#x %r" % (o, v, s))
# find the 'ut/%s/season' or 'season' URL template and its xref (the issuer)
print("\n### 'season' url template search ###")
for lit in (b"ut/%s/season\x00", b"/season\x00", b"season\x00"):
hits = find_all(lit, blocks=(".rdata",))
print(" ", lit, "->", [hex(h) for h in hits][:8])
for h in hits[:4]:
for x in xrefs_to(h):
print(" xref", hex(x[0]), x[2], hex(x[3]))
sys.stdout.flush()
os._exit(0)
except Exception:
traceback.print_exc()
sys.stdout.flush()
os._exit(0)