runtime capture pt2: vst3 loads AT ImageBase 0x180000000; 0x540658 = field [ctx+0x540658] not RVA; beacon->ctx script (racy)
This commit is contained in:
+129
@@ -0,0 +1,129 @@
|
||||
#!/usr/bin/env python3
|
||||
"""rtcapture2.py — robust runtime capture for a LONG render (host lives minutes).
|
||||
Dumps sections + raw target buffers at module_base+rva (PE ImageBase=0x180000000).
|
||||
"""
|
||||
import subprocess, time, glob, os, struct, sys
|
||||
|
||||
RPP = sys.argv[1] if len(sys.argv) > 1 else '/home/m/soothe-bt/dual300.rpp'
|
||||
OUT = sys.argv[2] if len(sys.argv) > 2 else '/tmp/rtcap2.log'
|
||||
RVAS = [0x541134, 0x541258, 0x541278, 0x5413c8, 0x541298, 0x541470, 0x541480, 0x541488, 0x5414b0]
|
||||
|
||||
|
||||
def find_pe(pid):
|
||||
mem = os.open(f'/proc/{pid}/mem', os.O_RDONLY)
|
||||
seen = set()
|
||||
for line in open(f'/proc/{pid}/maps').read().splitlines():
|
||||
lo = int(line.split()[0].split('-')[0], 16)
|
||||
if lo in seen:
|
||||
continue
|
||||
seen.add(lo)
|
||||
try:
|
||||
hdr = os.pread(mem, 0x1000, lo)
|
||||
except Exception:
|
||||
continue
|
||||
if hdr[:2] != b'MZ':
|
||||
continue
|
||||
try:
|
||||
x = struct.unpack('<I', hdr[0x3c:0x40])[0]
|
||||
if hdr[x:x + 4] != b'PE\x00\x00':
|
||||
continue
|
||||
magic = struct.unpack('<H', hdr[x + 24:x + 26])[0]
|
||||
ib = struct.unpack('<Q', hdr[x + 48:x + 56])[0] if magic == 0x20b else struct.unpack('<I', hdr[x + 52:x + 56])[0]
|
||||
return lo, ib
|
||||
except Exception:
|
||||
continue
|
||||
os.close(mem)
|
||||
return None, 0
|
||||
|
||||
|
||||
def sections(pid, base):
|
||||
mem = os.open(f'/proc/{pid}/mem', os.O_RDONLY)
|
||||
hdr = os.pread(mem, 0x1000, base)
|
||||
x = struct.unpack('<I', hdr[0x3c:0x40])[0]
|
||||
nsec = struct.unpack('<H', hdr[x + 6:x + 8])[0]
|
||||
opt = struct.unpack('<H', hdr[x + 20:x + 22])[0]
|
||||
out = []
|
||||
for i in range(nsec):
|
||||
sh = os.pread(mem, 40, base + x + 24 + opt + i * 40)
|
||||
nm = sh[:8].rstrip(b'\0').decode('utf8', 'replace')
|
||||
vsize, va, rsize, roc = struct.unpack('<IIII', sh[8:24])
|
||||
ch = struct.unpack('<I', sh[36:40])[0]
|
||||
out.append((nm, va, vsize, ch))
|
||||
os.close(mem)
|
||||
return out
|
||||
|
||||
|
||||
def vst_base(pid):
|
||||
lo = None
|
||||
for line in open(f'/proc/{pid}/maps').read().splitlines():
|
||||
if 'soothe2' not in line:
|
||||
continue
|
||||
a = int(line.split()[0].split('-')[0], 16)
|
||||
lo = a if lo is None else min(lo, a)
|
||||
if lo is None:
|
||||
return None
|
||||
try:
|
||||
mem0 = os.open(f'/proc/{pid}/mem', os.O_RDONLY)
|
||||
hdr = os.pread(mem0, 0x1000, lo)
|
||||
os.close(mem0)
|
||||
except Exception:
|
||||
return None
|
||||
return lo if hdr[:2] == b'MZ' else None
|
||||
|
||||
|
||||
def main():
|
||||
out = open(OUT, 'w')
|
||||
proc = subprocess.Popen(['reaper', '-nosplash', '-renderproject', RPP], stdout=out, stderr=subprocess.STDOUT)
|
||||
t0 = time.time()
|
||||
base = None
|
||||
host = None
|
||||
while time.time() - t0 < 90:
|
||||
for pid in glob.glob('/proc/[0-9]*'):
|
||||
pid = int(os.path.basename(pid))
|
||||
try:
|
||||
cmd = open(f'/proc/{pid}/cmdline', 'rb').read().decode('utf8', 'replace')
|
||||
maps = open(f'/proc/{pid}/maps').read()
|
||||
except Exception:
|
||||
continue
|
||||
if 'yabridge-host' not in cmd and 'soothe2' not in maps:
|
||||
continue
|
||||
b = vst_base(pid)
|
||||
if b:
|
||||
host, base = pid, b
|
||||
print(f'pid={pid} vst_base={hex(b)}', flush=True)
|
||||
break
|
||||
if base:
|
||||
break
|
||||
time.sleep(0.05)
|
||||
if not base:
|
||||
print('NO PE FOUND', flush=True)
|
||||
proc.kill()
|
||||
return
|
||||
for nm, va, vs, ch in sections(host, base):
|
||||
print(f'sec {nm:8s} rva={hex(va):>9} vsize={hex(vs):>9} chars={hex(ch)}', flush=True)
|
||||
mem = os.open(f'/proc/{host}/mem', os.O_RDONLY)
|
||||
t3 = time.time()
|
||||
last = 0
|
||||
while proc.poll() is None and time.time() - t3 < 60:
|
||||
try:
|
||||
d = os.pread(mem, 0x20, base + 0x541258)
|
||||
win = struct.unpack('<8f', d[:32]) if len(d) >= 32 else None
|
||||
except Exception:
|
||||
win = None
|
||||
now = time.time() - t3
|
||||
if now - last >= 2.0 or win is None:
|
||||
print(f'sample t={now:.1f}s win[0:8]={[round(v,5) for v in win] if win else None}', flush=True)
|
||||
for rva in RVAS:
|
||||
d = os.pread(mem, 128, base + rva)
|
||||
fl = struct.unpack('<%df' % (len(d) // 4), d[:len(d) // 4 * 4]) if len(d) >= 4 else []
|
||||
print(f' {hex(rva)} floats={[round(v,5) for v in fl[:4]]} raw={d[:24].hex()}', flush=True)
|
||||
last = now
|
||||
time.sleep(0.05)
|
||||
os.close(mem)
|
||||
print('render done', flush=True)
|
||||
proc.wait(timeout=10)
|
||||
print('done', flush=True)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
Reference in New Issue
Block a user