Visual injection on the running VT1200 OS -- key numbers ========================================================= ROM md5 b46a3e442ccb86134d2356bd70d22fd2 (unchanged). No driver edits. OS path: VT1200_SKIP_LEVEL1=1 (documented divergence), private -nvram_directory, rdebug over TCP 771 with the computed challenge (dwt/solve.py chain). 1. `jump` is a call and returns; the OS stays alive --------------------------------------------------- dwt/visual/build/ret_test.bin = 30 bytes, linked at bit 01840000h. Step1 log: dwt/evidence/visual/step1_ret_test.log jump 0x01840000: returned 0x00000000 after-peek 0x01850000 -> de c0 07 b0 (0xC0DE, 0xB007) post-jump opcode 7 -> Done second connection at frame 3526: opcode 7 -> Done; markers still de c0 07 b0 Frame at 3500 (step1_alive_3500.png) is the live Terminal Manager. So the loader is a real call: stack/return are intact, and the TCP session is usable before and after. 2. Static VRAM draw lands, but the OS repaints it -------------------------------------------------- drawal.bin: three word-aligned black 32x32 boxes at (48,48), (256,400), (928,752). Client log: dwt/evidence/visual/static_draw_client.log after-peek 0x0400C030 (64) -> 00 00 00 00 ff ff ... (the writes are in VRAM) jump returned; TCP Done; markers D2A0/B0C0. Frames 3420 (before) and 3430 (after) are byte-identical (static_before_3420.png / static_after_3430.png; md5 e98b9b4a38 both), and the box regions do not change in any of 3420..3600. The OS repaints before the next scanout. Control (CPU frozen after the same draw): control_spin_box_3480.png shows the black box, and the hello-world 256x64 block appears (control_hello_3480.png), so the coordinates/renderer mapping are right. 3. Resident display-interrupt hook ---------------------------------- DI vector: RLONG(0xFFFFFEA0) = 00000DB0h. RAM stub there is 6 bytes: 80 c0 d0 46 71 3f = JA 3F7146D0h (stock OS display handler) install rewrites the 32-bit target only: 80 c0 90 01 84 01 = JA 01840190h (our entry) (both read from dwt/evidence/visual/live/runpc/vt1200-ram-3440.bin; the dump itself is not committed -- see di_one_shot_state.log for the same stub read through the running system.) (a) draw before the stock handler: handler runs (counter 0x0A,0x62,...), but no box ever appears -- the handler repaints after the draw. (b) return-PC trampoline (draw after the handler's `reti`): visible blink. Payload `dwt/visual/build/blinkev.bin` (252 bytes; the post-handler trampoline with scratch at 01840800h). Two runs: run A (blink_resident_client.log), frames 15: frame 3450 box region 56.2% lit (black box ON) frame 3480 box region 100.0% (box OFF, white body) frame 3500 box region 56.2% (box ON again) TCP answered at 3450 and at 3500 (post-jump opcode 7 -> Done). run B (blink_repeat_client.log), frames live3, 5-frame dumps: 3440/3450 OFF, 3455..3520 ON (10-frame pairs): blink2_off_3450.png, blink2_on_3460.png, blink2_on_3500.png. The install returned and its post-jump opcode 7 -> Done, but a new connection at 3450 got the challenge then timed out, and by 3470 the terminal's IP stack was gone ("No route to host"). So the blink is reproducible, TCP survival is flaky. LIMIT: only the first trampoline entry draws. The stock handler's full path (0x3F579880) stops returning through the patched saved PC; the counter sticks at 1 (di_one_shot_state.log). So this is a real but short-lived blink, not a durable one. Breakpoint log: hook_breakpoints.log (ENTRY 1, RET 1, stock handler 34+). (c) with the settle/IE work, the one-shot post-handler draw persists: frames 24/25 show the black box at (448..511, 400..463) for 600+ frames, and the OS answers TCP at 3500/3600/3700/3800/4000 (settled_hook_client.log; settled_hook_mame.log). It does not toggle. (d) INT2 hook (stub 0F30h, handler 3F714530h) was tried; at idle the handler never takes the trampoline (counter 0), so it is not a blink source here. 4. Window --------- Port 6000 is OPEN on 192.168.99.2 (xcheck.log); 6001 is closed. An ordinary X client is rejected: xdpyinfo -display 192.168.99.2:0 -> "Client is not authorized to access server" So a normal X client cannot open a window without the server's auth cookie. Injection of a window was NOT attempted: it needs the X server's window structures, resource IDs and callbacks; that is a project, not an experiment. Evidence files -------------- step1_ret_test.log, step1_alive_3500.png static_draw_client.log, static_before_3420.png, static_after_3430.png control_spin_client.log, control_spin_box_3480.png, control_hello_3480.png blink_resident_client.log, blink_on_3450(_crop).png, blink_off_3480(_crop).png, blink_on_3500.png, blink_mame.log blink_repeat_client.log, blink_repeat_mame.log, blink2_off_3450.png, blink2_on_3460.png, blink2_on_3500.png, step3_blink_client.log settled_hook_client.log, settled_hook_mame.log, posthandler_persist_3600.png di_one_shot_state.log, hook_breakpoints.log xcheck.log, xcheck_mame.log