"""q_cd_route_2 -- the ClubSearch (FutStickerBookSearch) query-string builder. HYPOTHESIS The club item list is the "StickerBookSearch" request (RS4 literal at 0x180221e48). Its literal block holds "%s%s=%s" 0x180221e78, "%s%s=%d" 0x180221e80, "%s%s=" 0x180221e94, "2017", "desc", "asc", so the query string is assembled key by key with a separator+name+value printf, and the key names come out of the atom reverse lookup FUN_180180cd0 exactly as they do in the /stats/%s builder FUN_18012f4f0 (already decompiled: 6 cases, atoms 0x87 club / 0x389 year / 0xbd country / 0x189 league / 0x1d7 newcards / 0xa5 consumables). A RIP-displacement scan of .text on the on-disk PE puts every use of those three printf formats in 0x18012deb0..0x18012e5bd, one contiguous region, plus two strays at 0x180169357/0x1801693ac and one at 0x180163a1c. CONTROL FUN_18012f4f0 (/stats/%s) decompiled cleanly in q_cd_route_1 through the same helpers, so a NO FUNC or an empty body here is a fact about this address, not about the harness. Also included: the two enum reverse-lookups FUN_180166300 (table 0x180229ab0) and the sibling at 0x180166340 (table 0x180229c30), and their callers, because those tables are the candidate ?type= vocabularies and a table with no caller inside a URL builder proves nothing about the wire. Absence discipline: the atom-id switch in a builder is a `switch` with case labels, so it is enumerated by reading the decompile in full, not by grepping "== 0x". """ import traceback try: def show(label, ea, full=True): f = func(ea) print("=" * 78) print("### %s @ %s -> %s" % (label, hex(ea), f.getName() if f else "NO FUNC")) if f is None: return None print(" entry %s body %s" % (f.getEntryPoint(), f.getBody())) src = dec(f) print(" len(src) = %d" % len(src)) if full: print(src) return f seen = set() for ea in (0x18012deb0, 0x18012df5c, 0x18012e087, 0x18012e19f, 0x18012e202, 0x18012e256, 0x18012e2d0, 0x18012e322, 0x18012e5bd, 0x18012dfb0, 0x18012e003, 0x18012e36d, 0x18012e3b8, 0x18012e403, 0x18012e44e, 0x18012e499, 0x18012e0db): f = fm.getFunctionContaining(addr(ea)) if f is None: print("### query-fmt use @ %s -> NO FUNC" % hex(ea)) continue k = int(f.getEntryPoint().getOffset()) if k in seen: continue seen.add(k) show("query-fmt user (via %s)" % hex(ea), k) for ea in (0x180169357, 0x180163a1c): f = fm.getFunctionContaining(addr(ea)) if f is None: print("### stray fmt use @ %s -> NO FUNC" % hex(ea)) continue k = int(f.getEntryPoint().getOffset()) if k not in seen: seen.add(k) show("stray query-fmt user (via %s)" % hex(ea), k) show("enum revlookup table 0x180229ab0", 0x180166300) show("enum revlookup table 0x180229c30", 0x180166340) for ea in (0x180166300, 0x180166340): f = fm.getFunctionContaining(addr(ea)) if f is None: continue print("--- callers of %s:" % hex(ea)) for c in sorted(set(int(x.getEntryPoint().getOffset()) for x in f.getCallingFunctions(mon))): print(" %s %s" % (hex(c), fm.getFunctionAt(addr(c)).getName())) show("StaffStats suffix (/stats/staff user)", 0x18012b086) except Exception: traceback.print_exc()