# -*- coding: utf-8 -*- """ADVERSARIAL VERIFY 3: the reveal brain, the tier table, the headline predicate, the sort, the NUM_*_IN_PACK provider, and the playerType ABSENCE claim. H1 FUN_1800aa440 ranks on item+0x38 with fallback item+0x3c, gates on cardtype==1, fires 0x33 / 0x34, and issues NO network request. ATTACK on the "no network request" ABSENCE: instead of grepping the decompile text, I enumerate EVERY call target in the function FROM THE DISASSEMBLY and print its name, then check them against the known URL-builder / request machinery. H2 FUN_1800a9fe0(rareflag, rating) -> 1/2/3 with the quoted thresholds. H3 FUN_1800aa330 = (loans < 1) && (rating > 0x57 || playerid in fcc_GrandStandPlayers) H4 FUN_1800a96a0 is a stable descending sort keyed on tuple[0] H5 FUN_180015d80 reads NUM_*_IN_PACK from packdef +0xc0..+0xd0 H6 ABSENCE: atom 0x23d playerType has no arm in 0x18013fe00. ATTACK with a DIFFERENT METHOD than grepping the decompile: I reconstruct the atom ladder from the DISASSEMBLY of 0x18013fe00 by walking every SUB/CMP/DEC immediate on the dispatch register and accumulating the running sum, then report the full set of atom ids the ladder can reach. CONTROL: 0x23f playStyle, 0xd7 discardValue, 0x6c cardsubtypeid, 0x274 rating and 0x271 rareflag must all appear. """ import traceback, re OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/packres" def dump(n, s): p = "%s/v_%s.txt" % (OUT, n) open(p, "w").write(s) print("[wrote %s %d chars]" % (p, len(s))) try: print("=" * 78) print("H1: FUN_1800aa440 FULL") s = dec(0x1800aa440) print("len(src) = %d chars, %d lines" % (len(s), s.count("\n") + 1)) dump("q3_reveal", s) print(s) print("--- disassembly: EVERY call target inside FUN_1800aa440 ---") f = func(0x1800aa440) it = listing.getInstructions(f.getBody(), True) direct, indirect = [], [] while it.hasNext(): ins = it.next() t = str(ins) if not t.startswith("CALL"): continue a = int(ins.getAddress().getOffset()) fl = ins.getFlows() if fl and len(fl) > 0: tgt = int(fl[0].getOffset()) direct.append((a, tgt, fname(tgt))) else: indirect.append((a, t)) print(" direct calls: %d" % len(direct)) for a, tgt, nm in direct: print(" %#x -> %#x %s" % (a, tgt, nm)) print(" indirect calls: %d" % len(indirect)) for a, t in indirect: print(" %#x %s" % (a, t)) print(" URL builder 0x180129200 called?", any(t == 0x180129200 for _, t, _ in direct)) print("=" * 78) print("H2: FUN_1800a9fe0 FULL") s2 = dec(0x1800a9fe0) print("len=%d" % len(s2)); dump("q3_tier", s2); print(s2) print("=" * 78) print("H3: FUN_1800aa330 FULL") s3 = dec(0x1800aa330) print("len=%d" % len(s3)); dump("q3_pred", s3); print(s3) print("=" * 78) print("H4: FUN_1800a96a0 FULL") s4 = dec(0x1800a96a0) print("len=%d" % len(s4)); dump("q3_sort", s4); print(s4) print("=" * 78) print("H5: FUN_180015d80 FULL") s5 = dec(0x180015d80) print("len=%d" % len(s5)); dump("q3_numpack", s5); print(s5) print("=" * 78) print("H6: atom ladder of 0x18013fe00 reconstructed FROM DISASSEMBLY") s6 = dec(0x18013fe00) print("item deser decompile len=%d chars, %d lines" % (len(s6), s6.count("\n") + 1)) dump("q3_item_deser", s6) # decompile-side case list, for cross-check cases = sorted(set(int(x, 16) for x in re.findall(r"case 0x([0-9a-f]+):", s6))) print(" decompile 'case 0x..' arms: %d -> %s" % (len(cases), [hex(c) for c in cases])) print(" decompile contains '0x23d'? ", "0x23d" in s6) print(" decompile contains '0x23f'? ", "0x23f" in s6) f6 = func(0x18013fe00) print(" function body: %s - %s" % (f6.getBody().getMinAddress(), f6.getBody().getMaxAddress())) it = listing.getInstructions(f6.getBody(), True) running = 0 ladder = [] seq = [] while it.hasNext(): ins = it.next() mn = ins.getMnemonicString() t = str(ins) a = int(ins.getAddress().getOffset()) if mn in ("SUB", "CMP", "DEC", "ADD"): m = re.search(r",\s*(0x[0-9a-fA-F]+)$", t) imm = None if m: imm = int(m.group(1), 16) elif mn == "DEC": imm = 1 if imm is None: continue if mn == "SUB" or mn == "DEC": running += imm ladder.append((a, running, t)) elif mn == "CMP": ladder.append((a, running + imm, t + " [CMP => atom %#x]" % (running + imm))) elif mn == "ADD": running -= imm ladder.append((a, running, t)) seq.append((a, mn, imm, running)) reach = sorted(set(v for _, v, _ in ladder)) print(" ladder entries: %d ; distinct running-sum values: %d" % (len(ladder), len(reach))) print(" reachable atom-ish values (hex): %s" % [hex(v) for v in reach]) for probe, nm in ((0x23d, "playerType"), (0x23f, "playStyle"), (0xd7, "discardValue"), (0x6c, "cardsubtypeid"), (0x274, "rating"), (0x271, "rareflag"), (0x172, "itemState"), (0x19b, "loans"), (0x287, "resourceId")): print(" atom %#-6x %-14s in ladder? %s in decompile cases? %s" % (probe, nm, probe in reach, probe in cases)) print(" --- raw ladder (first 400) ---") for a, v, t in ladder[:400]: print(" %#x sum=%#-6x %s" % (a, v, t)) except Exception: traceback.print_exc() print("QUERY DONE")