71 lines
2.9 KiB
Python
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)
|