24hh-2: runtime dispatch tables STABLE (=static); bigkernels resolve to IMPORTS (outside dump); iat_name.py PE-export parser drafted (needs SIGSTOP race fix); once named, full cascade simulator becomes implementable
This commit is contained in:
@@ -3624,3 +3624,17 @@ fc500 ОДИН тон (f-серия) 1.1530 0.4038 +0.33 0.0013!!
|
||||
### Инструменты/данные раунда
|
||||
scripts/finish_f.py; k-серия (sc_k*, k*_ref); f-серия (sc_f*, f*_ref);
|
||||
k_series.pkl, f_series.pkl. Все рефы отрендеры чисто (без kill).
|
||||
|
||||
## ============ ДОПОЛНЕНИЕ 24gg-2: рантайм-таблицы стабильны; bigkernels = ИМПОРТЫ; имя ждёт PE-парсера ============
|
||||
|
||||
Дамп таблиц диспатча во время рендера (dump_dispatch.py): содержимое
|
||||
СТАБИЛЬНО и совпадает со статикой; idx=4 валиден. Entry[4] bigkernel'ов
|
||||
→ second-level thunks (141880 и со.) → IAT-слоты ВНЕ дампа ⇒ тела
|
||||
bigkernel'ов = ИМПОРТИРОВАННЫЕ функции (UCRT/хост-DLL).
|
||||
Инструмент iat_name.py читает рантайм-IAT и парсит PE-экспорты
|
||||
владельца-модуля — первый прогон дал мусор из-за гонки с завершением
|
||||
рендера (host умирает ~7 c); требует чтения ДО завершения или фиксации
|
||||
процесса SIGSTOP на время разбора.
|
||||
Как только имена получены (ожидаемо expf/powf/log10f класс), семантика
|
||||
bigkernel'ов замыкается, и полный каскадный симулятор шагов 9–19+FIR
|
||||
становится реализуемым без дальнейшей археологии.
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
#!/usr/bin/env python3
|
||||
"""dump_dispatch.py — dump dispatch tables of bigkernel stubs at runtime.
|
||||
Stubs of interest (from FIR loop / steps 14,17):
|
||||
1409e0 -> table@182617508 ; 140ad0 -> ? ; 140b30 -> table@1826176c8
|
||||
Nested stub inside 140a00: idx cell/table computed below.
|
||||
Dumps tables pre-render (static) and during render (runtime-patched).
|
||||
"""
|
||||
import struct, subprocess, sys, time
|
||||
import glob, os
|
||||
|
||||
BASE = 0x180000000
|
||||
data = open('/home/m/re-tools/soothe_mem.bin','rb').read()
|
||||
|
||||
def find_host():
|
||||
for p in glob.glob('/proc/[0-9]*'):
|
||||
pid=int(os.path.basename(p))
|
||||
try:
|
||||
cmd=open(f'/proc/{pid}/cmdline','rb').read().replace(b'\0',b' ').decode('utf8','replace')
|
||||
maps=open(f'/proc/{pid}/maps').read()
|
||||
except Exception: continue
|
||||
if 'soothe2' in maps and 'reaper' not in cmd: return pid
|
||||
return None
|
||||
|
||||
def rd(a,n):
|
||||
try: return os.pread(fd,n,a)
|
||||
except OSError: return None
|
||||
|
||||
subprocess.run("pkill -9 -x reaper; pkill -9 -f '[y]abridge'; "
|
||||
"rm -rf /run/user/1000/yabridge-soothe2_x64-*; sleep 1", shell=True)
|
||||
rpp=sys.argv[1] if len(sys.argv)>1 else '/tmp/opencode/multi.rpp'
|
||||
proc=subprocess.Popen(['/usr/bin/reaper','-nosplash','-ignoreerrors','-renderproject',rpp],
|
||||
stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
|
||||
t0=time.time(); host=None
|
||||
while time.time()-t0<30 and not host:
|
||||
host=find_host(); time.sleep(0.002)
|
||||
print('host',host,flush=True)
|
||||
if not host: sys.exit(1)
|
||||
fd=os.open(f'/proc/{host}/mem',os.O_RDONLY)
|
||||
|
||||
TABLES={'bk140b30':0x1826176c8,'bk140b60':0x182617708,'bk1409e0':0x182617508,
|
||||
'bk140ad0':None,'bk140a40':0x182617588}
|
||||
# find bk140ad0 table: stub 140ad0 pattern movsxd rax,[rip+X]; lea r10,[rip+Y]
|
||||
off=0x180140ad0-BASE
|
||||
b=data[off:off+16]
|
||||
rel1=struct.unpack('<i',b[3:7])[0]
|
||||
rel2=struct.unpack('<i',b[10:14])[0]
|
||||
idx_a=0x180140ad0+7+rel1
|
||||
tbl_a=0x180140ad0+14+rel2
|
||||
TABLES['bk140ad0']=tbl_a
|
||||
print('bk140ad0 idx@%x tbl@%x' % (idx_a,tbl_a),flush=True)
|
||||
|
||||
def dump_tables(tag):
|
||||
print(tag,'fd=',fd,flush=True)
|
||||
for nm,t in TABLES.items():
|
||||
b=rd(t,64)
|
||||
if b is None:
|
||||
import errno
|
||||
print('%s %s unreadable err=%s'%(tag,nm,os.strerror(errno.EIO))); continue
|
||||
vals=struct.unpack('<%dQ'%(len(b)//8),b[:len(b)//8*8])
|
||||
nz=[(i,hex(v)) for i,v in enumerate(vals) if v]
|
||||
print('%s %-9s: %s' % (tag,nm,nz), flush=True)
|
||||
|
||||
# also nested stub inside 140a00 (static parse):
|
||||
off=0x140a10-BASE
|
||||
b1=data[off:off+7]
|
||||
if b1[:3]==b'\x48\x63\x05':
|
||||
rel=struct.unpack('<i',b1[3:7])[0]
|
||||
icell=0x180140a10+7+rel
|
||||
b2=data[icell-BASE:4]
|
||||
print('nested idx cell @%x static=%d' % (icell, struct.unpack('<i',b2)[0]),flush=True)
|
||||
|
||||
for k in range(30):
|
||||
dump_tables('R%d'%k)
|
||||
time.sleep(0.15)
|
||||
try:
|
||||
os.kill(proc.pid,0)
|
||||
except ProcessLookupError:
|
||||
break
|
||||
os.close(fd)
|
||||
@@ -0,0 +1,117 @@
|
||||
#!/usr/bin/env python3
|
||||
"""iat_name.py — resolve imported-function names for bigkernel dispatch targets.
|
||||
Reads runtime IAT values, finds owning module, parses PE exports."""
|
||||
import struct, subprocess, sys, time
|
||||
import glob, os
|
||||
|
||||
BASE=0x180000000
|
||||
data=open('/home/m/re-tools/soothe_mem.bin','rb').read()
|
||||
|
||||
def rd(fd,a,n):
|
||||
try: return os.pread(fd,n,a)
|
||||
except OSError: return None
|
||||
|
||||
def find_host():
|
||||
for p in glob.glob('/proc/[0-9]*'):
|
||||
pid=int(os.path.basename(p))
|
||||
try:
|
||||
cmd=open('/proc/%d/cmdline'%pid,'rb').read().replace(b'\0',b' ').decode('utf8','replace')
|
||||
maps=open('/proc/%d/maps'%pid).read()
|
||||
except Exception: continue
|
||||
if 'soothe2' in maps and 'reaper' not in cmd: return pid
|
||||
return None
|
||||
|
||||
def iat_slot(stub):
|
||||
# pattern: mov rax,[rip+rel] (48 8b 05 rel32)
|
||||
off=stub-BASE
|
||||
b=data[off:off+7]
|
||||
if b[:2]!=b'\x48\x8b': return None
|
||||
rel=struct.unpack('<i',b[2:6])[0]
|
||||
return stub+6+rel
|
||||
|
||||
def pe_exports(path):
|
||||
"""Parse PE export table -> {name: rva}"""
|
||||
try:
|
||||
f=open(path,'rb').read()
|
||||
except Exception:
|
||||
return {}
|
||||
if f[:2]!=b'MZ': return {}
|
||||
pe=struct.unpack('<I',f[0x3c:0x40])[0]
|
||||
if f[pe:pe+4]!=b'PE\0\0': return {}
|
||||
nsec=struct.unpack('<H',f[pe+6:pe+8])[0]
|
||||
optsz=struct.unpack('<H',f[pe+20:pe+22])[0]
|
||||
magic=struct.unpack('<H',f[pe+24:pe+26])[0]
|
||||
ddir=pe+24+(0x70 if magic==0x20b else 0x60)+0*8 # data dir[0]=export
|
||||
exp_rva,exp_sz=struct.unpack('<II',f[ddir:ddir+8])
|
||||
if not exp_rva: return {}
|
||||
# sections
|
||||
secs=[]
|
||||
so=pe+24+optsz
|
||||
for i in range(nsec):
|
||||
s=f[so+i*40:so+i*40+40]
|
||||
va,sz=struct.unpack('<II',s[12:20])
|
||||
raw,rsz=struct.unpack('<II',s[20:28])
|
||||
secs.append((va,sz,raw,rsz))
|
||||
def r2o(rva):
|
||||
for va,sz,raw,rsz in secs:
|
||||
if va<=rva<va+max(sz,rsz): return raw+(rva-va)
|
||||
return None
|
||||
eo=r2o(exp_rva)
|
||||
if eo is None: return {}
|
||||
nnames=struct.unpack('<I',f[eo+24:eo+28])[0]
|
||||
nrva=struct.unpack('<I',f[eo+32:eo+36])[0]
|
||||
names_rva=struct.unpack('<I',f[eo+32+4:eo+32+8])[0]
|
||||
funcs_rva=struct.unpack('<I',f[eo+28:eo+32])[0]
|
||||
no=r2o(names_rva); fo=r2o(funcs_rva)
|
||||
out={}
|
||||
if no is None or fo is None: return {}
|
||||
for i in range(nnames):
|
||||
nrva_i=struct.unpack('<I',f[no+i*4:no+i*4+4])[0]
|
||||
noff=r2o(nrva_i)
|
||||
if noff is None: continue
|
||||
end=f.find(b'\0',noff)
|
||||
nm=f[noff:end].decode('ascii','replace')
|
||||
frva=struct.unpack('<I',f[fo+i*4:fo+i*4+4])[0]
|
||||
out[nm]=frva
|
||||
return out
|
||||
|
||||
subprocess.run("pkill -9 -x reaper; pkill -9 -f '[y]abridge'; "
|
||||
"rm -rf /run/user/1000/yabridge-soothe2_x64-*; sleep 1", shell=True)
|
||||
proc=subprocess.Popen(['/usr/bin/reaper','-nosplash','-ignoreerrors','-renderproject','/tmp/opencode/multi.rpp'],
|
||||
stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
|
||||
t0=time.time(); host=None
|
||||
while time.time()-t0<30 and not host:
|
||||
host=find_host(); time.sleep(0.002)
|
||||
print('host',host,flush=True)
|
||||
fd=os.open('/proc/%d/mem'%host,os.O_RDONLY)
|
||||
|
||||
# build module map
|
||||
mods=[]
|
||||
for line in open('/proc/%d/maps'%host):
|
||||
parts=line.split()
|
||||
if len(parts)<6 or 'x' not in parts[1]: continue
|
||||
lo,hi=(int(x,16) for x in parts[0].split('-'))
|
||||
mods.append((lo,hi,parts[5]))
|
||||
print('modules:',len(mods))
|
||||
|
||||
def owner(addr):
|
||||
for lo,hi,path in mods:
|
||||
if lo<=addr<hi: return (lo,addr-lo,path)
|
||||
return None
|
||||
|
||||
targets={}
|
||||
for stub in (0x180140b30,0x180140b60,0x1801409e0,0x180140ad0,0x180140a40):
|
||||
off=stub-BASE
|
||||
b=data[off:off+7]
|
||||
rel=struct.unpack('<i',b[3:7])[0]
|
||||
tbl=stub+14+rel
|
||||
v=rd(fd,tbl+4*8,8)
|
||||
tgt=struct.unpack('<Q',v)[0] if v else 0
|
||||
ow=owner(tgt)
|
||||
print('%x idx4->%x runtime=%x owner=%s' % (stub,tbl,tgt,ow[2] if ow else '?'),flush=True)
|
||||
if ow:
|
||||
lo,rva,path=ow
|
||||
exps=pe_exports(path)
|
||||
best=[nm for nm,r in exps.items() if r==rva]
|
||||
print(' export:',best,flush=True)
|
||||
os.close(fd)
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
import struct, subprocess, time, os, glob
|
||||
def find_host():
|
||||
for p in glob.glob('/proc/[0-9]*'):
|
||||
pid=int(os.path.basename(p))
|
||||
try:
|
||||
cmd=open('/proc/%d/cmdline'%pid,'rb').read().replace(b'\0',b' ').decode('utf8','replace')
|
||||
maps=open('/proc/%d/maps'%pid).read()
|
||||
except Exception: continue
|
||||
if 'soothe2' in maps and 'reaper' not in cmd: return pid
|
||||
return None
|
||||
subprocess.run("pkill -9 -x reaper; pkill -9 -f '[y]abridge'; sleep 1; "
|
||||
"rm -rf /run/user/1000/yabridge-soothe2_x64-*", shell=True)
|
||||
proc=subprocess.Popen(['/usr/bin/reaper','-nosplash','-ignoreerrors','-renderproject','/tmp/opencode/multi.rpp'],
|
||||
stdout=subprocess.DEVNULL,stderr=subprocess.STDOUT)
|
||||
t0=time.time();host=None
|
||||
while time.time()-t0<30 and not host: host=find_host();time.sleep(0.002)
|
||||
print('host',host)
|
||||
fd=os.open('/proc/%d/mem'%host,os.O_RDONLY)
|
||||
for addr,nm in ((0x1824ac210,'vtbl'),(0x182617508,'bk-table'),(0x180140ad0,'stub-code'),(0x180533340,'iir-gen')):
|
||||
try:
|
||||
b=os.pread(fd,16,addr)
|
||||
print('%-10s %x OK: %s' % (nm,addr,b[:8].hex()))
|
||||
except OSError as e:
|
||||
print('%-10s %x FAIL: %s' % (nm,addr,e))
|
||||
Reference in New Issue
Block a user