#!/usr/bin/env python3 import subprocess, os, glob, sys, time, struct proc = None RPP = sys.argv[1] if len(sys.argv) > 1 else "/home/m/soothe-bt/render_long.rpp" START = len(sys.argv) > 2 and sys.argv[2] == "start" if START: proc = subprocess.Popen( ['reaper', '-nosplash', '-renderproject', RPP], stdout=open('/tmp/rtfind.log', 'w'), stderr=subprocess.STDOUT) print('reaper', proc.pid, flush=True) # The SpectralProcessor vtable slot containing ctor 0x180529610 CTOR = 0x180529610 # candidate vptrs: slots near it VCANDS = [0x1824abb80, 0x1824abb88, 0x1824abb90, 0x1824abb98, 0x1824abba0, 0x1824abba8, 0x1824abbb0] def all_mapped(pid): out = [] maps = open(f'/proc/{pid}/maps').read() for line in maps.splitlines(): p = line.split() lo, hi = (int(x, 16) for x in p[0].split('-')) if 'r' in p[1]: out.append((lo, hi)) return out def scan(pid, vptr, tgt): mem = os.open(f'/proc/{pid}/mem', os.O_RDONLY) hits = [] for lo, hi in all_mapped(pid): try: d = os.pread(mem, hi - lo, lo) except Exception: continue i = 0 while True: i = d.find(tgt, i) if i < 0: break hits.append(lo + i) i += 1 os.close(mem) return hits def filter_candidates(pid, hit_addrs): # for each candidate object addr (addr = where vptr stored => object base), read fields out = [] mem = os.open(f'/proc/{pid}/mem', os.O_RDONLY) for a in hit_addrs: try: d = os.pread(mem, 0x600, a) except Exception: continue f4 = struct.unpack('<%dI' % (len(d) // 4), d) # look for N at +0x19c and oversample at +0x1ac n = f4[0x19c // 4] if (0x19c // 4) < len(f4) else 0 u = f4[0x1ac // 4] if (0x1ac // 4) < len(f4) else 0 w = struct.unpack('= 0x1a4 + 8 else 0 ok = (n in (256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536) and u in (2, 4, 8, 16)) if w != 0 and (n > 0 or ok): out.append((a, n, u, w, ok)) os.close(mem) return out hosts = {} t0 = time.time() seen = set() while time.time() - t0 < 90: for p in glob.glob('/proc/[0-9]*'): try: pid = int(os.path.basename(p)) if pid in seen: continue maps = open(f'/proc/{pid}/maps').read() if 'soothe2' not in maps or 'yabridge-host.exe' not in open(f'/proc/{pid}/cmdline', 'rb').read().decode('utf8', 'replace'): continue except Exception: continue seen.add(pid) print('host', pid, flush=True) # scan whole maps for each candidate vptr for v in VCANDS: h = scan(pid, v, struct.pack('