# 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.