"""D5 Q1/Q4 recon: the store/transaction purchase fork. HYPOTHESIS: there are TWO distinct client server-calls that both POST to "/transaction" -- PurchasePack (expects FutCreatePackServerResponse) and PurchaseItems (expects FutPurchaseItemsServerResponse) -- and the fork is decided CLIENT-SIDE before the request is sent, by which ServerCall object is constructed, not by anything the server does. CONTROL: class_deser("FutSquadSaveServerResponse") must resolve to 0x180171a60 and class_deser("FutCreateMatchServerResponse") to 0x180120380. If the controls come back empty the whole run is untrustworthy. Outputs everything to /tmp/.../packres/d5_q1_*.txt with len() printed for every decompile, so no absence is ever concluded from a truncation. """ import traceback, os OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/packres" def w(name, text): p = os.path.join(OUT, name) with open(p, "w") as f: f.write(text) print("WROTE %s (%d bytes)" % (p, len(text))) try: buf = [] def P(*a): s = " ".join(str(x) for x in a) print(s) buf.append(s) # ---------- CONTROLS ---------- P("=== CONTROLS ===") for c, expect in (("FutSquadSaveServerResponse", 0x180171a60), ("FutCreateMatchServerResponse", 0x180120380), ("FutSquadListServerResponse", 0x180172140)): try: r = class_deser(c) except Exception as e: r = "ERR %s" % e P(" %-34s -> %s (expect %#x)" % (c, r, expect)) # ---------- string xrefs ---------- STRS = { 0x1802203e8: "/transaction", 0x18022fe80: "useCredits", 0x18022fea0: "usePreOrder", 0x18022fb78: "transaction", 0x18022fb88: "transactionId", 0x1802203c8: "User already has a transaction", 0x180220400: "PURCHASEERROR", 0x18021f2d8: "PURCHASEPACK", 0x18021f2e8: "PurchaseItems", 0x18021f2f8: "PURCHASEITEMS", 0x1801f4e48: "PurchasePack", 0x1801f4e78: "ValidateCoinPurchase", 0x1801f4e90: "ValidatePointsPurchase", 0x1801ff7c8: "PURCHASE_INSUFFICIENT_FUNDS", 0x1802293a8: "NOTRANSACTION", 0x1802293b8: "TRANSACTIONCREATED", 0x1802293d0: "PURCHASESTARTED", 0x1802293e0: "PURCHASECOMPLETE", 0x180229420: "TRANSACTIONCOMPLETE", 0x180229438: "TRANSACTIONCANCEL", 0x180231010: "extPrice", 0x180230b48: "currencies", 0x1802310f0: "finalPrice", 0x180231c78: "originalPrice", 0x1802310e0: "finalFunds", 0x180231110: "firstPartyStoreId", 0x1802321a0: "purchaseLimit", 0x180232160: "purchaseCount", 0x1801ec120: "OnTransactionFailure", 0x1801f0668: "OnServerTransactionIdResponse", 0x18022ed10: "FUT_STORE_POINTS_", 0x1801ff788: "PURCHASE_METHOD", } P("") P("=== STRING XREFS ===") funcs_of_interest = {} for va, nm in sorted(STRS.items()): try: xs = xrefs_to(va) except Exception as e: P(" %-32s %#x ERR %s" % (nm, va, e)); continue P(" %-32s %#x %d xrefs" % (nm, va, len(xs))) for frm, typ, fn, ent in xs: P(" from %#x %-14s in %s @ %#x" % (frm, typ, fn, ent)) if ent: funcs_of_interest.setdefault(ent, set()).add(nm) P("") P("=== FUNCS OF INTEREST (%d) ===" % len(funcs_of_interest)) for ent, names in sorted(funcs_of_interest.items()): P(" %#x %-40s <- %s" % (ent, fname(ent), ",".join(sorted(names)))) w("d5_q1_xrefs.txt", "\n".join(buf) + "\n") # ---------- decompiles ---------- TARGETS = { "purchaseitems_deser": 0x180126a04, "createpack_deser": 0x180162880, "packtypes_deser": 0x1801234e0, "pack_elem_deser": 0x18013af30, "extprice_finalprice": 0x180139070, "extprice_originalprice": 0x18013aae0, "currencies_deser": 0x180122c50, "packquantities_deser": 0x1801758c0, "updatecredits_deser": 0x1801738b2, } for tag, va in sorted(TARGETS.items()): try: f = func(va) src = dec(va) except Exception as e: src = "// ERR %s" % e f = None hdr = "// target %s va=%#x entry=%s name=%s len=%d\n" % ( tag, va, ("%#x" % int(f.getEntryPoint().getOffset())) if f else "None", f.getName() if f else "None", len(src)) w("d5_q1_dec_%s.txt" % tag, hdr + src) # decompile every func-of-interest, full text for ent, names in sorted(funcs_of_interest.items()): try: src = dec(ent) except Exception as e: src = "// ERR %s" % e hdr = "// entry %#x name=%s strings=%s len=%d\n" % ( ent, fname(ent), ",".join(sorted(names)), len(src)) w("d5_q1_fn_%x.txt" % ent, hdr + src) print("DONE") except Exception: traceback.print_exc()