# VERIFICATION pass 2: the objective URL builders (RANK 9), the /consumables/%s # builder (RANK 10), and the xref counts behind the sbs/draft suffix claims. import re def show(name, a): c = dec(a) bal = c.count("{") - c.count("}") print("=== %s @%#x len=%d balanced=%s" % (name, a, len(c), bal == 0)) print(c) return c for nm, a in (("FUN_180151610", 0x180151610), ("FUN_180147780", 0x180147780), ("FUN_1801308c0", 0x1801308c0)): show(nm, a) print("#" * 72) print("# xrefs to each suffix string") for s in ["/sets", "/sets/tag", "/setId/%d/challenges", "/squadBuildingSets", "/challenge/%d", "/challenge/%d/squad", "/consumables/%s", "/objective/", "/loan/players", "/stats/staff", "/choices/player", "/%d/draft/choose", "ut/%s/sbs", "ut/%s/draft/mode"]: hits = find_all(s.encode() + b"\x00", blocks=(".rdata", ".data", ".text")) for h in hits: xs = xrefs_to(h) txt = ", ".join("%s@%#x" % (fn, en) for (_, _, fn, en) in xs) print(" %-24s @%#x xrefs=%d %s" % (s, h, len(xs), txt)) print("#" * 72) print("# .rdata neighbourhood of the two objective vtables (identity check)") for vt in (0x1801fc080, 0x180206090): print("-- vtable %#x" % vt) for i in range(8): try: q = qword(vt + i * 8) except Exception: break f = fm.getFunctionAt(addr(q)) if 0x180000000 <= q < 0x181000000 else None print(" +%02x %#018x %s" % (i * 8, q, f.getName() if f else "")) # ascii that follows b = read_bytes(vt + 64, 160) print(" trailing bytes:", re.findall(rb"[ -~]{4,}", b))