38 lines
1.7 KiB
Python
38 lines
1.7 KiB
Python
"""DIMENSION 4 q5: map model vtable slots +0x2b0..+0x320 to their accessor
|
|
displacements, so slot +0x2d0 (the offline-draft-specific gate in FUN_1800b2680)
|
|
and slot +0x320 (cVar9) can be measured live.
|
|
|
|
Model vtable static = 0x18021c2a0 (from ground truth / card doc). For each slot read
|
|
the target function's first bytes; if it is the accessor stub 0f b6 81 <disp32> c3
|
|
(movzx eax,byte [rcx+disp]; ret) decode disp.
|
|
|
|
Control: slot +0x270 must decode to disp 0x1fd2e (IS_TRADING), slot +0x2c8 to 0x1fd3d
|
|
(IS_DRAFT_MODE_ENABLED) -- both established in the card-subsystem doc.
|
|
"""
|
|
import traceback
|
|
try:
|
|
VT = 0x18021c2a0
|
|
names = {0x270:"IS_TRADING(+0x1fd2e)", 0x280:"IS_STORE", 0x2b0:"FRIENDLY_SEASON(+0x1fd3a)",
|
|
0x2b8:"TOURNAMENT_QUIT(+0x1fd3b)", 0x2c0:"PROCESSING(+0x1fd3c)",
|
|
0x2c8:"DRAFT_MODE(+0x1fd3d)", 0x2d0:"?offline-draft gate?",
|
|
0x2d8:"STORY_MODE_REWARD", 0x2e0:"packAnim(+0x1fd45)",
|
|
0x2f0:"RETURNING_USER", 0x320:"cVar9(FUN_1800b2680)"}
|
|
for slot in range(0x2a0, 0x330, 8):
|
|
tgt = qword(VT + slot)
|
|
b = read_bytes(tgt, 8)
|
|
disp = None
|
|
if b[:3] == b"\x0f\xb6\x81": # movzx eax, byte [rcx+disp32]
|
|
import struct
|
|
disp = struct.unpack("<i", b[3:7])[0]
|
|
note = names.get(slot, "")
|
|
print("slot +%#05x -> %#012x stub=%s disp=%s %s" %
|
|
(slot, tgt, b.hex(), hex(disp) if disp is not None else "(not a byte-accessor)", note))
|
|
if disp is None:
|
|
# decompile non-trivial accessors (offline draft gate / cVar9 may compute)
|
|
if slot in (0x2d0, 0x320):
|
|
print(" --- dec slot +%#x target ---" % slot)
|
|
print(dec(tgt))
|
|
except Exception:
|
|
traceback.print_exc()
|
|
print("QUERY_DONE")
|