#!/usr/bin/env python3 """Find string xrefs in hiby_player (lui/addiu address-load pattern). Usage: python3 rev_xref.py [string ...] Prints the string's rodata vaddr and every code location that loads it via the lui rt,hi16; addiu rt,rt,lo16 idiom. """ import sys, struct, subprocess from capstone import Cs, CS_ARCH_MIPS, CS_MODE_MIPS32, CS_MODE_LITTLE_ENDIAN BIN = "patch_demo/hiby_player_stock" data = open(BIN, "rb").read() def segs(): out = subprocess.run(["readelf", "-lW", BIN], capture_output=True, text=True).stdout res = [] for line in out.splitlines(): p = line.split() if len(p) >= 9 and p[0] == "LOAD": off, vaddr = int(p[1], 16), int(p[2], 16) filesz = int(p[4], 16) flags = "".join(p[6:8]) res.append((vaddr, filesz, off, flags)) return res SEGS = segs() def v2off(v): for vaddr, sz, off, fl in SEGS: if vaddr <= v < vaddr + sz: return off + (v - vaddr) return None def find_string(s): b = s.encode() + b"\x00" idx = data.find(b) if idx < 0: return None for vaddr, sz, off, fl in SEGS: if off <= idx < off + sz: return vaddr + (idx - off) return None def find_load_addr(addr): # .text range out = subprocess.run(["readelf", "-SW", BIN], capture_output=True, text=True).stdout tv = ts = None for line in out.splitlines(): p = line.split() if len(p) >= 7 and p[1] == ".text": tv, ts = int(p[3], 16), int(p[5], 16) blob = data[v2off(tv):v2off(tv) + ts] ins = [] for i in range(0, len(blob) - 8, 4): w1 = struct.unpack_from("> 26) == 0x0F and (w2 >> 26) == 0x09 and ((w1 >> 16) & 0x1F) == ((w2 >> 21) & 0x1F): rt = (w1 >> 16) & 0x1F lo = w2 & 0xFFFF if lo & 0x8000: lo -= 0x10000 val = ((w1 & 0xFFFF) << 16) + lo if val == addr: ins.append((tv + i, rt)) return ins if __name__ == "__main__": for s in sys.argv[1:]: addr = find_string(s) if addr is None: print(f"{s!r}: NOT FOUND") continue print(f"{s!r}: rodata vaddr {addr:#x}") for a, rt in find_load_addr(addr): print(f" lui/addiu at {a:#x} -> reg ${rt}")