runtime capture pt2: vst3 loads AT ImageBase 0x180000000; 0x540658 = field [ctx+0x540658] not RVA; beacon->ctx script (racy)
This commit is contained in:
@@ -349,3 +349,31 @@ getFunctionContaining(0x52ac64) and has the complete per-band loop + FFT-conv).
|
|||||||
## опять +1.4 dB).
|
## опять +1.4 dB).
|
||||||
## => мультибанд: сумма displacements -> sat-кривая. Каждая полоса отдельно калибруется single-
|
## => мультибанд: сумма displacements -> sat-кривая. Каждая полоса отдельно калибруется single-
|
||||||
## band рендерами; комбинация закрывается runtime или sat-подгонкой на b1on12_b2on12.
|
## band рендерами; комбинация закрывается runtime или sat-подгонкой на b1on12_b2on12.
|
||||||
|
|
||||||
|
|
||||||
|
## ============ 2026-08-18h2: RUNTIME CAPTURE PARTIAL (base 0x180000000, 0x540658 = FIELD NOT RVA) ============
|
||||||
|
|
||||||
|
### Runtime capture infra (rtcapture2.py, WORKS):
|
||||||
|
- Launch: `reaper -nosplash -renderproject X.rpp`; host pid found by scanning /proc/*/maps for 'soothe2'
|
||||||
|
(lowest map addr with soothe2 in path = PE base). **vst3 loads AT ImageBase 0x180000000** (no reloc).
|
||||||
|
- Reading /proc/pid/mem (+0x180000000) works DURING render; process dies right after render finishes.
|
||||||
|
- Section table (Authoritative): .text rva 0x1000 raw 0x600 vsize 0x1a52000; IPPCODE 0x1a53000/0x1a51e00;
|
||||||
|
.rdata 0x1baa000/0x1ba8400 vsize 0xa60000; .data 0x260a000/0x2608200 vsize 0x72000; .pdata 0x267c000.
|
||||||
|
- FILE->RVA mapping: raw off F maps to rva = F - raw_sec + va_sec (e.g. .text: F=0x53F658<->rva=0x541058).
|
||||||
|
|
||||||
|
### CRITICAL: 0x540658 (and 0x540678/0x5407c8/0x5408b0/etc) are FIELD OFFSETS, NOT RVAs!
|
||||||
|
- Disasm at rva 0x52b771: `mov rax,[rdi+0x540658]` -> window read is [ctx+0x540658] (ctx = DSP object).
|
||||||
|
- Static soothe_mem.bin is RVA-linear; reading at 0x540658 gives .text CODE bytes (garbage floats).
|
||||||
|
- So the "window" (FIR*=WINDOW in FFT-conv step 5) lives in the HEAP DSP object at offset 0x540658,
|
||||||
|
NOT in module image. Runtime must locate `ctx` = base of DSP object.
|
||||||
|
- Beacon idea: phase_table_1024 (twiddle doubles 0x182615608 in .data) is the FFT-plan table;
|
||||||
|
scan host heap for u64==0x182615608, then the pointer owner is plan (+0x18/+0x20/+0x68 fields)
|
||||||
|
-> ctx = byte_addr_of_(pointer_field) - field_offset; window at ctx+0x540658.
|
||||||
|
(rtdeep2.py implements this; currently racy - host may exit before numpy import + first scan.)
|
||||||
|
|
||||||
|
### Notes for next session:
|
||||||
|
- Render lifetime is short (~2-19s); to win the race: import numpy BEFORE Popen, scan /proc instantly,
|
||||||
|
and re-run if host missed. Could also pre-load module into gdb for direct ctx inspection.
|
||||||
|
- Alternative: find ctx via 'consumers_out' alloc chain (note :119-135) if heap layout known.
|
||||||
|
- Verified render outputs: out_dual300.wav etc; run_sweep works; pkill -9 -x reaper hangs shell -
|
||||||
|
use `pkill -9 -f "reap[e]r"` style to avoid killing own bash.
|
||||||
|
|||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
"""rtcapture.py — runtime-захват soothe2 из yabridge-host во время offline-рендера.
|
||||||
|
|
||||||
|
Запускает reaper -renderproject <rpp>, находит yabridge-host.exe.so с soothe2_x64.vst3,
|
||||||
|
вычисляет runtime-базу модуля (по MZ/PE) и непрерывно сэмплирует целевую RAM плагина
|
||||||
|
(RVA = VA - 0x180000000). Печатает последние стабильные значения по окончании рендера.
|
||||||
|
|
||||||
|
Цели (RVA от базы модуля):
|
||||||
|
0x540658 окно/FIR (размер окна из plan) [искомое 0.540658]
|
||||||
|
0x540678 per-bin уровень-трекеры
|
||||||
|
0x5407c8 аккумулятор маски (C)
|
||||||
|
0x540698 freq-axis значение
|
||||||
|
0x540534 N/2 (FFT size)
|
||||||
|
0x5408b0 узлы кривой 0x188 (20 doubles)
|
||||||
|
0x540888 0x540880 ctor-константы
|
||||||
|
0x540530..0x5405a0 план-таблицы FFT
|
||||||
|
"""
|
||||||
|
import os, sys, glob, time, struct, subprocess
|
||||||
|
|
||||||
|
RPP = sys.argv[1] if len(sys.argv) > 1 else '/home/m/soothe-bt/render_long.rpp'
|
||||||
|
BASE = 0x180000000
|
||||||
|
TARGETS = {
|
||||||
|
'window_0x540658': (0x540658, 0x1000),
|
||||||
|
'levels_0x540678': (0x540678, 0x400),
|
||||||
|
'acc_0x5407c8': (0x5407c8, 0x40),
|
||||||
|
'freqaxis_0x540698': (0x540698, 0x20),
|
||||||
|
'n2_0x540534': (0x540534, 0x20),
|
||||||
|
'curve_0x5408b0': (0x5408b0, 0x200),
|
||||||
|
'ctor_0x540870': (0x540870, 0x60),
|
||||||
|
'plan_0x540530': (0x540530, 0x80),
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def find_base(pid):
|
||||||
|
maps = open(f'/proc/{pid}/maps').read()
|
||||||
|
mem = os.open(f'/proc/{pid}/mem', os.O_RDONLY)
|
||||||
|
seen = set()
|
||||||
|
for line in maps.splitlines():
|
||||||
|
p = line.split()
|
||||||
|
lo = int(p[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]
|
||||||
|
if magic == 0x20b:
|
||||||
|
ib = struct.unpack('<Q', hdr[x + 24 + 24:x + 24 + 32])[0] # PE32+ ImageBase
|
||||||
|
elif magic == 0x10b:
|
||||||
|
ib = struct.unpack('<I', hdr[x + 24 + 28:x + 24 + 32])[0]
|
||||||
|
else:
|
||||||
|
continue
|
||||||
|
return lo, ib
|
||||||
|
except Exception:
|
||||||
|
continue
|
||||||
|
os.close(mem)
|
||||||
|
return None, 0
|
||||||
|
|
||||||
|
|
||||||
|
def read(pid, addr, n):
|
||||||
|
mem = os.open(f'/proc/{pid}/mem', os.O_RDONLY)
|
||||||
|
try:
|
||||||
|
return os.pread(mem, n, addr)
|
||||||
|
except Exception:
|
||||||
|
return None
|
||||||
|
finally:
|
||||||
|
os.close(mem)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
proc = subprocess.Popen(['reaper', '-nosplash', '-renderproject', RPP],
|
||||||
|
stdout=open('/tmp/rtcap.log', 'w'), stderr=subprocess.STDOUT)
|
||||||
|
host = None
|
||||||
|
t0 = time.time()
|
||||||
|
while time.time() - t0 < 120:
|
||||||
|
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' in cmd and ('soothe2' in maps or 'vst3' in maps):
|
||||||
|
host = pid
|
||||||
|
break
|
||||||
|
if host:
|
||||||
|
break
|
||||||
|
time.sleep(0.2)
|
||||||
|
if not host:
|
||||||
|
print('HOST NOT FOUND')
|
||||||
|
proc.kill()
|
||||||
|
return
|
||||||
|
base, ib = find_base(host)
|
||||||
|
print(f'host pid={host} module_base={hex(base)} PE_ImageBase={hex(ib)} delta={hex(base - ib)}', flush=True)
|
||||||
|
if not base:
|
||||||
|
proc.kill()
|
||||||
|
return
|
||||||
|
# sample until reaper exits
|
||||||
|
last = {}
|
||||||
|
ts = time.time()
|
||||||
|
while proc.poll() is None and time.time() - ts < 150:
|
||||||
|
for name, (rva, n) in TARGETS.items():
|
||||||
|
d = read(host, base + rva, n)
|
||||||
|
if d is not None:
|
||||||
|
last[name] = d
|
||||||
|
time.sleep(0.05)
|
||||||
|
proc.wait(timeout=10)
|
||||||
|
print('--- captured (render done) ---')
|
||||||
|
for name, (rva, n) in TARGETS.items():
|
||||||
|
d = last.get(name)
|
||||||
|
if not d:
|
||||||
|
print(f'{name:20s} MISSING')
|
||||||
|
continue
|
||||||
|
vals = struct.unpack('<%dI' % (min(n, len(d)) // 4), d[:min(n, len(d))])
|
||||||
|
if name == 'window_0x540658':
|
||||||
|
fl = struct.unpack('<%df' % (len(d) // 4), d[:len(d) // 4 * 4])
|
||||||
|
nz = [(i, round(v, 6)) for i, v in enumerate(fl) if abs(v) > 1e-9]
|
||||||
|
print(f'{name:20s} nonzero={len(nz)} first20={nz[:20]}')
|
||||||
|
elif name == 'acc_0x5407c8':
|
||||||
|
print(f'{name:20s} ints={[hex(v) for v in vals[:8]]}')
|
||||||
|
elif name == 'curve_0x5408b0':
|
||||||
|
dl = struct.unpack('<%dd' % (len(d) // 8), d[:len(d) // 8 * 8])
|
||||||
|
print(f'{name:20s} doubles={[round(v, 6) for v in dl[:20]]}')
|
||||||
|
elif name == 'levels_0x540678':
|
||||||
|
fl = struct.unpack('<%df' % (len(d) // 4), d[:len(d) // 4 * 4])
|
||||||
|
print(f'{name:20s} floats={[round(v, 5) for v in fl[:40]]}')
|
||||||
|
elif name in ('ctor_0x540870',):
|
||||||
|
fl = struct.unpack('<%df' % (len(d) // 4), d[:len(d) // 4 * 4])
|
||||||
|
print(f'{name:20s} floats={[round(v, 5) for v in fl[:16]]}')
|
||||||
|
elif name in ('plan_0x540530',):
|
||||||
|
print(f'{name:20s} ints={[hex(v) for v in vals[:24]]}')
|
||||||
|
else:
|
||||||
|
print(f'{name:20s} ints={[hex(v) for v in vals[:8]]}')
|
||||||
|
print('done')
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
+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()
|
||||||
+90
-57
@@ -1,76 +1,109 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
import subprocess, os, glob, sys, time, struct
|
"""rtdeep2.py — find DSP ctx object via phase-table pointer beacon, then dump window 0x540658 & neighbors."""
|
||||||
|
import subprocess, time, glob, os, struct, sys
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
RPP = "/home/m/soothe-bt/render_long.rpp"
|
RPP = sys.argv[1] if len(sys.argv) > 1 else '/home/m/soothe-bt/dual300.rpp'
|
||||||
proc = subprocess.Popen(['reaper', '-nosplash', '-renderproject', RPP],
|
BEACON = 0x182615608 # VA of phase_table_1024 (static .data)
|
||||||
stdout=open('/tmp/rtdeep2.log', 'w'), stderr=subprocess.STDOUT)
|
|
||||||
print('reaper', proc.pid, flush=True)
|
|
||||||
|
|
||||||
|
|
||||||
def find_hosts():
|
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)
|
||||||
|
return lo
|
||||||
|
|
||||||
|
|
||||||
|
def readable_regions(pid):
|
||||||
out = []
|
out = []
|
||||||
for p in glob.glob('/proc/[0-9]*'):
|
for line in open(f'/proc/{pid}/maps').read().splitlines():
|
||||||
try:
|
p = line.split()[0]
|
||||||
pid = int(os.path.basename(p))
|
lo, hi = int(p.split('-')[0], 16), int(p.split('-')[1], 16)
|
||||||
m = open(f'/proc/{pid}/maps').read()
|
if 'vst3' in line:
|
||||||
c = open(f'/proc/{pid}/cmdline', 'rb').read().decode('utf8', 'replace')
|
continue # skip module itself
|
||||||
if 'soothe2' in m and 'yabridge-host.exe' in c:
|
out.append((lo, hi))
|
||||||
out.append(pid)
|
|
||||||
except Exception:
|
|
||||||
pass
|
|
||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
def scan(pid):
|
def find_beacon(pid):
|
||||||
# strategy: enumerate every readable chunk; build set of img addresses whose content is 0x18052xxxx
|
try:
|
||||||
# then find heap words equal to any such address
|
|
||||||
mem = os.open(f'/proc/{pid}/mem', os.O_RDONLY)
|
mem = os.open(f'/proc/{pid}/mem', os.O_RDONLY)
|
||||||
img_sp = set() # vtbl-slot candidates: addrs in module image holding 0x18052xxxx
|
except Exception:
|
||||||
heap_addrs = [] # (va, chunk) heap chunks
|
return []
|
||||||
maps = open(f'/proc/{pid}/maps').read()
|
res = []
|
||||||
for line in maps.splitlines():
|
for lo, hi in readable_regions(pid):
|
||||||
p = line.split()
|
sz = (hi - lo) & ~7
|
||||||
lo, hi = (int(x, 16) for x in p[0].split('-'))
|
if sz <= 0 or sz > 0x200000000:
|
||||||
if 'r' not in p[1]:
|
|
||||||
continue
|
continue
|
||||||
try:
|
try:
|
||||||
d = os.pread(mem, hi - lo, lo)
|
buf = os.pread(mem, sz, lo)
|
||||||
except Exception:
|
except Exception:
|
||||||
continue
|
continue
|
||||||
if lo < 0x180000000 < hi or (0x180000000 <= lo < 0x183000000):
|
arr = np.frombuffer(buf, dtype='<u8')
|
||||||
for off in range(0, len(d) - 7, 8):
|
idx = np.where(arr == BEACON)[0]
|
||||||
q = struct.unpack_from('<Q', d, off)[0]
|
for i in idx:
|
||||||
if 0x180520000 <= q < 0x180555000:
|
res.append(lo + int(i) * 8)
|
||||||
img_sp.add(lo + off)
|
|
||||||
else:
|
|
||||||
heap_addrs.append((lo, d))
|
|
||||||
os.close(mem)
|
os.close(mem)
|
||||||
print('img SP-slot addrs found:', len(img_sp), flush=True)
|
return res
|
||||||
# find heap objects pointing into img_sp
|
|
||||||
found = []
|
|
||||||
for lo, d in heap_addrs:
|
|
||||||
for s in img_sp:
|
|
||||||
t = struct.pack('<Q', s)
|
|
||||||
i = 0
|
|
||||||
while True:
|
|
||||||
i = d.find(t, i)
|
|
||||||
if i < 0:
|
|
||||||
break
|
|
||||||
found.append((s, lo + i))
|
|
||||||
i += 1
|
|
||||||
return img_sp, found
|
|
||||||
|
|
||||||
res = {}
|
|
||||||
|
def main():
|
||||||
|
proc = subprocess.Popen(['reaper', '-nosplash', '-renderproject', RPP],
|
||||||
|
stdout=open('/tmp/rtdeep2.log', 'w'), stderr=subprocess.STDOUT)
|
||||||
t0 = time.time()
|
t0 = time.time()
|
||||||
while time.time() - t0 < 80:
|
host = None
|
||||||
for pid in find_hosts():
|
while time.time() - t0 < 60:
|
||||||
if pid in res:
|
for p in glob.glob('/proc/[0-9]*'):
|
||||||
|
try:
|
||||||
|
maps = open(f'/proc/{p}/maps').read()
|
||||||
|
except Exception:
|
||||||
continue
|
continue
|
||||||
img_sp, found = scan(pid)
|
if 'soothe2' not in maps:
|
||||||
res[pid] = (img_sp, found)
|
continue
|
||||||
print('PID', pid, 'objects pointing to SP-method vtbl:', len(found), flush=True)
|
host = int(os.path.basename(p))
|
||||||
for s, a in found[:30]:
|
break
|
||||||
print(f' slotslot {s:#x} object@{a:#x}', flush=True)
|
if host:
|
||||||
time.sleep(0.4)
|
break
|
||||||
|
time.sleep(0.05)
|
||||||
|
print(f'host={host}')
|
||||||
|
if not host:
|
||||||
|
proc.kill()
|
||||||
|
return
|
||||||
|
base = vst_base(host)
|
||||||
|
# allow module load: plugin init first
|
||||||
|
mem = os.open(f'/proc/{host}/mem', os.O_RDONLY)
|
||||||
|
t1 = time.time()
|
||||||
|
while time.time() - t1 < 50:
|
||||||
|
hits = find_beacon(host)
|
||||||
|
ctxs = set()
|
||||||
|
for p in hits:
|
||||||
|
for d in (0x540548, 0x540550, 0x540598):
|
||||||
|
ctxc = p - d
|
||||||
|
if 0x10000000 < ctxc < 0x7fff00000000:
|
||||||
|
ctxs.add(ctxc)
|
||||||
|
if ctxs:
|
||||||
|
print(f't={time.time()-t1:.1f}s hits={len(hits)} ctx_cands={sorted(hex(c) for c in ctxs)}', flush=True)
|
||||||
|
for ctx in sorted(ctxs):
|
||||||
|
d = os.pread(mem, 4096, ctx + 0x540658)
|
||||||
|
if len(d) < 4096:
|
||||||
|
continue
|
||||||
|
fl = np.frombuffer(d, dtype='<f4')
|
||||||
|
if np.all(np.isfinite(fl)) and fl.min() >= -1 and fl.max() <= 2:
|
||||||
|
print(f' ctx={hex(ctx)} WIN@+0x540658 head={[round(float(x),4) for x in fl[:8]]} mid={[round(float(x),4) for x in fl[1024:1032]]}', flush=True)
|
||||||
|
blk = os.pread(mem, 0x8000, ctx + 0x540000)
|
||||||
|
open(f'/tmp/ctx_{ctx:x}_win.bin', 'wb').write(blk)
|
||||||
|
break
|
||||||
|
time.sleep(0.2)
|
||||||
|
os.close(mem)
|
||||||
|
try:
|
||||||
|
proc.wait(timeout=5)
|
||||||
|
except Exception:
|
||||||
proc.kill()
|
proc.kill()
|
||||||
print('done', flush=True)
|
print('done', flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
Reference in New Issue
Block a user