Files
vt1200/dwt/gui/README.md
T
SDD a94e99579f dwt/gui: injected X window works via create_process
The xserver local service is reachable from a payload, but a connect made
inside the rdebug process is accepted at the service layer and then never
dequeued: the server's accept callback runs (3F34EC50), but no 12-byte X11
setup read follows and Xlib waits in select.

create_process(entry,name,stack,1,arg) from a new process fixes it. xlaunch
creates the child; the server reads the setup (READ12 ret 0x0C), writes the
reply (8 + 0x90), and xhello creates/maps/syncs a 400x200 window. The payload
also had to keep Display* in a11 (callee-saved) instead of reloading it from a
RAM cell, and re-run SETF after each Xlib call.

Final breakpoint-free frame: dwt/gui/evidence/xhello_window_frame2838.png.
ROM untouched (b46a3e442ccb86134d2356bd70d22fd2).
2026-10-18 14:28:58 +03:00

3.9 KiB

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

./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 <network><device tag=":lance" interface="0" .../></network> in vt1200.cfg the taptun provider is never opened (the tap stays NO-CARRIER).

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 "<prefix> <count> <stride>" 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.