"""HYPOTHESIS: CardsDLL holds named-state literals for online/connection state, in the same family as IS_TRADING_ENABLED (an OUTPUT name published by FUN_18006cc60). If an ONLINE/CONNECT/SESSION named state exists, the UI's market refusal and the Seasons refusal may both read it. CONTROL: IS_TRADING_ENABLED (0x1801fc118) MUST appear in the enumeration, with exactly one rip-relative xref (the lea in the publisher). If the enumeration misses it, the enumeration is broken. Enumerates .rdata ASCII literals matching online-ish tokens, and for each prints xref count + containing functions. """ import re, traceback try: blocks = {} for b in mem.getBlocks(): blocks[str(b.getName())] = (int(b.getStart().getOffset()), int(b.getEnd().getOffset())) print("BLOCKS:", {k: ("%#x-%#x" % v) for k, v in blocks.items()}) def block_bytes(name): s, e = blocks[name] out = bytearray() a = s while a <= e: n = min(1 << 20, e - a + 1) out += read_bytes(a, n) a += n return s, bytes(out) rs, rdata = block_bytes(".rdata") ds, data = block_bytes(".data") ts, text = block_bytes(".text") print("LEN .rdata=%d .data=%d .text=%d" % (len(rdata), len(data), len(text))) TOKENS = [b"ONLINE", b"OFFLINE", b"RECONNECT", b"RE-CONNECT", b"CONNECT", b"DISCONNECT", b"SESSION", b"HEARTBEAT", b"PING", b"NUCLEUS", b"PERSONA", b"SEASON", b"UNAVAILABLE", b"UNREACHABLE", b"Online", b"Offline", b"Reconnect", b"reconnect", b"connected", b"isOnline", b"online"] strre = re.compile(rb"[\x20-\x7e]{5,120}") found = {} for blkname, base, buf in ((".rdata", rs, rdata), (".data", ds, data)): for m in strre.finditer(buf): s = m.group() if not any(t in s for t in TOKENS): continue # require NUL termination to be a real C string end = m.end() if end < len(buf) and buf[end] != 0: continue va = base + m.start() found.setdefault(va, (blkname, s.decode("latin1"))) print("TOTAL candidate literals:", len(found)) # rip-relative xref counting over .text, form-independent: find any 4-byte # displacement d such that (insn_end + d) == va. We approximate by scanning for # the exact 4-byte LE of (va - (ts + i + 4)) at each i -- too slow. Instead use # Ghidra's reference manager, and ALSO a raw disp scan for the control. def xr(va): try: return xrefs_to(va) except Exception: return [] ctrl = 0x1801fc118 print("\n=== CONTROL IS_TRADING_ENABLED %#x ===" % ctrl) print(" str:", repr(rd_str(ctrl))) print(" xrefs:", [(hex(a), t, n) for a, t, n, e in xr(ctrl)]) print(" in enumeration:", ctrl in found) print("\n=== ENUMERATION (va | block | xrefcount | funcs | string) ===") for va in sorted(found): blk, s = found[va] x = xr(va) fns = sorted({n for a, t, n, e in x}) print("%#x %s xr=%d %s | %s" % (va, blk, len(x), ",".join(fns[:5]), s)) except Exception: traceback.print_exc()