"""D3 store-price q2. HYPOTHESES H5 Some function reads the 0x1a8 store-tile viewmodel's currency flags vm+0xb5 (has mtx) / vm+0xb6 (has coins) / vm+0xb7 (has points) and the formatted price string vm+0x168, and that function is the Scaleform push that supplies the "or %1s" argument. H6 DAT_1802de0d0 vtable slot +0x30 is the gate that disables the "points" currency branch in FUN_18002c3c0. METHOD / CONTROL. For H5 I scan EVERY function in .text and collect the set of scalar operands, then report functions whose scalar set contains the distinctive triple {0xb5,0xb6,0xb7}. The positive control is that FUN_18002c3c0 (known to write all three) MUST appear in the result; if it does not, the scan is broken and every negative is worthless. """ import traceback OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/store" try: w = open(OUT + "/q2_raw.txt", "w") def p(*a): s = " ".join(str(x) for x in a) print(s) w.write(s + "\n") # ---------- H5 whole-.text scalar-set scan ---------- want = {0xb5, 0xb6, 0xb7} hits = [] nfun = 0 it = fm.getFunctions(True) while it.hasNext(): f = it.next() nfun += 1 sc = set() ii = listing.getInstructions(f.getBody(), True) while ii.hasNext(): ins = ii.next() for i in range(ins.getNumOperands()): for o in ins.getOpObjects(i): try: sc.add(int(o.getValue()) & 0xFFFFFFFFFFFFFFFF) except Exception: pass if want <= sc: hits.append((int(f.getEntryPoint().getOffset()), f.getName(), 0x168 in sc, 0xa4 in sc, 0xa8 in sc, 0xa0 in sc, 0x6c in sc)) p("=" * 70) p("H5 scanned %d functions; %d contain the {0xb5,0xb6,0xb7} triple" % (nfun, len(hits))) p("CONTROL: FUN_18002c3c0 present? %s" % any(h[0] == 0x18002c3c0 for h in hits)) p("%-12s %-24s %-7s %-6s %-6s %-6s %-5s" % ("entry", "name", "has168", "hasa4", "hasa8", "hasa0", "has6c")) for h in hits: p("%-12x %-24s %-7s %-6s %-6s %-6s %-5s" % h) # ---------- H6 the points gate ---------- p("") p("=" * 70) p("H6 writers of DAT_1802de0d0") for a in (0x180013ed0, 0x180013f20): src = dec(a) p("") p("--- FUN_%x len=%d FULL" % (a, len(src))) p(src) p("") p("H6 the gate call site, FUN_18002c3c0 around 0x18002c77f") ii = listing.getInstructions(addr(0x18002c750), True) n = 0 while ii.hasNext() and n < 40: ins = ii.next() p(" %x %s" % (int(ins.getAddress().getOffset()), ins)) n += 1 # try to resolve the vtable of the gate object: find its ctor via the writer p("") p("H6 vtable candidates: qword at DAT_1802de0d0 in the static image = %#x" % qword(0x1802de0d0)) # ---------- extra: literal 0x1801f04f0 / 0x1801f04f8 used by FUN_18002e680 ---------- p("") p("=" * 70) p("entitlement-category literals used by FUN_18002e680") for a in (0x1801f04f0, 0x1801f04f8, 0x180228338, 0x1801eab80, 0x1802055ea): p(" %#x = %r" % (a, rd_str(a, 40))) # ---------- extra: CreatePack request serializer currency vocabulary ---------- p("") p("=" * 70) p("CreatePack request serializer FUN_180162530 (writes MTX / POINTS literals)") src = dec(0x180162530) p("len=%d FULL" % len(src)) p(src) w.close() except Exception: traceback.print_exc() try: w.write(traceback.format_exc()); w.close() except Exception: pass