diff --git a/handoff/NOTES_LEVEL.md b/handoff/NOTES_LEVEL.md index 4b70188..c058bbf 100644 --- a/handoff/NOTES_LEVEL.md +++ b/handoff/NOTES_LEVEL.md @@ -2412,3 +2412,13 @@ t_{-24,-12,0,+24}.rpp (тон@1000, бин 85): scr85 = −1.0071 / −0.2276 / 2. Проверить 0x18052e1c0/0x180534580 дизасмом (уже лежат окна? нет — снять). 3. После опознания дубля: bp на его выход → [rsp]=адрес применения → декод масштаба 1.805. + +### 23i (короткое): HW-watchpoint заведён, попаданий нет +Отладочные регистры через POKEUSER: база u_debugreg = **0x350** (не 0x340/0x380; +DR7 @0x388; LEN=10(8B) отвергается ядром — использовать LEN=11(4B), +DR7=L0|R/W=11|LEN=11 = 0xF0001; сброс DR6 = poke 0xFFFF0FF0 @DR0+48). +scripts/fnwatch.py: watch на слово кернела (bin43.re) от момента создания +экземпляра до конца хоста — **0 попаданий** при подтверждённом армировании. +Гипотезы: потребитель читает КОПИЮ кернела; либо строится однократно до +армирования; либо выравнивание доступа мимо слова. Следующий шаг: watch +нескольких слов + старт с рождения хоста + контроль факта рендера (wav mtime). diff --git a/handoff/nls_dasm/hot_52e1c0.dis b/handoff/nls_dasm/hot_52e1c0.dis new file mode 100644 index 0000000..1d8e210 --- /dev/null +++ b/handoff/nls_dasm/hot_52e1c0.dis @@ -0,0 +1,69 @@ +; hot_52e1c0 + +/tmp/slice.bin: file format binary + + +Disassembly of section .data: + +000000018052e1c0 <.data>: + 18052e1c0: 05 e8 fa 2e ad add $0xad2efae8,%eax + 18052e1c5: ff 85 f6 48 89 1f incl 0x1f8948f6(%rbp) + 18052e1cb: 0f 48 f3 cmovs %ebx,%esi + 18052e1ce: 89 77 08 mov %esi,0x8(%rdi) + 18052e1d1: 85 f6 test %esi,%esi + 18052e1d3: 74 2f je 0x18052e204 + 18052e1d5: 8d 0c b5 00 00 00 00 lea 0x0(,%rsi,4),%ecx + 18052e1dc: e8 9f 2e ad ff call 0x180001080 + 18052e1e1: 48 89 07 mov %rax,(%rdi) + 18052e1e4: 39 5f 08 cmp %ebx,0x8(%rdi) + 18052e1e7: 7e 1b jle 0x18052e204 + 18052e1e9: 48 8b cb mov %rbx,%rcx + 18052e1ec: 0f 1f 40 00 nopl 0x0(%rax) + 18052e1f0: 48 8b 07 mov (%rdi),%rax + 18052e1f3: 48 8d 49 04 lea 0x4(%rcx),%rcx + 18052e1f7: ff c3 inc %ebx + 18052e1f9: f3 0f 11 74 01 fc movss %xmm6,-0x4(%rcx,%rax,1) + 18052e1ff: 3b 5f 08 cmp 0x8(%rdi),%ebx + 18052e202: 7c ec jl 0x18052e1f0 + 18052e204: 48 8b 5c 24 40 mov 0x40(%rsp),%rbx + 18052e209: 48 8b 74 24 48 mov 0x48(%rsp),%rsi + 18052e20e: 0f 28 74 24 20 movaps 0x20(%rsp),%xmm6 + 18052e213: 48 83 c4 30 add $0x30,%rsp + 18052e217: 5f pop %rdi + 18052e218: c3 ret + 18052e219: cc int3 + 18052e21a: cc int3 + 18052e21b: cc int3 + 18052e21c: cc int3 + 18052e21d: cc int3 + 18052e21e: cc int3 + 18052e21f: cc int3 + 18052e220: 40 53 rex push %rbx + 18052e222: 48 83 ec 20 sub $0x20,%rsp + 18052e226: 83 79 08 00 cmpl $0x0,0x8(%rcx) + 18052e22a: 48 8b d9 mov %rcx,%rbx + 18052e22d: 7e 1b jle 0x18052e24a + 18052e22f: 48 8b 09 mov (%rcx),%rcx + 18052e232: 48 85 c9 test %rcx,%rcx + 18052e235: 74 05 je 0x18052e23c + 18052e237: e8 84 2e ad ff call 0x1800010c0 + 18052e23c: 33 c0 xor %eax,%eax + 18052e23e: 48 89 03 mov %rax,(%rbx) + 18052e241: 89 43 08 mov %eax,0x8(%rbx) + 18052e244: 48 83 c4 20 add $0x20,%rsp + 18052e248: 5b pop %rbx + 18052e249: c3 ret + 18052e24a: 33 c0 xor %eax,%eax + 18052e24c: 48 89 01 mov %rax,(%rcx) + 18052e24f: 89 41 08 mov %eax,0x8(%rcx) + 18052e252: 48 83 c4 20 add $0x20,%rsp + 18052e256: 5b pop %rbx + 18052e257: c3 ret + 18052e258: cc int3 + 18052e259: cc int3 + 18052e25a: cc int3 + 18052e25b: cc int3 + 18052e25c: cc int3 + 18052e25d: cc int3 + 18052e25e: cc int3 + 18052e25f: cc int3 diff --git a/handoff/nls_dasm/hot_534580.dis b/handoff/nls_dasm/hot_534580.dis new file mode 100644 index 0000000..8274b44 --- /dev/null +++ b/handoff/nls_dasm/hot_534580.dis @@ -0,0 +1,198 @@ + +/tmp/slice.bin: file format binary + + +Disassembly of section .data: + +0000000180534580 <.data>: + 180534580: 48 89 1f mov %rbx,(%rdi) + 180534583: 0f 48 f3 cmovs %ebx,%esi + 180534586: 89 77 08 mov %esi,0x8(%rdi) + 180534589: 85 f6 test %esi,%esi + 18053458b: 74 26 je 0x1805345b3 + 18053458d: 8b ce mov %esi,%ecx + 18053458f: e8 ec ca ac ff call 0x180001080 + 180534594: 48 89 07 mov %rax,(%rdi) + 180534597: 39 5f 08 cmp %ebx,0x8(%rdi) + 18053459a: 7e 17 jle 0x1805345b3 + 18053459c: 48 8b cb mov %rbx,%rcx + 18053459f: 90 nop + 1805345a0: 48 8b 07 mov (%rdi),%rax + 1805345a3: 48 8d 49 01 lea 0x1(%rcx),%rcx + 1805345a7: ff c3 inc %ebx + 1805345a9: c6 44 01 ff 00 movb $0x0,-0x1(%rcx,%rax,1) + 1805345ae: 3b 5f 08 cmp 0x8(%rdi),%ebx + 1805345b1: 7c ed jl 0x1805345a0 + 1805345b3: 48 8b 5c 24 30 mov 0x30(%rsp),%rbx + 1805345b8: 48 8b 74 24 38 mov 0x38(%rsp),%rsi + 1805345bd: 48 83 c4 20 add $0x20,%rsp + 1805345c1: 5f pop %rdi + 1805345c2: c3 ret + 1805345c3: cc int3 + 1805345c4: cc int3 + 1805345c5: cc int3 + 1805345c6: cc int3 + 1805345c7: cc int3 + 1805345c8: cc int3 + 1805345c9: cc int3 + 1805345ca: cc int3 + 1805345cb: cc int3 + 1805345cc: cc int3 + 1805345cd: cc int3 + 1805345ce: cc int3 + 1805345cf: cc int3 + 1805345d0: 40 53 rex push %rbx + 1805345d2: 48 83 ec 40 sub $0x40,%rsp + 1805345d6: 48 c7 44 24 30 fe ff movq $0xfffffffffffffffe,0x30(%rsp) + 1805345dd: ff ff + 1805345df: 48 8b d9 mov %rcx,%rbx + 1805345e2: 48 8d 05 c7 ce f3 ff lea -0xc3139(%rip),%rax # 0x1804714b0 + 1805345e9: 48 89 44 24 20 mov %rax,0x20(%rsp) + 1805345ee: 4c 8d 0d 8b 00 00 00 lea 0x8b(%rip),%r9 # 0x180534680 + 1805345f5: ba 80 00 00 00 mov $0x80,%edx + 1805345fa: 44 8d 42 90 lea -0x70(%rdx),%r8d + 1805345fe: e8 01 d6 bf 00 call 0x181131c04 + 180534603: 90 nop + 180534604: c7 83 00 08 00 00 08 movl $0x8,0x800(%rbx) + 18053460b: 00 00 00 + 18053460e: 48 c7 83 04 08 00 00 movq $0x447a0000,0x804(%rbx) + 180534615: 00 00 7a 44 + 180534619: c7 83 0c 08 00 00 f4 movl $0x3f34fdf4,0x80c(%rbx) + 180534620: fd 34 3f + 180534623: c6 83 10 08 00 00 00 movb $0x0,0x810(%rbx) + 18053462a: c7 83 14 08 00 00 01 movl $0x1,0x814(%rbx) + 180534631: 00 00 00 + 180534634: 33 c0 xor %eax,%eax + 180534636: 48 89 83 18 08 00 00 mov %rax,0x818(%rbx) + 18053463d: 48 89 83 20 08 00 00 mov %rax,0x820(%rbx) + 180534644: 48 8b c3 mov %rbx,%rax + 180534647: 48 83 c4 40 add $0x40,%rsp + 18053464b: 5b pop %rbx + 18053464c: c3 ret + 18053464d: cc int3 + 18053464e: cc int3 + 18053464f: cc int3 + 180534650: 48 83 ec 38 sub $0x38,%rsp + 180534654: 48 c7 44 24 20 fe ff movq $0xfffffffffffffffe,0x20(%rsp) + 18053465b: ff ff + 18053465d: 4c 8d 0d 4c ce f3 ff lea -0xc31b4(%rip),%r9 # 0x1804714b0 + 180534664: ba 80 00 00 00 mov $0x80,%edx + 180534669: 44 8d 42 90 lea -0x70(%rdx),%r8d + 18053466d: e8 aa d0 bf 00 call 0x18113171c + 180534672: 90 nop + 180534673: 48 83 c4 38 add $0x38,%rsp + 180534677: c3 ret + 180534678: cc int3 + 180534679: cc int3 + 18053467a: cc int3 + 18053467b: cc int3 + 18053467c: cc int3 + 18053467d: cc int3 + 18053467e: cc int3 + 18053467f: cc int3 + 180534680: 48 83 ec 28 sub $0x28,%rsp + 180534684: e8 a7 00 00 00 call 0x180534730 + 180534689: 4c 8b 19 mov (%rcx),%r11 + 18053468c: 48 ba 00 00 00 00 00 movabs $0x3ff0000000000000,%rdx + 180534693: 00 f0 3f + 180534696: 49 89 13 mov %rdx,(%r11) + 180534699: 48 8b 41 08 mov 0x8(%rcx),%rax + 18053469d: 48 89 10 mov %rdx,(%rax) + 1805346a0: 48 8b c1 mov %rcx,%rax + 1805346a3: 48 83 c4 28 add $0x28,%rsp + 1805346a7: c3 ret + 1805346a8: cc int3 + 1805346a9: cc int3 + 1805346aa: cc int3 + 1805346ab: cc int3 + 1805346ac: cc int3 + 1805346ad: cc int3 + 1805346ae: cc int3 + 1805346af: cc int3 + 1805346b0: 48 89 5c 24 08 mov %rbx,0x8(%rsp) + 1805346b5: 48 89 74 24 10 mov %rsi,0x10(%rsp) + 1805346ba: 57 push %rdi + 1805346bb: 48 83 ec 20 sub $0x20,%rsp + 1805346bf: 48 8b d9 mov %rcx,%rbx + 1805346c2: 8b f2 mov %edx,%esi + 1805346c4: 48 83 c1 60 add $0x60,%rcx + 1805346c8: e8 a3 11 d7 00 call 0x1812a5870 + 1805346cd: 48 8d 05 64 7f f7 01 lea 0x1f77f64(%rip),%rax # 0x1824ac638 + 1805346d4: 48 89 03 mov %rax,(%rbx) + 1805346d7: 48 8b 4b 48 mov 0x48(%rbx),%rcx + 1805346db: c7 43 54 00 00 00 00 movl $0x0,0x54(%rbx) + 1805346e2: ff 15 c0 6b 67 01 call *0x1676bc0(%rip) # 0x181bab2a8 + 1805346e8: 48 8b 7b 08 mov 0x8(%rbx),%rdi + 1805346ec: 48 85 ff test %rdi,%rdi + 1805346ef: 74 17 je 0x180534708 + 1805346f1: 48 8b 4f 18 mov 0x18(%rdi),%rcx + 1805346f5: ff 15 ad 6b 67 01 call *0x1676bad(%rip) # 0x181bab2a8 + 1805346fb: ba 28 01 00 00 mov $0x128,%edx + 180534700: 48 8b cf mov %rdi,%rcx + 180534703: e8 ec c9 bf 00 call 0x1811310f4 + 180534708: 40 f6 c6 01 test $0x1,%sil + 18053470c: 74 0d je 0x18053471b + 18053470e: ba e0 00 00 00 mov $0xe0,%edx + 180534713: 48 8b cb mov %rbx,%rcx + 180534716: e8 d9 c9 bf 00 call 0x1811310f4 + 18053471b: 48 8b 74 24 38 mov 0x38(%rsp),%rsi + 180534720: 48 8b c3 mov %rbx,%rax + 180534723: 48 8b 5c 24 30 mov 0x30(%rsp),%rbx + 180534728: 48 83 c4 20 add $0x20,%rsp + 18053472c: 5f pop %rdi + 18053472d: c3 ret + 18053472e: cc int3 + 18053472f: cc int3 + 180534730: 4c 8d 41 18 lea 0x18(%rcx),%r8 + 180534734: c7 41 10 03 00 00 00 movl $0x3,0x10(%rcx) + 18053473b: 49 8b c0 mov %r8,%rax + 18053473e: 4c 89 01 mov %r8,(%rcx) + 180534741: 0f 57 c9 xorps %xmm1,%xmm1 + 180534744: c6 41 78 01 movb $0x1,0x78(%rcx) + 180534748: 48 83 c0 10 add $0x10,%rax + 18053474c: f2 0f 11 4c 24 08 movsd %xmm1,0x8(%rsp) + 180534752: f2 0f 10 44 24 08 movsd 0x8(%rsp),%xmm0 + 180534758: 48 8d 51 30 lea 0x30(%rcx),%rdx + 18053475c: 48 89 51 08 mov %rdx,0x8(%rcx) + 180534760: 66 0f c6 c0 00 shufpd $0x0,%xmm0,%xmm0 + 180534765: 41 f6 c0 0f test $0xf,%r8b + 180534769: 75 06 jne 0x180534771 + 18053476b: 41 0f 11 00 movups %xmm0,(%r8) + 18053476f: eb 0f jmp 0x180534780 + 180534771: 41 0f 11 00 movups %xmm0,(%r8) + 180534775: 66 66 66 0f 1f 84 00 data16 data16 nopw 0x0(%rax,%rax,1) + 18053477c: 00 00 00 00 + 180534780: 45 33 c9 xor %r9d,%r9d + 180534783: f2 0f 11 4c 24 08 movsd %xmm1,0x8(%rsp) + 180534789: f2 0f 10 44 24 08 movsd 0x8(%rsp),%xmm0 + 18053478f: 4c 89 08 mov %r9,(%rax) + 180534792: 48 8b c2 mov %rdx,%rax + 180534795: 48 83 c0 10 add $0x10,%rax + 180534799: 66 0f c6 c0 00 shufpd $0x0,%xmm0,%xmm0 + 18053479e: f6 c2 0f test $0xf,%dl + 1805347a1: 75 05 jne 0x1805347a8 + 1805347a3: 0f 11 02 movups %xmm0,(%rdx) + 1805347a6: eb 08 jmp 0x1805347b0 + 1805347a8: 0f 11 02 movups %xmm0,(%rdx) + 1805347ab: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1) + 1805347b0: 4c 89 08 mov %r9,(%rax) + 1805347b3: 49 ba 00 00 00 00 00 movabs $0x3ff0000000000000,%r10 + 1805347ba: 00 f0 3f + 1805347bd: 4d 89 10 mov %r10,(%r8) + 1805347c0: 4c 8d 41 48 lea 0x48(%rcx),%r8 + 1805347c4: 49 8b c0 mov %r8,%rax + 1805347c7: f2 0f 11 4c 24 08 movsd %xmm1,0x8(%rsp) + 1805347cd: f2 0f 10 44 24 08 movsd 0x8(%rsp),%xmm0 + 1805347d3: 48 83 c0 10 add $0x10,%rax + 1805347d7: 4c 89 12 mov %r10,(%rdx) + 1805347da: 66 0f c6 c0 00 shufpd $0x0,%xmm0,%xmm0 + 1805347df: 41 f6 c0 0f test $0xf,%r8b + 1805347e3: 75 06 jne 0x1805347eb + 1805347e5: 41 0f 11 00 movups %xmm0,(%r8) + 1805347e9: eb 05 jmp 0x1805347f0 + 1805347eb: 41 0f 11 00 movups %xmm0,(%r8) + 1805347ef: 90 nop + 1805347f0: 48 8d 51 60 lea 0x60(%rcx),%rdx + 1805347f4: 4c 89 08 mov %r9,(%rax) + 1805347f7: 48 8b c2 mov %rdx,%rax + 1805347fa: f2 0f 11 4c 24 08 movsd %xmm1,0x8(%rsp) diff --git a/scripts/fnwatch.py b/scripts/fnwatch.py new file mode 100644 index 0000000..f9510ea --- /dev/null +++ b/scripts/fnwatch.py @@ -0,0 +1,234 @@ +#!/usr/bin/env python3 +"""fnwatch.py — hardware data-watchpoint (DR0 RW) on the live FIR kernel word. +Catches whoever READS the built kernel during offline render -> consumer RIP.""" +import ctypes +import glob +import os +import signal +import struct +import subprocess +import sys +import time + +DUR = float(os.environ.get('WATCH_DUR', '20')) +BIN = '/home/m/re-tools/soothe_mem.bin' +BASE = 0x180000000 + +PTRACE_CONT = 7 +PTRACE_GETREGS = 12 +PTRACE_SETREGS = 13 +PTRACE_PEEKUSER = 3 +PTRACE_POKEUSER = 6 +PTRACE_SINGLESTEP = 9 +PTRACE_SEIZE = 0x4206 +PTRACE_INTERRUPT = 0x4207 +PTRACE_O_TRACECLONE = 2 + +DR0_OFF = 0x350 # empirically verified debugreg base +DR7_OFF = DR0_OFF + 56 # 0x388 +DR7_VAL = 0x000F0001 # L0=1, R/W0=11 (rd/wr), LEN0=11 (4 bytes) + +libc = ctypes.CDLL('libc.so.6', use_errno=True) +_mod = open(BIN, 'rb').read() + + +class UserRegs(ctypes.Structure): + _fields_ = [(n, ctypes.c_ulonglong) for n in ( + 'r15', 'r14', 'r13', 'r12', 'rbp', 'rbx', 'r11', 'r10', + 'r9', 'r8', 'rax', 'rcx', 'rdx', 'rsi', 'rdi', 'orig_rax', + 'rip', 'cs', 'eflags', 'rsp', 'ss', 'fs_base', 'gs_base', + 'ds', 'es', 'fs', 'gs')] + + +def pt(req, pid, addr=0, data=0): + libc.ptrace.restype = ctypes.c_long + r = libc.ptrace(req, pid, ctypes.c_void_p(addr), ctypes.c_void_p(data)) + return None if r == -1 else r + + +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 main(): + 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', '/home/m/soothe-bt/dual_b1q_0.5.rpp'], + stdout=open('/dev/null', 'w'), stderr=subprocess.STDOUT) + host = None + t0 = time.time() + while time.time() - t0 < 30 and not host: + host = find_host() + time.sleep(0.002) + if not host: + print('NO HOST') + return 1 + + fd = os.open(f'/proc/{host}/mem', os.O_RDONLY) + + def rd(a, n): + try: + return os.pread(fd, n, a) + except OSError: + return None + + # find ctx & FIR ptr while running (poll till instance exists) + ctx = firptr = None + vt = struct.pack('= 0: + cand = a + j + sb = rd(cand + 0x540870, 4) + if sb and struct.unpack(' 100: + ctx = cand + qb = rd(cand + 0x540668, 8) + firptr = struct.unpack(' r=%s read=%#x' % (off, 'ok' if r is not None else 'EIO', v or 0), flush=True) + + def arm(tid): + pt(PTRACE_POKEUSER, tid, DR0_OFF, firptr + 43 * 8) # bin43 re (hot word) + pt(PTRACE_POKEUSER, tid, DR7_OFF, DR7_VAL) + v = pt(PTRACE_PEEKUSER, tid, DR7_OFF) + # bit10 of DR7 reads as always-1 (RA1) + return v is not None and (v & ~0x400) == (DR7_VAL & ~0x400) + + # stop host briefly to verify arming works at all + pt(PTRACE_INTERRUPT, host) + for _ in range(50): + try: + pid, st = os.waitpid(host, os.WUNTRACED | os.WNOHANG) + except ChildProcessError: + break + if pid == host: + break + time.sleep(0.002) + arm_dbg(host) + ok = arm(host) + print('arm check (stopped):', ok, flush=True) + pt(PTRACE_CONT, host, 0, 0) + + if ok: + armed.add(host) + + hits = [] + t_end = time.time() + DUR + last_sweep = 0.0 + while time.time() < t_end: + now = time.time() + if now - last_sweep > 0.03: + last_sweep = now + for tid_s in glob.glob(f'/proc/{host}/task/*'): + tid = int(os.path.basename(tid_s)) + if tid not in seized: + if pt(PTRACE_SEIZE, tid, 0, 0) is not None: + seized.add(tid) + if tid not in armed: + pt(PTRACE_INTERRUPT, tid) + for _ in range(40): + try: + pid, st = os.waitpid(tid, os.WUNTRACED | os.WNOHANG) + except ChildProcessError: + break + if pid == tid: + break + time.sleep(0.001) + if arm(tid): + armed.add(tid) + try: + pt(PTRACE_CONT, tid, 0, 0) + except OSError: + pass + try: + pid, status = os.waitpid(-1, os.WSTOPPED | os.WNOHANG) + except ChildProcessError: + break + if pid == 0: + time.sleep(0.0005) + continue + sig = status >> 8 + if os.WIFEXITED(status) or os.WIFSIGNALED(status): + continue + if os.WIFSTOPPED(pid) and sig == signal.SIGTRAP: + regs = UserRegs() + if pt(PTRACE_GETREGS, pid, 0, ctypes.addressof(regs)) is None: + continue + rec = dict(rip=regs.rip, rsp=regs.rsp, tid=pid, + ret=struct.unpack('