mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-31 12:05:05 +02:00
The firmware transforms the reply (16-round Feistel per 8-byte record) and compares it with the host-order copy of the challenge, so the answer is swap4(inverse_transform(swap4(challenge))). The font stages are memcpy in this path because dwt_prf initialises only mode 1. challenge.py implements the transform and its inverse using the firmware's fixed key/SP table; solve.py answers the challenge over TCP using the unmodified exploit client. 320 forward vectors, the firmware's own inverse and three live sessions validate it. A live run with no breakpoints poked the 82-byte hello-world payload and ran it: MAGIC DEAD/BEEF/0400, VRAM 1024/1024. Notes and evidence under dwt/notes and dwt/evidence.
54 lines
1.7 KiB
Lua
54 lines
1.7 KiB
Lua
-- live_check.lua -- verification with NO breakpoints and no memory writes.
|
|
--
|
|
-- This script only reads RAM/VRAM once per frame. There is no bpset anywhere,
|
|
-- so the exploit cannot be attributed to any debugger action: the only thing
|
|
-- the emulator does is report what the firmware and the payload left in memory.
|
|
local machine = manager.machine
|
|
local cpu = machine.devices[':maincpu']
|
|
local dbg = machine.debugger
|
|
local space = cpu.spaces['program']
|
|
if not dbg then machine:exit(); return end
|
|
dbg.visible_cpu = cpu
|
|
|
|
local MAGIC1 = 0x01810000
|
|
local MAGIC2 = 0x01810010
|
|
local COUNT = 0x01810020
|
|
local VRAM = 0x04019040
|
|
local f = 0
|
|
local done_at = nil
|
|
local last = nil
|
|
|
|
emu.register_frame_done(function()
|
|
f = f + 1
|
|
if f % 500 == 0 then
|
|
print(string.format("CHECK frame %d MAGIC1=%04X MAGIC2=%04X COUNT=%04X",
|
|
f, space:read_u16(MAGIC1), space:read_u16(MAGIC2), space:read_u16(COUNT)))
|
|
end
|
|
if done_at == nil and space:read_u16(MAGIC1) == 0xDEAD then
|
|
done_at = f
|
|
local filled, holes = 0, 0
|
|
for r = 0, 63 do
|
|
for c = 0, 15 do
|
|
if space:read_u16(VRAM + r * 1024 + c * 16) == 0xFFFF then
|
|
filled = filled + 1
|
|
else
|
|
holes = holes + 1
|
|
end
|
|
end
|
|
end
|
|
print(string.format("CHECK payload-ran: MAGIC1=%04X MAGIC2=%04X COUNT=%04X",
|
|
space:read_u16(MAGIC1), space:read_u16(MAGIC2), space:read_u16(COUNT)))
|
|
print(string.format("CHECK payload-ran: VRAM block %d/1024 words FFFF, %d holes",
|
|
filled, holes))
|
|
end
|
|
if done_at and f >= done_at + 120 then
|
|
print(string.format("CHECK exiting at frame %d (payload seen at %d)", f, done_at))
|
|
machine:exit()
|
|
end
|
|
if f >= 12000 then
|
|
print("CHECK timeout: no payload markers")
|
|
machine:exit()
|
|
end
|
|
end, "vt1200-live-check")
|
|
dbg.execution_state = 'run'
|