"""ADVERSARIAL VERIFICATION BATCH 1. HYPOTHESES UNDER ATTACK (from the D4 report): H-A record+0x54 is card LEVEL derived from rating by an unconditional ladder in the tail of FUN_180141660, NOT itemType. H-B FUN_1801a87f0 is a one-byte read of record+0xb4 and all four OVERALL_RATING publishers call it. H-C playStyle lands at record+0x88, FUN_180136480 accepts only 0xfb..0x111. H-D atom 0x173 itemType never becomes an int. CONTROLS. * For every "no such thing" statement I enumerate case labels, `== 0x`, `!= 0x` AND sub/dec ladders, and I state which form the positive control used. * Positive control for the dispatch enumeration: atoms 0x274 (rating) and 0x287 (resourceId), both known-present, must be found by the SAME enumerator. * Positive control for the literal-xref method: a literal whose xref count is independently known. Everything is written to files; nothing is truncated. """ import traceback OUT = "/tmp/claude-1000/-home-alex-Documents-OpenFUT/8e521ca1-ca3e-4138-bb96-df1744dd1d30/scratchpad/cards/adv/" try: import re def dump(name, s): p = OUT + name open(p, "w").write(s) print("WROTE %s (%d chars)" % (p, len(s))) targets = { "merge_141660": 0x180141660, "deser_13fe00": 0x18013FE00, "playersmerge_135890": 0x180135890, "acc_rating_1a87f0": 0x1801A87F0, "acc_cardlevel_1a80c0": 0x1801A80C0, "acc_playstyle_1a85c0": 0x1801A85C0, "acc_league_1a8550": 0x1801A8550, "acc_attr_1a8450": 0x1801A8450, "acc_dream_1a8830": 0x1801A8830, "acc_assetid_1a8010": 0x1801A8010, "acc_asset2_1a8020": 0x1801A8020, "mapper_playstyle_136480": 0x180136480, "family_d8330": 0x1800D8330, "resid_166ca0": 0x180166CA0, } blob = [] src = {} for nm, a in targets.items(): f = func(a) s = dec(a, 600) src[nm] = s blob.append("=" * 78) blob.append("### %s @ %#x ghidra_fn=%s entry=%#x len=%d" % ( nm, a, f.getName() if f else "NONE", int(f.getEntryPoint().getOffset()) if f else 0, len(s))) blob.append(s) dump("v1_bodies.txt", "\n".join(blob)) # ---- dispatch-form enumeration over the item deser, ALL FOUR FORMS d = src["deser_13fe00"] print("\n--- deser FUN_18013fe00 len=%d ---" % len(d)) cases = sorted(set(int(x, 16) for x in re.findall(r"case\s+0x([0-9a-fA-F]+)", d))) cases += sorted(set(int(x) for x in re.findall(r"case\s+(\d+)", d))) eq = sorted(set(int(x, 16) for x in re.findall(r"==\s*0x([0-9a-fA-F]+)", d))) ne = sorted(set(int(x, 16) for x in re.findall(r"!=\s*0x([0-9a-fA-F]+)", d))) lt = sorted(set(int(x, 16) for x in re.findall(r"<\s*0x([0-9a-fA-F]+)", d))) sub = sorted(set(int(x, 16) for x in re.findall(r"-\s*0x([0-9a-fA-F]+)", d))) print("case labels (%d): %s" % (len(cases), [hex(c) for c in cases])) print("== 0x (%d): %s" % (len(eq), [hex(c) for c in eq])) print("!= 0x (%d): %s" % (len(ne), [hex(c) for c in ne])) print("< 0x (%d): %s" % (len(lt), [hex(c) for c in lt])) print("- 0x ladders (%d): %s" % (len(sub), [hex(c) for c in sub])) for probe, label in [(0x274, "rating CONTROL"), (0x287, "resourceId CONTROL"), (0x173, "itemType"), (0x23F, "playStyle"), (0x172, "itemState"), (0x207, "owners"), (0x361, "untradeable"), (0x1B, "amount"), (0x226, "pile"), (0x6B, "cardassetid"), (0x23, "assetId"), (0x18A, "leagueId"), (0x1D1, "nation"), (0x6C, "cardsubtypeid")]: forms = [] if probe in cases: forms.append("case") if probe in eq: forms.append("==") if probe in ne: forms.append("!=") print(" atom %#x %-18s dispatch forms: %s" % (probe, label, forms or "NONE FOUND")) # ---- who writes offset 0x54 anywhere in the two functions? print("\n--- textual writes to +0x54 / 0x54 in merge and deser ---") for nm in ("merge_141660", "deser_13fe00", "playersmerge_135890"): for ln_no, ln in enumerate(src[nm].split("\n")): if "0x54" in ln or "0xb4" in ln: print(" %-20s %4d| %s" % (nm, ln_no, ln.strip())) # ---- OVERALL_RATING literal: locate it MYSELF, then xref print("\n--- OVERALL_RATING literal census ---") hits = find_all(b"OVERALL_RATING\x00") print("occurrences of 'OVERALL_RATING\\0':", [hex(h) for h in hits]) for h in hits: xs = xrefs_to(h) print(" %#x xrefs=%d" % (h, len(xs))) for frm, t, fn, ent in xs: print(" from %#x %s in %s @%#x" % (frm, t, fn, ent)) # control: a literal with an obviously different xref profile for lit in (b"CARD_LEVEL\x00", b"PLAY_STYLE\x00", b"LEAGUE_ID\x00", b"ATTRIBUTE_VALUE\x00", b"IS_DREAM_PLAYER\x00", b"ASSET_ID\x00"): hs = find_all(lit) print("\n%s occurrences: %s" % (lit, [hex(x) for x in hs])) for h in hs: xs = xrefs_to(h) print(" %#x xrefs=%d -> %s" % (h, len(xs), sorted(set(x[2] for x in xs)))) except Exception: traceback.print_exc()