# -*- coding: utf-8 -*- """ q_pack_inv_3 -- DIMENSION 1 pass 3: the consumers and the route table. HYPOTHESES (a) .rdata around 0x18021e100 is a ROUTE TABLE (command -> "ut/%s/..." literal); dumping it enumerates every HTTP path CardsDLL can build, which answers Q3 exhaustively rather than by keyword luck. (b) 0x1802cb800.. is the matching COMMAND-NAME table (PurchasedItems, PurchasePack, StorePackTypes, StorePackQuantities were all found there). (c) The unopenedPacks total is pushed through model->vtbl[0x4e0]; the vtable can be reached from the singleton storage DAT_1802e6398, and the reader is another slot on the same vtable. (d) Functions flagged HOT for atoms 0x35e/0x24b/0x20c in pass 2 are further deserializers that touch pack inventory. CONTROLS * The route-table dump MUST contain "ut/%s/squad" and "ut/%s/item", two routes we already serve. If it does not, the table base is wrong. * class_deser("FutSquadSaveServerResponse") is re-run and must still be 0x180171a60 (guards against a stale/corrupt project). * Each decompile prints len() first. """ import struct import traceback OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/packres" try: got = sorted(set(x[0] for x in class_deser("FutSquadSaveServerResponse"))) print("CONTROL FutSquadSaveServerResponse -> %s %s" % ([hex(g) for g in got], "PASS" if 0x180171a60 in got else "FAIL")) print("\n########## ROUTE TABLE DUMP .rdata 0x18021df00..0x18021e300 ##########") for va in range(0x18021df00, 0x18021e300, 8): try: q = qword(va) except Exception: continue s = "" if 0x180001000 <= q <= 0x1802efc08: try: s = rd_str(q, 120) except Exception: s = "" if s and s.isprintable() and len(s) > 1: print(" %#x -> %#x %r" % (va, q, s)) print("CONTROL route table contains ut/%s/squad and ut/%s/item: see above") print("\n########## COMMAND-NAME TABLE .rdata/.data 0x1802cb600..0x1802cbb00 ##########") for va in range(0x1802cb600, 0x1802cbb00, 8): try: q = qword(va) except Exception: continue s = "" if 0x180001000 <= q <= 0x1802efc08: try: s = rd_str(q, 120) except Exception: s = "" if s and s.isprintable() and len(s) > 1: print(" %#x -> %#x %r" % (va, q, s)) print("\n########## SINGLETON STORAGE DAT_1802e6398 ##########") for (fr, ty, fn, en) in xrefs_to(0x1802e6398): print(" %#x %-10s %s @%#x" % (fr, ty, fn, en)) print("\n########## call [reg+0x4e0] SITES ##########") for modrm in (0x90, 0x91, 0x92, 0x93, 0x96, 0x97): pat = bytes([0xFF, modrm]) + struct.pack("