mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
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).
50 lines
1.7 KiB
Lua
50 lines
1.7 KiB
Lua
-- probe_win.lua -- final, breakpoint-free observation of the injected window.
|
|
--
|
|
-- No bpset/wpset at all: this script only reads RAM markers and takes PNG
|
|
-- snapshots on a trigger file ("<prefix> <count> <stride>"). The payload does
|
|
-- the work; the script just looks.
|
|
local machine = manager.machine
|
|
local dir = os.getenv("MSG_DIR") or "."
|
|
local trigger = os.getenv("MSG_TRIGGER") or (dir .. "/trigger")
|
|
local screen = nil
|
|
for _, s in pairs(machine.screens) do screen = s; break end
|
|
local cpu = machine.devices[':maincpu']
|
|
local space = cpu.spaces['program']
|
|
local f = 0
|
|
local job = nil
|
|
|
|
local function u32(a)
|
|
local ok, v = pcall(function() return space:read_u32(a) end)
|
|
if ok then return v end
|
|
return 0xdeadbeef
|
|
end
|
|
|
|
local function consume_trigger()
|
|
local fh = io.open(trigger, "r")
|
|
if not fh then return end
|
|
local text = fh:read("*a") or ""
|
|
fh:close(); os.remove(trigger)
|
|
local prefix, count, stride = text:match("(%S+)%s+(%d+)%s+(%d+)")
|
|
if not prefix then return end
|
|
job = { prefix = prefix, left = tonumber(count), stride = tonumber(stride), next = f }
|
|
print(string.format("probe_win: frame %d job %s x%d every %d",
|
|
f, prefix, job.left, job.stride))
|
|
end
|
|
|
|
emu.register_frame_done(function()
|
|
f = f + 1
|
|
consume_trigger()
|
|
if job and screen and f >= job.next then
|
|
local out = string.format("%s/%s_frame%05d.png", dir, job.prefix, f)
|
|
local ok = pcall(function() return screen:snapshot(out) end)
|
|
print(string.format("probe_win: frame %d %s ok=%s", f, out, tostring(ok)))
|
|
job.left = job.left - 1
|
|
job.next = f + job.stride
|
|
if job.left <= 0 then job = nil end
|
|
end
|
|
if f % 100 == 0 then
|
|
print(string.format("probe_win: f=%d stage=%d strlen=%d win_low=%04X",
|
|
f, u32(0x01890140), u32(0x01890160), u32(0x01890120)))
|
|
end
|
|
end, "vt1200-gui-probe-win")
|