"""D3 run 7: the RPC descriptor row's handler, and the end of the pack-record trail. FOUND IN RUN 6: a descriptor table in .data at ~0x1802cb800 with 0x30-byte rows [display-name ptr, 0x1b, COMMAND-token ptr, 0, 0, function ptr] 0x1802cb860 "PurchaseItems" "PURCHASEITEMS" -> 0x180124240 0x1802cb890 "StorePackTypes" "STOREPACKTYPES" -> 0x180124810 0x1802cb8c0 "StorePackQuantities" "STOREPACKQUANTITIES" -> ? Also a factory table at 0x18021ddf8 holding 0x180123480. CardsDLL exports only PlugInitialize_ / PlugDeinitialize_ / entry, so everything the packed exe can see comes through interfaces those hand out. THIS RUN 1. Walk the descriptor table rows around 0x1802cb800 +/- 0x300 and print each row. 2. Decompile the StorePackTypes handler 0x180124810 and the CreatePack handler, then follow their callees/callers, looking for anything that touches the response object's vector at +0x28. 3. Same for the CreatePack response: who reads numberItems at obj+0x28 or the itemList vector at obj+0x30/0x38, i.e. what sizes the reveal. CONTROL: 0x180124810 must decompile to something that mentions the store response factory 0x180123480 or the vtable 0x18021dd68 or the path string "store"; if it looks unrelated the table row reading is wrong. """ import traceback, sys, os OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/packres/" os.makedirs(OUT, exist_ok=True) def dump(tag, va, path, echo=True): src = dec(va) hdr = "%s %#x fname=%s len(src)=%d (FULL, NOT TRUNCATED)" % ( tag, va, fname(va), len(src)) if echo: print("=" * 78) print(hdr) print("=" * 78) print(src) with open(path, "w") as fh: fh.write("// " + hdr + "\n" + src) return src def sstr(q): if 0x1801e5000 <= q < 0x1802e0000: try: s = rd_str(q, 64) if s and all(32 <= ord(c) < 127 for c in s): return s except Exception: pass return None try: print("### 1. DESCRIPTOR TABLE WALK") base = 0x1802cb500 for row in range(0, 0x600, 0x30): a = base + row try: qs = [qword(a + i * 8) for i in range(6)] except Exception: continue n0, n2 = sstr(qs[0]), sstr(qs[2]) if not (n0 and n2): continue fn = qs[5] print(" %#x %-24s %-24s flags=%#x fn=%#x %s" % (a, n0, n2, qs[1], fn, fname(fn) if fn else "")) print("\n### 2. HANDLERS") seen = set() for va, tag in ((0x180124810, "StorePackTypes handler"), (0x180124240, "PurchaseItems handler")): dump(tag, va, OUT + "d3_h_%x.txt" % va, echo=True) print(" callees:") for a, n in callees(va): print(" %#x %s" % (a, n)) print(" callers:") for a, n in callers(va): print(" %#x %s" % (a, n)) seen.add(va) print("\n### 3. WHO ELSE MENTIONS THE STORE FACTORY / VTABLE / FACTORY TABLE SLOT") for tgt in (0x18021ddf8, 0x18021dd68, 0x180123480, 0x1801234e0, 0x180123030): print(" xrefs to %#x:" % tgt) for frm, typ, fn, ent in xrefs_to(tgt): print(" %#x %s %s" % (frm, typ, fn)) print("\n### 4. CREATEPACK RESPONSE CONSUMERS") dump("FutCreatePack ctor", 0x180162420, OUT + "d3_cp_ctor.txt", echo=True) print(" callers of ctor: %s" % [(hex(a), n) for a, n in callers(0x180162420)]) dump("FutCreatePack factory 0x180162770", 0x180162770, OUT + "d3_cp_factory.txt", echo=True) print(" callers of factory: %s" % [(hex(a), n) for a, n in callers(0x180162770)]) for tgt in (0x180162770, 0x180162880, 0x180228260): pat = tgt.to_bytes(8, "little") for h in find_all(pat, blocks=(".rdata", ".data")): print(" %#x embedded at %#x" % (tgt, h)) except Exception: traceback.print_exc() sys.stdout.flush()