"""Q19: every constant the code compares a +0x50 (cardsubtypeid) or +0x4c (cardtype) field against. The parsed item record has cardsubtypeid at +0x50 and cardtype at +0x4c. Instead of searching for a constant (which misses jump tables) or for a syntactic form (which misses != and ladders), search for the FIELD ACCESS and then collect every immediate that touches the loaded register within the next 8 instructions, whatever the mnemonic. Both the direct form (CMP dword [reg+0x50], imm) and the load-then-test form (MOV r32,[reg+0x50]; SUB r32,imm; CMP r32,imm) are covered. CONTROL: FUN_18011e3c0 is known to do `*(int *)(x + 0x50) - 0x91U < 6`, so it must appear with 0x91 (and 6) attached to a +0x50 access. If the control is absent the scan is broken and nothing may be concluded from what it does not find. """ import traceback try: block = None for b in mem.getBlocks(): if b.getName() == ".text": block = b break per = {} it = listing.getInstructions(block.getStart(), True) window = [] # [(reg_name, remaining_instrs)] n = 0 while it.hasNext(): ins = it.next() n += 1 txt = str(ins) # 1) direct: memory operand with disp 0x50/0x4c and an immediate for disp in ("0x50", "0x4c"): if ("+ " + disp + "]") in txt or ("+" + disp + "]") in txt: imms = [] for i in range(ins.getNumOperands()): for o in ins.getOpObjects(i): try: imms.append(int(o.getValue())) except Exception: pass f = fm.getFunctionContaining(ins.getAddress()) key = (f.getName(), int(f.getEntryPoint().getOffset())) if f else ("?", 0) rec = per.setdefault(key, {"direct": set(), "near": set()}) for v in imms: if v not in (0x50, 0x4C) and 0 <= v < 0x1000: rec["direct"].add((disp, v)) # start a window: whatever register this instruction defines for r in ins.getResultObjects(): window.append([str(r), 8, key, disp]) # 2) decay window and attach immediates that touch the tracked register nxt = [] for w in window: reg, left, key, disp = w if left <= 0: continue if reg in txt: for i in range(ins.getNumOperands()): for o in ins.getOpObjects(i): try: v = int(o.getValue()) except Exception: continue if 0 <= v < 0x1000: per.setdefault(key, {"direct": set(), "near": set()}) per[key]["near"].add((disp, v)) w[1] = left - 1 nxt.append(w) window = nxt[-40:] print("instructions scanned: %d" % n) print() CAND = {9, 10, 11, 0x1E, 0x1F, 7, 0x91} print("=== functions whose +0x50 / +0x4c constants meet {9,10,11,0x1e,0x1f,7,0x91} ===") for (name, ent), rec in sorted(per.items()): vals = rec["direct"] | rec["near"] hit = {v for _d, v in vals} & CAND if not hit: continue print(" %-24s %#x hits=%s" % (name, ent, sorted("%#x" % h for h in hit))) print(" direct=%s" % sorted("%s:%#x" % (d, v) for d, v in rec["direct"])) print(" near =%s" % sorted("%s:%#x" % (d, v) for d, v in rec["near"])[:40]) print() print("=== control FUN_18011e3c0 ===") for (name, ent), rec in per.items(): if ent == 0x18011E3C0: print(" direct=%s" % sorted("%s:%#x" % (d, v) for d, v in rec["direct"])) print(" near =%s" % sorted("%s:%#x" % (d, v) for d, v in rec["near"])) except Exception: traceback.print_exc()