# dwt/gui — injected X window (working) Investigation of the VT1200 GUI architecture and whether an injected payload can create its own window. Read `dwt/notes/GUI_APPS.md` first (especially the new §10); this directory is the reproducible part. **Result:** yes. The payload must run in a process created by the firmware's own `create_process` (not in the rdebug dispatcher), and it must keep the `Display *` in a callee-saved register rather than reloading it from a RAM cell. The final breakpoint-free run shows the window at frame 2838: `evidence/xhello_window_frame2838.png` (black 400x200 window at 100,100, framed by the WM). | file | what it is | |---|---| | `xhello.asm` | the window payload: ABI check (`strlen("0::0")==4`), `XOpenDisplay`, root lookup, `XCreateSimpleWindow`, `XMapWindow`, `XSync`; Display in `a11`, window in `a10`, `setf` re-established after every call | | `xlaunch.asm` | 128-byte launcher: `create_process(xhello, name, 0x6000, 1, 0)` — the Telnet handler's call shape | | `build.sh` | TI SDK (GSPA/GSPLNK under DOSBox) wrapper; writes `build/`, scratch in `work/` | | `probe_win.lua` | **breakpoint-free** final probe: marker log + PNG snapshots on a trigger file | | `probe.lua` / `probe2.lua` / `probe3.lua` | earlier probes (marker/PC telemetry; `probe3` targets the mis-identified `3F58B800`) | | `trace_accept.lua` | instrumented run: service attach/lookup, server accept callback, 12-byte setup read, setup-reply write, Xlib read, process create | | `build/xhello.bin` | assembled payload, linked at bit `0x01840000` | | `build/xlaunch.bin` | assembled launcher, linked at bit `0x01860000` | | `evidence/xhello_window_frame2838.png` | the window, after a run with no breakpoints | | `evidence/transport_evidence.txt` | quoted accept/read/reply lines from the instrumented runs | | `run12/debug.log` | full instrumented trace of the successful fresh-process run | | `run13/` | final run: `mame.log`, snapshots, private cfg/nvram | | `run/` | the earlier failing experiment (rdebug context, stage 2) | ## Build ```sh ./dwt/gui/build.sh dwt/gui/xhello.asm 01840000 # 390 bytes ./dwt/gui/build.sh dwt/gui/xlaunch.asm 01860000 # 128 bytes ``` ## Run The payload needs the OS, i.e. `VT1200_SKIP_LEVEL1=1` (documented divergence), a BOOTP/TFTP server and the LANCE attached. MAME's network device is enabled by the **cfg file**, not the command line — without `` in `vt1200.cfg` the taptun provider is never opened (the tap stays `NO-CARRIER`). ```sh RUN=$PWD/dwt/gui/run13 mkdir -p $RUN/cfg $RUN/nvram cp harness/mame/cfg-net/vt1200.cfg $RUN/cfg/vt1200.cfg sudo python3 -u harness/serve.py 192.168.99.1 --bootp & VT1200_SKIP_LEVEL1=1 MSG_TRIGGER=$RUN/trigger MSG_DIR=$RUN \ /home/arti/code/k-space/mame0289/vt1200 vt1200 \ -rompath harness/mame/roms -sound none -skip_gameinfo \ -networkprovider taptun -video none -nothrottle \ -cfg_directory $RUN/cfg -nvram_directory $RUN/nvram \ -debug -debugger none -autoboot_script $PWD/dwt/gui/probe_win.lua \ -autoboot_delay 0 # once 192.168.99.2:771 answers (rdebug creates a fresh process per connection) python3 dwt/visual/inject.py --host 192.168.99.2 \ --poke-file 0x01840000 --file dwt/gui/build/xhello.bin python3 dwt/visual/inject.py --host 192.168.99.2 \ --poke-file 0x01860000 --file dwt/gui/build/xlaunch.bin \ --jump 0x01860000 --jump-wait 8 # snapshots: write " " into $RUN/trigger echo 'xhello 6 60' > $RUN/trigger ``` Markers are diagnostic cells at bit `0x01890100` (display), `01890110` (root), `01890120` (window), `01890130` (sync), `01890140` (stage), `01890160` (strlen). In the successful run the stage reaches 6 and `strlen` is 4. Do **not** call Xlib in the rdebug process: the service attach and the server's accept callback succeed, but the server never reads the 12-byte setup, and Xlib waits forever. See §10 of the note for the trace and the remaining open question.