"""Final batch. Q-A How many places consume each getter? FUN_1801a8620 = item+0x38 (wire discardValue, UI name DISCARD_CREDITS) FUN_1801a8090 = item+0x3c (client fcc_discardcoins result, UI name CALCULATED_DISCARD_CREDITS) If +0x3c has exactly ONE consumer and it is the UI property push, then no native code ever falls back from the wire value to the computed one, and which number the tile shows is a Flash-asset decision. That is H1. Q-B What is FUN_1800eb850 registered as? Its only xrefs are DATA slots at 0x180216130 / 0x1802658a0 / 0x1802f85ec, so it sits in a dispatch table. Dump the qwords either side and resolve any string pointers to name it. Q-C item+0x34 feeds the UI property "BOUGHT_FOR" and is NOT on the field map. Print the deserializer sites that write +0x194 (= 0x34 + 0x160, the frame form inside FUN_18013fe00) so the wire atom can be identified later. CONTROL: FUN_1801a8620 and FUN_1801a8090 are 8-byte leaf functions whose bodies were printed in q7, so their identity is not in doubt; the xref counts below are the only new claim. A getter with zero xrefs would mean the xref index is stale, which is checkable against FUN_1801a80c0 (CARD_LEVEL), known to be called from FUN_1800eb850. """ import traceback OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/cards/q8_out.txt" try: lines = [] def P(*a): lines.append(" ".join(str(x) for x in a)) P("=== Q-A getter consumers ===") for nm, a in (("+0x38 DISCARD_CREDITS getter FUN_1801a8620", 0x1801A8620), ("+0x3c CALCULATED getter FUN_1801a8090", 0x1801A8090), ("+0x54 CARD_LEVEL getter FUN_1801a80c0", 0x1801A80C0), ("+0x58 rare==1 getter FUN_1801a88c0", 0x1801A88C0), ("+0x58 rare==0xc getter FUN_1801a8880", 0x1801A8880)): xs = xrefs_to(a) P("%-44s %d xrefs" % (nm, len(xs))) for frm, typ, fn, ent in xs: P(" %#x %-12s %s @ %#x" % (frm, typ, fn, ent)) P("") P("=== Q-B dispatch-table context around the FUN_1800eb850 slots ===") for slot in (0x180216130, 0x1802658A0, 0x1802F85EC): P("-- slot %#x --" % slot) for off in range(-0x40, 0x48, 8): a = slot + off try: v = qword(a) except Exception: P(" %#x " % a) continue tag = "" f = fm.getFunctionAt(addr(v)) if 0x180000000 <= v < 0x181000000 else None if f: tag = "-> FUNC %s" % f.getName() elif 0x1801E5000 <= v <= 0x180290000: try: s = rd_str(v, 60) except Exception: s = "" if s and all(32 <= ord(c) < 127 for c in s): tag = "-> %r" % s P(" %#x %016x %s%s" % (a, v, tag, " <== the slot" if off == 0 else "")) P("") P("=== Q-C writes to the parsed item's +0x34 (frame form RBP+0x194) ===") f = func(0x18013FE00) lo = int(f.getBody().getMinAddress().getOffset()) hi = int(f.getBody().getMaxAddress().getOffset()) p = lo while p <= hi: ins = listing.getInstructionAt(addr(p)) if ins is None: p += 1 continue t = str(ins) if "0x194]" in t or "0x190]" in t or "0x198]" in t or "0x19c]" in t: P(" %#x %s" % (p, t)) p += ins.getLength() with open(OUT, "w") as fh: fh.write("\n".join(lines)) print("wrote %s (%d lines)" % (OUT, len(lines))) except Exception: traceback.print_exc()