#!/usr/bin/env python3 """RT-4D firmware xref/disasm helper. python xref.py dis [n] disassemble n bytes at vaddr python xref.py callers who bl/blx's this address python xref.py lit where this 32-bit literal appears (pool refs) python xref.py imm movw/movt pairs building this constant python xref.py find raw byte search """ import sys, struct, capstone BASE = 0x08002800 import os _CANDS = [ "/home/viktor/claude/rt-4d/stock-fw/rt4d_stock_v3.25_abs_0x08002800.bin", "/home/viktor/claude/rt-4d-repo/firmware/rt4d_stock_v3.25_abs_0x08002800.bin", os.path.join(os.path.dirname(os.path.abspath(__file__)), "..", "firmware", "rt4d_stock_v3.25_abs_0x08002800.bin"), ] IMG = next(open(p, "rb").read() for p in _CANDS if os.path.exists(p)) md = capstone.Cs(capstone.CS_ARCH_ARM, capstone.CS_MODE_THUMB) md.detail = True def _word(va): o = va - BASE if 0 <= o <= len(IMG) - 4: return struct.unpack_from(" {target: [sites]}.""" xr = {} for start in (0, 2): # both alignments, dedupe by site for i in md.disasm(IMG[start:], BASE + start): if i.mnemonic in ("bl", "blx") and i.op_str.startswith("#"): t = int(i.op_str[1:], 16) xr.setdefault(t, set()).add(i.address) return {k: sorted(v) for k, v in xr.items()} def callers(va): xr = _all_calls() hits = xr.get(va, []) + xr.get(va | 1, []) + xr.get(va & ~1, []) hits = sorted(set(hits)) print(f"callers of 0x{va:08X}: {len(hits)}") for h in hits: print(f" 0x{h:08X}") return hits def lit(val): hits = [] for off in range(0, len(IMG) - 4, 4): if struct.unpack_from("> 16) & 0xFFFF out = [] for i in md.disasm(IMG, BASE): if i.mnemonic == "movw" and i.op_str.endswith(f"#{hex(lo)}"): out.append(i.address) print(f"movw #{hex(lo)} (for 0x{val:08X}): {len(out)} site(s)") for a in out[:60]: print(f" 0x{a:08X}") return out def find(hexs): pat = bytes.fromhex(hexs) off = 0 hits = [] while True: j = IMG.find(pat, off) if j < 0: break hits.append(BASE + j); off = j + 1 print(f"bytes {hexs}: {len(hits)} hit(s)") for h in hits[:60]: print(f" 0x{h:08X}") return hits if __name__ == "__main__": cmd = sys.argv[1] if cmd == "dis": dis(int(sys.argv[2], 16), int(sys.argv[3], 0) if len(sys.argv) > 3 else 0x60) elif cmd == "callers": callers(int(sys.argv[2], 16)) elif cmd == "lit": lit(int(sys.argv[2], 16)) elif cmd == "imm": imm(int(sys.argv[2], 16)) elif cmd == "find": find(sys.argv[2])