mirror of
https://git.k-space.ee/arti/vt1200.git
synced 2026-10-30 12:03:54 +02:00
dwt/loader: end-to-end host loader over rdebug
hostload.py drives one rdebug connection: jump(malloc) for the COFF buffer, poke the COFF, poke the loader at 0x01880000, write the descriptor, call the loader, and verify status 0 plus app evidence (marker cells or xhello stage 6 and a VRAM screenshot). --tftp uses the existing tftpc.bin fetch instead of a host poke. Adds evidence for two/three fresh boots and appends the integrate section to dwt/notes/LOADER.md, including the bit-offset result-block layout and the create_process clobber of the descriptor.
This commit is contained in:
1 parent
bebc0ccbc1
commit
8588340527
22 files changed
+1104
No files matched your search
@@ -0,0 +1,91 @@
|
||||
# hostload evidence (rdebug -> malloc -> COFF -> loader -> app)
|
||||
|
||||
All runs: `VT1200_SKIP_LEVEL1=1`, private `-cfg_directory`/`-nvram_directory`,
|
||||
`-networkprovider taptun`, BOOTP/TFTP from `dwt/tcpip/serve_probe.py` on
|
||||
`192.168.99.2`. The ROM is untouched
|
||||
(`md5 b46a3e442ccb86134d2356bd70d22fd2`, re-checked after the runs); no driver
|
||||
edits, no breakpoints.
|
||||
|
||||
Driver: `dwt/loader/hostload.py`. Each log is one complete connection.
|
||||
|
||||
## Malloc -> poke -> descriptor -> loader -> markers (three boots)
|
||||
|
||||
| log | boot | `jump(malloc)` bit ptr | byte | status / PCB | markers |
|
||||
|---|---|---|---|---|---|
|
||||
| `marker_boot2_run4.log` | 2 | `0x007df450` | `0x0FBE8A` | 0 / `0x003fc5d0` | start/data/data2/bss OK, count moving |
|
||||
| `marker_boot3.log` | 3 | `0x007c7290` | `0x0F8E52` | 0 / `0x003ffbd0` | start/data/data2/bss OK, count moving |
|
||||
| `marker_boot4.log` | 4 | `0x007c8030` | `0x0F9006` | 0 / `0x003ffbd0` | start/data/data2/bss OK, count moving |
|
||||
| `marker_nopokeloader_boot4.log` | 4 | `0x007d8970` | `0x0FB12E` | 0 / `0x003fd590` | loader readback 610 words, 0 differing |
|
||||
|
||||
The marker values in every run are `start=0x018C0000`, `data=0xDEADBEEF`,
|
||||
`data2=0x12345678`, `bss=0` after a fresh boot. The counter changes between two
|
||||
samples (multiple children from successive runs can make it go backwards; a
|
||||
fresh boot is monotonic).
|
||||
|
||||
Each log shows the full result block: status 0, entry/text/data/bss addresses
|
||||
and sizes, `pcb != 0`, `nscns=3`, `coff_len=510`, `loader_base=0x01880000`.
|
||||
|
||||
## xhello -> X window (two boots)
|
||||
|
||||
| log | boot | malloc bit ptr | stage | screenshot |
|
||||
|---|---|---|---|---|
|
||||
| `xhello_boot3.log` | 3 | `0x007c82d0` | 6 | `hostload_xhello_boot3_xhello.png` |
|
||||
| `xhello_boot4.log` | 4 | `0x007c9070` | 6 | `hostload_xhello_boot4_xhello.png` |
|
||||
|
||||
`stage=6` is set after `XSync`; `strlen=4` is the ABI check. The PNGs (1-bit
|
||||
1024x1024 VRAM, lossless) show the black 400x200 window with its WM title bar at
|
||||
`(100,100)` over the Terminal Manager — same visual as
|
||||
`dwt/loader/evidence/loader_frame2650.png`.
|
||||
|
||||
## Heap placement (read-only `dwt/heapmap.py`)
|
||||
|
||||
`heapmap_boot4.txt` shows the global free list after the boot-4 runs and checks
|
||||
the two app `.text` targets: `0x018C0000` and `0x01840000` are both **inside**
|
||||
the last free block (`byte 0x1719BA..0x400000`) with about 950 KiB / 0.97 MiB
|
||||
of headroom to its end. The malloc'd COFF buffers (`0x007C…`, `0x009F…`,
|
||||
`0x00AD…`) are in the low blocks, far from the loader page (byte `0x310000`)
|
||||
and from both targets. That is why the loader's free-list check (a check, not
|
||||
a reservation) passes on these boots.
|
||||
|
||||
## `--tftp`: fetched COFF, no host poke of the COFF (two boots)
|
||||
|
||||
| log | boot | tftpc buffer | RRQ line |
|
||||
|---|---|---|---|
|
||||
| `tftp_marker_boot3.log` | 3 | `0x009fccd0` | `15:31:47 ... requested 'dwt/tcpip/probe.bin' (510 bytes)` |
|
||||
| `tftp_marker_boot4.log` | 4 | `0x009fccd0` | `15:32:16 ... requested 'dwt/tcpip/probe.bin' (510 bytes)` |
|
||||
|
||||
(`serve_tftp_marker_boot2.log` is the boot-2 RRQ from the first, pre-logging
|
||||
run: `15:31:07`, buffer `0x00b4ce90`; its host-side output was not saved.)
|
||||
|
||||
The TFTP server was serving `dwt/loader/build/marker.coff` for **any** name
|
||||
(`--file dwt/loader/build/marker.coff`); `tftpc.asm`'s RRQ name is fixed. Each
|
||||
log shows `stage=4 fd=1 total=510 done=0x05A5A5A5`, then a `peek` comparison of
|
||||
the fetched buffer against the local COFF: 510/510 bytes, sha256
|
||||
`519e4724aa537436a35f5e49a3306b3f6bcebdc216a0ce4c103822b0df28d749` (same as
|
||||
the file). The loader then used that buffer's bit address in the descriptor.
|
||||
|
||||
## Failure that is not a failure
|
||||
|
||||
The first integration attempts parsed the result block at byte offsets
|
||||
`0x20, 0x40, ...` and saw `0x55555555`. The loader's constants are **bit**
|
||||
offsets (`RESULT_BASE+020h` = +4 bytes), so the real block is 13 adjacent
|
||||
32-bit cells (52 bytes) at byte offsets `0x00, 0x04, ... 0x30`. The stale/free
|
||||
heap fill beyond byte 0x34 reads `0x55`. `hostload.py` now converts bit
|
||||
offsets to bytes; no loader change was needed.
|
||||
|
||||
## Descriptor quirk worth knowing
|
||||
|
||||
After a successful load, a 16-byte window at `0x01882C00` (the descriptor) is
|
||||
overwritten with `0d 00 00 00 <pcb> <ptr> 00 60 00 00` — the `create_process`
|
||||
call frame from the loader's `ARG_AREA` (`0x01882B00`, 0x100 bits below the
|
||||
descriptor). It is harmless: the loader has already read the descriptor, and
|
||||
the result block at `0x01882D00` is untouched. It does mean a second call must
|
||||
rewrite the descriptor, which `hostload.py` always does immediately before the
|
||||
jump.
|
||||
|
||||
## Frame dumps
|
||||
|
||||
`hostload.py --frame N` only waits for `vt1200-frame-N.ppm` (a MAME
|
||||
`VT1200_DUMP_FRAME` dump). Frame numbers are boot-relative and the dump must be
|
||||
configured on the MAME side; the load-relative evidence here is the rdebug VRAM
|
||||
screenshot, not a MAME frame dump.
|
||||
@@ -0,0 +1,26 @@
|
||||
# fresh boot 4, after hostload marker/xhello/tftp runs
|
||||
# free counter / global free list (read-only peek)
|
||||
free counter: 22345840 bits = 2793230 bytes (2793 KB decimal)
|
||||
global: 10 blocks, byte 0x0F5A7E..0x400000, 2705790 bytes usable
|
||||
bit 0x007AD3F0 byte 0x0F5A7E size 84 B end 0x0F5AD2 next 0x007ADF90
|
||||
bit 0x007ADF90 byte 0x0F5BF2 size 44 B end 0x0F5C1E next 0x007AEAD0
|
||||
bit 0x007AEAD0 byte 0x0F5D5A size 88 B end 0x0F5DB2 next 0x007AF0F0
|
||||
bit 0x007AF0F0 byte 0x0F5E1E size 12768 B end 0x0F8FFE next 0x007DBCD0
|
||||
bit 0x007DBCD0 byte 0x0FB79A size 836 B end 0x0FBADE next 0x007DF410
|
||||
bit 0x007DF410 byte 0x0FBE82 size 11364 B end 0x0FEAE6 next 0x008DB630
|
||||
bit 0x008DB630 byte 0x11B6C6 size 56 B end 0x11B6FE next 0x009029D0
|
||||
bit 0x009029D0 byte 0x12053A size 164 B end 0x1205DE next 0x009209F0
|
||||
bit 0x009209F0 byte 0x12413E size 76 B end 0x12418A next 0x00B8CDD0
|
||||
bit 0x00B8CDD0 byte 0x1719BA size 2680390 B end 0x400000 next 0x00000000
|
||||
|
||||
# --at 0x018C0000 (marker .text target)
|
||||
free counter: 22345520 bits = 2793190 bytes (2793 KB decimal)
|
||||
global: 10 blocks, byte 0x0F5A7E..0x400000, 2705790 bytes usable
|
||||
check bit 0x018C0000 (byte 0x318000): INSIDE a free block
|
||||
global: block bit 0x00B8CDD0, 950272 bytes of headroom to its end
|
||||
|
||||
# --at 0x01840000 (xhello .text target)
|
||||
free counter: 22345840 bits = 2793230 bytes (2793 KB decimal)
|
||||
global: 10 blocks, byte 0x0F5A7E..0x400000, 2705790 bytes usable
|
||||
check bit 0x01840000 (byte 0x308000): INSIDE a free block
|
||||
global: block bit 0x00B8CDD0, 1015808 bytes of headroom to its end
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 6.5 KiB |
@@ -0,0 +1,11 @@
|
||||
Warning: -video none doesn't make much sense without -seconds_to_run
|
||||
vt1200: screen_update#1 frame=0 clip_y=0..0 screen=1280x901
|
||||
vt1200: screen_update#2 frame=0 clip_y=1..900 screen=1280x901
|
||||
vt1200: guard#1 frame=0 dump_frame=-1 dump_ram=-1
|
||||
vt1200: screen_update#3 frame=0 clip_y=0..900 screen=1280x901
|
||||
vt1200: scanline#1 line=0 enabled=1
|
||||
vt1200: guard#2 frame=0 dump_frame=-1 dump_ram=-1
|
||||
vt1200: screen_update#4 frame=1 clip_y=0..0 screen=1280x901
|
||||
vt1200: scanline#2 line=0 enabled=1
|
||||
vt1200: scanline#3 line=1 enabled=1
|
||||
vt1200: scanline#4 line=2 enabled=1
|
||||
@@ -0,0 +1,11 @@
|
||||
Warning: -video none doesn't make much sense without -seconds_to_run
|
||||
vt1200: screen_update#1 frame=0 clip_y=0..0 screen=1280x901
|
||||
vt1200: screen_update#2 frame=0 clip_y=1..900 screen=1280x901
|
||||
vt1200: guard#1 frame=0 dump_frame=-1 dump_ram=-1
|
||||
vt1200: screen_update#3 frame=0 clip_y=0..900 screen=1280x901
|
||||
vt1200: scanline#1 line=0 enabled=1
|
||||
vt1200: guard#2 frame=0 dump_frame=-1 dump_ram=-1
|
||||
vt1200: screen_update#4 frame=1 clip_y=0..0 screen=1280x901
|
||||
vt1200: scanline#2 line=0 enabled=1
|
||||
vt1200: scanline#3 line=1 enabled=1
|
||||
vt1200: scanline#4 line=2 enabled=1
|
||||
@@ -0,0 +1,11 @@
|
||||
Warning: -video none doesn't make much sense without -seconds_to_run
|
||||
vt1200: screen_update#1 frame=0 clip_y=0..0 screen=1280x901
|
||||
vt1200: screen_update#2 frame=0 clip_y=1..900 screen=1280x901
|
||||
vt1200: guard#1 frame=0 dump_frame=-1 dump_ram=-1
|
||||
vt1200: screen_update#3 frame=0 clip_y=0..900 screen=1280x901
|
||||
vt1200: scanline#1 line=0 enabled=1
|
||||
vt1200: guard#2 frame=0 dump_frame=-1 dump_ram=-1
|
||||
vt1200: screen_update#4 frame=1 clip_y=0..0 screen=1280x901
|
||||
vt1200: scanline#2 line=0 enabled=1
|
||||
vt1200: scanline#3 line=1 enabled=1
|
||||
vt1200: scanline#4 line=2 enabled=1
|
||||
@@ -0,0 +1,11 @@
|
||||
Warning: -video none doesn't make much sense without -seconds_to_run
|
||||
vt1200: screen_update#1 frame=0 clip_y=0..0 screen=1280x901
|
||||
vt1200: screen_update#2 frame=0 clip_y=1..900 screen=1280x901
|
||||
vt1200: guard#1 frame=0 dump_frame=-1 dump_ram=-1
|
||||
vt1200: screen_update#3 frame=0 clip_y=0..900 screen=1280x901
|
||||
vt1200: scanline#1 line=0 enabled=1
|
||||
vt1200: guard#2 frame=0 dump_frame=-1 dump_ram=-1
|
||||
vt1200: screen_update#4 frame=1 clip_y=0..0 screen=1280x901
|
||||
vt1200: scanline#2 line=0 enabled=1
|
||||
vt1200: scanline#3 line=1 enabled=1
|
||||
vt1200: scanline#4 line=2 enabled=1
|
||||
@@ -0,0 +1,33 @@
|
||||
[.] COFF /home/arti/code/k-space/vt1200/dwt/loader/build/marker.coff: 510 B, 3 sections, entry=0x018c0000 sha256=519e4724aa537436a35f5e49a3306b3f6bcebdc216a0ce4c103822b0df28d749
|
||||
.text paddr=0x018c0000 size=656 bits (82 B) nreloc=0
|
||||
.data paddr=0x018d0000 size=64 bits (8 B) nreloc=0
|
||||
.bss paddr=0x018d8000 size=64 bits (8 B) nreloc=0
|
||||
[.] connected 192.168.99.2:771; opcode 7 -> flag=0x0 b'Done\n\x00'
|
||||
[.] jump returned 0x007df450 (8254544)
|
||||
[+] jump(malloc) -> 0x007df450; bit 0x007df450 = byte 0x0fbe8a, 510 bytes, bit range 0x007df450..0x007e0440
|
||||
[+] COFF poked 510 B at 0x007df450 (255 words, 0 differing bytes)
|
||||
readback[0:510] 90 00 03 00 de e0 d4 6a 02 01 00 00 0e 00 00 00 1c 00 03 01 08 01 c7 00 90 02 00 00 40 00 00 00 40 00 00 00 00 00 8c 01 00 00 8c 01 00 00 8d 01 2e 74 65 78 74 00 00 00 00 00 8c 01 00 00 8c 01 90 02 00 00 a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 2e 64 61 74 61 00 00 00 00 00 8d 01 00 00 8d 01 40 00 00 00 fa 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 2e 62 73 73 00 00 00 00 00 80 8d 01 00 80 8d 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 50 05 40 07 e2 09 00 00 8c 01 82 07 00 00 8e 01 a0 07 00 00 8d 01 80 07 20 00 8e 01 a1 07 20 00 8d 01 81 07 40 00 8e 01 a3 07 00 80 8d 01 83 07 60 00 8e 01 84 44 04 0b 01 00 84 07 20 80 8d 01 84 07 80 00 8e 01 e5 09 00 20 00 00 25 3c f3 c0 60 09 ef be ad de 78 56 34 12 2e 74 65 78 74 00 00 00 00 00 8c 01 01 00 00 00 03 01 90 02 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 64 61 74 61 00 00 00 00 00 8d 01 02 00 00 00 03 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 62 73 73 00 00 00 00 00 80 8d 01 03 00 00 00 03 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 73 75 62 00 00 00 00 00 80 02 8c 01 01 00 00 00 02 00 5f 73 74 61 72 74 00 00 00 00 8c 01 01 00 00 00 02 00 2e 74 65 78 74 00 00 00 00 00 8c 01 01 00 00 00 02 00 65 74 65 78 74 00 00 00 90 02 8c 01 01 00 00 00 02 00 2e 64 61 74 61 00 00 00 00 00 8d 01 02 00 00 00 02 00 65 64 61 74 61 00 00 00 40 00 8d 01 02 00 00 00 02 00 2e 62 73 73 00 00 00 00 00 80 8d 01 03 00 00 00 02 00 65 6e 64 00 00 00 00 00 40 80 8d 01 03 00 00 00 02 00
|
||||
[+] loader poked 1220 B at 0x01880000 (610 words, 0 differing)
|
||||
[.] descriptor @ 0x01882c00: 44 4c 31 52 50 f4 7d 00 fe 01 00 00 01 00 00 00 (magic 4C44/5231, buf=0x007df450, len=510, mode=1)
|
||||
[.] jump returned 0x00000000 (0)
|
||||
[.] loader A8=0x0 (OK)
|
||||
[.] result block @ 0x1882d00:
|
||||
+0x000 status 0x00000000
|
||||
+0x020 entry 0x018c0000
|
||||
+0x040 text_addr 0x018c0000
|
||||
+0x060 text_size 0x00000290
|
||||
+0x080 data_addr 0x018d0000
|
||||
+0x0a0 data_size 0x00000040
|
||||
+0x0c0 bss_addr 0x018d8000
|
||||
+0x0e0 bss_size 0x00000040
|
||||
+0x100 relocs 0x00000000
|
||||
+0x120 pcb 0x003fc5d0
|
||||
+0x140 nscns 0x00000003
|
||||
+0x160 coff_len 0x000001fe
|
||||
+0x180 loader_base 0x01880000
|
||||
[.] marker start 0x018c0000 (want 0x018c0000)
|
||||
[.] marker data 0xdeadbeef (want 0xdeadbeef)
|
||||
[.] marker data2 0x12345678 (want 0x12345678)
|
||||
[.] marker bss 0x00000000 (want 0x00000000)
|
||||
[.] marker count 20495 -> 23238 (child scheduled)
|
||||
[+] PASS: status=0 pcb=0x003fc5d0 entry=0x018c0000 (marker_boot2_run4)
|
||||
@@ -0,0 +1,33 @@
|
||||
[.] COFF /home/arti/code/k-space/vt1200/dwt/loader/build/marker.coff: 510 B, 3 sections, entry=0x018c0000 sha256=519e4724aa537436a35f5e49a3306b3f6bcebdc216a0ce4c103822b0df28d749
|
||||
.text paddr=0x018c0000 size=656 bits (82 B) nreloc=0
|
||||
.data paddr=0x018d0000 size=64 bits (8 B) nreloc=0
|
||||
.bss paddr=0x018d8000 size=64 bits (8 B) nreloc=0
|
||||
[.] connected 192.168.99.2:771; opcode 7 -> flag=0x0 b'Done\n\x00'
|
||||
[.] jump returned 0x007c7290 (8155792)
|
||||
[+] jump(malloc) -> 0x007c7290; bit 0x007c7290 = byte 0x0f8e52, 510 bytes, bit range 0x007c7290..0x007c8280
|
||||
[+] COFF poked 510 B at 0x007c7290 (255 words, 0 differing bytes)
|
||||
readback[0:510] 90 00 03 00 de e0 d4 6a 02 01 00 00 0e 00 00 00 1c 00 03 01 08 01 c7 00 90 02 00 00 40 00 00 00 40 00 00 00 00 00 8c 01 00 00 8c 01 00 00 8d 01 2e 74 65 78 74 00 00 00 00 00 8c 01 00 00 8c 01 90 02 00 00 a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 2e 64 61 74 61 00 00 00 00 00 8d 01 00 00 8d 01 40 00 00 00 fa 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 2e 62 73 73 00 00 00 00 00 80 8d 01 00 80 8d 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 50 05 40 07 e2 09 00 00 8c 01 82 07 00 00 8e 01 a0 07 00 00 8d 01 80 07 20 00 8e 01 a1 07 20 00 8d 01 81 07 40 00 8e 01 a3 07 00 80 8d 01 83 07 60 00 8e 01 84 44 04 0b 01 00 84 07 20 80 8d 01 84 07 80 00 8e 01 e5 09 00 20 00 00 25 3c f3 c0 60 09 ef be ad de 78 56 34 12 2e 74 65 78 74 00 00 00 00 00 8c 01 01 00 00 00 03 01 90 02 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 64 61 74 61 00 00 00 00 00 8d 01 02 00 00 00 03 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 62 73 73 00 00 00 00 00 80 8d 01 03 00 00 00 03 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 73 75 62 00 00 00 00 00 80 02 8c 01 01 00 00 00 02 00 5f 73 74 61 72 74 00 00 00 00 8c 01 01 00 00 00 02 00 2e 74 65 78 74 00 00 00 00 00 8c 01 01 00 00 00 02 00 65 74 65 78 74 00 00 00 90 02 8c 01 01 00 00 00 02 00 2e 64 61 74 61 00 00 00 00 00 8d 01 02 00 00 00 02 00 65 64 61 74 61 00 00 00 40 00 8d 01 02 00 00 00 02 00 2e 62 73 73 00 00 00 00 00 80 8d 01 03 00 00 00 02 00 65 6e 64 00 00 00 00 00 40 80 8d 01 03 00 00 00 02 00
|
||||
[+] loader poked 1220 B at 0x01880000 (610 words, 0 differing)
|
||||
[.] descriptor @ 0x01882c00: 44 4c 31 52 90 72 7c 00 fe 01 00 00 01 00 00 00 (magic 4C44/5231, buf=0x007c7290, len=510, mode=1)
|
||||
[.] jump returned 0x00000000 (0)
|
||||
[.] loader A8=0x0 (OK)
|
||||
[.] result block @ 0x1882d00:
|
||||
+0x000 status 0x00000000
|
||||
+0x020 entry 0x018c0000
|
||||
+0x040 text_addr 0x018c0000
|
||||
+0x060 text_size 0x00000290
|
||||
+0x080 data_addr 0x018d0000
|
||||
+0x0a0 data_size 0x00000040
|
||||
+0x0c0 bss_addr 0x018d8000
|
||||
+0x0e0 bss_size 0x00000040
|
||||
+0x100 relocs 0x00000000
|
||||
+0x120 pcb 0x003ffbd0
|
||||
+0x140 nscns 0x00000003
|
||||
+0x160 coff_len 0x000001fe
|
||||
+0x180 loader_base 0x01880000
|
||||
[.] marker start 0x018c0000 (want 0x018c0000)
|
||||
[.] marker data 0xdeadbeef (want 0xdeadbeef)
|
||||
[.] marker data2 0x12345678 (want 0x12345678)
|
||||
[.] marker bss 0x00000000 (want 0x00000000)
|
||||
[.] marker count 387 -> 1301 (child scheduled)
|
||||
[+] PASS: status=0 pcb=0x003ffbd0 entry=0x018c0000 (marker_boot3)
|
||||
@@ -0,0 +1,33 @@
|
||||
[.] COFF /home/arti/code/k-space/vt1200/dwt/loader/build/marker.coff: 510 B, 3 sections, entry=0x018c0000 sha256=519e4724aa537436a35f5e49a3306b3f6bcebdc216a0ce4c103822b0df28d749
|
||||
.text paddr=0x018c0000 size=656 bits (82 B) nreloc=0
|
||||
.data paddr=0x018d0000 size=64 bits (8 B) nreloc=0
|
||||
.bss paddr=0x018d8000 size=64 bits (8 B) nreloc=0
|
||||
[.] connected 192.168.99.2:771; opcode 7 -> flag=0x0 b'Done\n\x00'
|
||||
[.] jump returned 0x007c8030 (8159280)
|
||||
[+] jump(malloc) -> 0x007c8030; bit 0x007c8030 = byte 0x0f9006, 510 bytes, bit range 0x007c8030..0x007c9020
|
||||
[+] COFF poked 510 B at 0x007c8030 (255 words, 0 differing bytes)
|
||||
readback[0:510] 90 00 03 00 de e0 d4 6a 02 01 00 00 0e 00 00 00 1c 00 03 01 08 01 c7 00 90 02 00 00 40 00 00 00 40 00 00 00 00 00 8c 01 00 00 8c 01 00 00 8d 01 2e 74 65 78 74 00 00 00 00 00 8c 01 00 00 8c 01 90 02 00 00 a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 2e 64 61 74 61 00 00 00 00 00 8d 01 00 00 8d 01 40 00 00 00 fa 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 2e 62 73 73 00 00 00 00 00 80 8d 01 00 80 8d 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 50 05 40 07 e2 09 00 00 8c 01 82 07 00 00 8e 01 a0 07 00 00 8d 01 80 07 20 00 8e 01 a1 07 20 00 8d 01 81 07 40 00 8e 01 a3 07 00 80 8d 01 83 07 60 00 8e 01 84 44 04 0b 01 00 84 07 20 80 8d 01 84 07 80 00 8e 01 e5 09 00 20 00 00 25 3c f3 c0 60 09 ef be ad de 78 56 34 12 2e 74 65 78 74 00 00 00 00 00 8c 01 01 00 00 00 03 01 90 02 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 64 61 74 61 00 00 00 00 00 8d 01 02 00 00 00 03 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 62 73 73 00 00 00 00 00 80 8d 01 03 00 00 00 03 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 73 75 62 00 00 00 00 00 80 02 8c 01 01 00 00 00 02 00 5f 73 74 61 72 74 00 00 00 00 8c 01 01 00 00 00 02 00 2e 74 65 78 74 00 00 00 00 00 8c 01 01 00 00 00 02 00 65 74 65 78 74 00 00 00 90 02 8c 01 01 00 00 00 02 00 2e 64 61 74 61 00 00 00 00 00 8d 01 02 00 00 00 02 00 65 64 61 74 61 00 00 00 40 00 8d 01 02 00 00 00 02 00 2e 62 73 73 00 00 00 00 00 80 8d 01 03 00 00 00 02 00 65 6e 64 00 00 00 00 00 40 80 8d 01 03 00 00 00 02 00
|
||||
[+] loader poked 1220 B at 0x01880000 (610 words, 0 differing)
|
||||
[.] descriptor @ 0x01882c00: 44 4c 31 52 30 80 7c 00 fe 01 00 00 01 00 00 00 (magic 4C44/5231, buf=0x007c8030, len=510, mode=1)
|
||||
[.] jump returned 0x00000000 (0)
|
||||
[.] loader A8=0x0 (OK)
|
||||
[.] result block @ 0x1882d00:
|
||||
+0x000 status 0x00000000
|
||||
+0x020 entry 0x018c0000
|
||||
+0x040 text_addr 0x018c0000
|
||||
+0x060 text_size 0x00000290
|
||||
+0x080 data_addr 0x018d0000
|
||||
+0x0a0 data_size 0x00000040
|
||||
+0x0c0 bss_addr 0x018d8000
|
||||
+0x0e0 bss_size 0x00000040
|
||||
+0x100 relocs 0x00000000
|
||||
+0x120 pcb 0x003ffbd0
|
||||
+0x140 nscns 0x00000003
|
||||
+0x160 coff_len 0x000001fe
|
||||
+0x180 loader_base 0x01880000
|
||||
[.] marker start 0x018c0000 (want 0x018c0000)
|
||||
[.] marker data 0xdeadbeef (want 0xdeadbeef)
|
||||
[.] marker data2 0x12345678 (want 0x12345678)
|
||||
[.] marker bss 0x00000000 (want 0x00000000)
|
||||
[.] marker count 380 -> 1252 (child scheduled)
|
||||
[+] PASS: status=0 pcb=0x003ffbd0 entry=0x018c0000 (marker_boot4)
|
||||
@@ -0,0 +1,33 @@
|
||||
[.] COFF /home/arti/code/k-space/vt1200/dwt/loader/build/marker.coff: 510 B, 3 sections, entry=0x018c0000 sha256=519e4724aa537436a35f5e49a3306b3f6bcebdc216a0ce4c103822b0df28d749
|
||||
.text paddr=0x018c0000 size=656 bits (82 B) nreloc=0
|
||||
.data paddr=0x018d0000 size=64 bits (8 B) nreloc=0
|
||||
.bss paddr=0x018d8000 size=64 bits (8 B) nreloc=0
|
||||
[.] connected 192.168.99.2:771; opcode 7 -> flag=0x0 b'Done\n\x00'
|
||||
[.] jump returned 0x007d8970 (8227184)
|
||||
[+] jump(malloc) -> 0x007d8970; bit 0x007d8970 = byte 0x0fb12e, 510 bytes, bit range 0x007d8970..0x007d9960
|
||||
[+] COFF poked 510 B at 0x007d8970 (255 words, 0 differing bytes)
|
||||
readback[0:510] 90 00 03 00 de e0 d4 6a 02 01 00 00 0e 00 00 00 1c 00 03 01 08 01 c7 00 90 02 00 00 40 00 00 00 40 00 00 00 00 00 8c 01 00 00 8c 01 00 00 8d 01 2e 74 65 78 74 00 00 00 00 00 8c 01 00 00 8c 01 90 02 00 00 a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 2e 64 61 74 61 00 00 00 00 00 8d 01 00 00 8d 01 40 00 00 00 fa 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 2e 62 73 73 00 00 00 00 00 80 8d 01 00 80 8d 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 50 05 40 07 e2 09 00 00 8c 01 82 07 00 00 8e 01 a0 07 00 00 8d 01 80 07 20 00 8e 01 a1 07 20 00 8d 01 81 07 40 00 8e 01 a3 07 00 80 8d 01 83 07 60 00 8e 01 84 44 04 0b 01 00 84 07 20 80 8d 01 84 07 80 00 8e 01 e5 09 00 20 00 00 25 3c f3 c0 60 09 ef be ad de 78 56 34 12 2e 74 65 78 74 00 00 00 00 00 8c 01 01 00 00 00 03 01 90 02 00 00 05 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 64 61 74 61 00 00 00 00 00 8d 01 02 00 00 00 03 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 62 73 73 00 00 00 00 00 80 8d 01 03 00 00 00 03 01 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 73 75 62 00 00 00 00 00 80 02 8c 01 01 00 00 00 02 00 5f 73 74 61 72 74 00 00 00 00 8c 01 01 00 00 00 02 00 2e 74 65 78 74 00 00 00 00 00 8c 01 01 00 00 00 02 00 65 74 65 78 74 00 00 00 90 02 8c 01 01 00 00 00 02 00 2e 64 61 74 61 00 00 00 00 00 8d 01 02 00 00 00 02 00 65 64 61 74 61 00 00 00 40 00 8d 01 02 00 00 00 02 00 2e 62 73 73 00 00 00 00 00 80 8d 01 03 00 00 00 02 00 65 6e 64 00 00 00 00 00 40 80 8d 01 03 00 00 00 02 00
|
||||
[.] --no-poke-loader: /home/arti/code/k-space/vt1200/dwt/loader/build/loader.bin readback (610 words, 0 differing)
|
||||
[.] descriptor @ 0x01882c00: 44 4c 31 52 70 89 7d 00 fe 01 00 00 01 00 00 00 (magic 4C44/5231, buf=0x007d8970, len=510, mode=1)
|
||||
[.] jump returned 0x00000000 (0)
|
||||
[.] loader A8=0x0 (OK)
|
||||
[.] result block @ 0x1882d00:
|
||||
+0x000 status 0x00000000
|
||||
+0x020 entry 0x018c0000
|
||||
+0x040 text_addr 0x018c0000
|
||||
+0x060 text_size 0x00000290
|
||||
+0x080 data_addr 0x018d0000
|
||||
+0x0a0 data_size 0x00000040
|
||||
+0x0c0 bss_addr 0x018d8000
|
||||
+0x0e0 bss_size 0x00000040
|
||||
+0x100 relocs 0x00000000
|
||||
+0x120 pcb 0x003fd590
|
||||
+0x140 nscns 0x00000003
|
||||
+0x160 coff_len 0x000001fe
|
||||
+0x180 loader_base 0x01880000
|
||||
[.] marker start 0x018c0000 (want 0x018c0000)
|
||||
[.] marker data 0xdeadbeef (want 0xdeadbeef)
|
||||
[.] marker data2 0x12345678 (want 0x12345678)
|
||||
[.] marker bss 0x00000000 (want 0x00000000)
|
||||
[.] marker count 4578 -> 606 (child scheduled)
|
||||
[+] PASS: status=0 pcb=0x003fd590 entry=0x018c0000 (marker_nopokeloader_boot4)
|
||||
@@ -0,0 +1,4 @@
|
||||
tftp: serving 600 bytes (probe.bin) for any name on ('192.168.99.1', 69)
|
||||
bootp: L2 responder on tap-mess-1000-0: handing out 192.168.99.2, siaddr 192.168.99.1
|
||||
bootp: request from 08:00:2b:16:4b:5a xid=f81fccff -> 192.168.99.2 (siaddr 192.168.99.1, tap tap-mess-1000-0)
|
||||
bootp: request from 08:00:2b:16:4b:5a xid=f81fccff -> 192.168.99.2 (siaddr 192.168.99.1, tap tap-mess-1000-0)
|
||||
@@ -0,0 +1,8 @@
|
||||
tftp: serving 510 bytes (marker.coff) for any name on ('192.168.99.1', 69)
|
||||
bootp: L2 responder on tap-mess-1000-0: handing out 192.168.99.2, siaddr 192.168.99.1
|
||||
15:31:07 RRQ 192.168.99.2:1025 requested 'dwt/tcpip/probe.bin' (510 bytes)
|
||||
bootp: request from 08:00:2b:16:4b:5a xid=f81fccff -> 192.168.99.2 (siaddr 192.168.99.1, tap tap-mess-1000-0)
|
||||
15:31:47 RRQ 192.168.99.2:1025 requested 'dwt/tcpip/probe.bin' (510 bytes)
|
||||
bootp: request from 08:00:2b:16:4b:5a xid=f81fccff -> 192.168.99.2 (siaddr 192.168.99.1, tap tap-mess-1000-0)
|
||||
15:32:16 RRQ 192.168.99.2:1025 requested 'dwt/tcpip/probe.bin' (510 bytes)
|
||||
15:32:53 RRQ 192.168.99.2:1026 requested 'dwt/tcpip/probe.bin' (510 bytes)
|
||||
@@ -0,0 +1,3 @@
|
||||
tftp: serving 510 bytes (marker.coff) for any name on ('192.168.99.1', 69)
|
||||
bootp: L2 responder on tap-mess-1000-0: handing out 192.168.99.2, siaddr 192.168.99.1
|
||||
15:31:07 RRQ 192.168.99.2:1025 requested 'dwt/tcpip/probe.bin' (510 bytes)
|
||||
@@ -0,0 +1,34 @@
|
||||
[.] COFF /home/arti/code/k-space/vt1200/dwt/loader/build/marker.coff: 510 B, 3 sections, entry=0x018c0000 sha256=519e4724aa537436a35f5e49a3306b3f6bcebdc216a0ce4c103822b0df28d749
|
||||
.text paddr=0x018c0000 size=656 bits (82 B) nreloc=0
|
||||
.data paddr=0x018d0000 size=64 bits (8 B) nreloc=0
|
||||
.bss paddr=0x018d8000 size=64 bits (8 B) nreloc=0
|
||||
[.] connected 192.168.99.2:771; opcode 7 -> flag=0x0 b'Done\n\x00'
|
||||
[.] tftpc poked 694 B at 0x01870000 (347 words, 0 differing)
|
||||
[.] jump returned 0x00000000 (0)
|
||||
[.] tftpc markers: stage=4 fd=1 buf=0x9fccd0 total=510 last=514 block=0x100 done=0x5a5a5a5
|
||||
[.] server RRQ (dwt/loader/evidence/hostload/serve_tftp_marker.log): 15:31:47 RRQ 192.168.99.2:1025 requested 'dwt/tcpip/probe.bin' (510 bytes)
|
||||
[+] TFTP fetch verified byte-for-byte: 510 B at 0x009fccd0 (sha256=519e4724aa537436a35f5e49a3306b3f6bcebdc216a0ce4c103822b0df28d749)
|
||||
[+] loader poked 1220 B at 0x01880000 (610 words, 0 differing)
|
||||
[.] descriptor @ 0x01882c00: 44 4c 31 52 d0 cc 9f 00 fe 01 00 00 01 00 00 00 (magic 4C44/5231, buf=0x009fccd0, len=510, mode=1)
|
||||
[.] jump returned 0x00000000 (0)
|
||||
[.] loader A8=0x0 (OK)
|
||||
[.] result block @ 0x1882d00:
|
||||
+0x000 status 0x00000000
|
||||
+0x020 entry 0x018c0000
|
||||
+0x040 text_addr 0x018c0000
|
||||
+0x060 text_size 0x00000290
|
||||
+0x080 data_addr 0x018d0000
|
||||
+0x0a0 data_size 0x00000040
|
||||
+0x0c0 bss_addr 0x018d8000
|
||||
+0x0e0 bss_size 0x00000040
|
||||
+0x100 relocs 0x00000000
|
||||
+0x120 pcb 0x003fe310
|
||||
+0x140 nscns 0x00000003
|
||||
+0x160 coff_len 0x000001fe
|
||||
+0x180 loader_base 0x01880000
|
||||
[.] marker start 0x018c0000 (want 0x018c0000)
|
||||
[.] marker data 0xdeadbeef (want 0xdeadbeef)
|
||||
[.] marker data2 0x12345678 (want 0x12345678)
|
||||
[.] marker bss 0x00000000 (want 0x00000000)
|
||||
[.] marker count 268 -> 794 (child scheduled)
|
||||
[+] PASS: status=0 pcb=0x003fe310 entry=0x018c0000 (tftp_marker_boot3)
|
||||
@@ -0,0 +1,34 @@
|
||||
[.] COFF /home/arti/code/k-space/vt1200/dwt/loader/build/marker.coff: 510 B, 3 sections, entry=0x018c0000 sha256=519e4724aa537436a35f5e49a3306b3f6bcebdc216a0ce4c103822b0df28d749
|
||||
.text paddr=0x018c0000 size=656 bits (82 B) nreloc=0
|
||||
.data paddr=0x018d0000 size=64 bits (8 B) nreloc=0
|
||||
.bss paddr=0x018d8000 size=64 bits (8 B) nreloc=0
|
||||
[.] connected 192.168.99.2:771; opcode 7 -> flag=0x0 b'Done\n\x00'
|
||||
[.] tftpc poked 694 B at 0x01870000 (347 words, 0 differing)
|
||||
[.] jump returned 0x00000000 (0)
|
||||
[.] tftpc markers: stage=4 fd=1 buf=0x9fccd0 total=510 last=514 block=0x100 done=0x5a5a5a5
|
||||
[.] server RRQ (dwt/loader/evidence/hostload/serve_tftp_marker.log): 15:32:16 RRQ 192.168.99.2:1025 requested 'dwt/tcpip/probe.bin' (510 bytes)
|
||||
[+] TFTP fetch verified byte-for-byte: 510 B at 0x009fccd0 (sha256=519e4724aa537436a35f5e49a3306b3f6bcebdc216a0ce4c103822b0df28d749)
|
||||
[+] loader poked 1220 B at 0x01880000 (610 words, 0 differing)
|
||||
[.] descriptor @ 0x01882c00: 44 4c 31 52 d0 cc 9f 00 fe 01 00 00 01 00 00 00 (magic 4C44/5231, buf=0x009fccd0, len=510, mode=1)
|
||||
[.] jump returned 0x00000000 (0)
|
||||
[.] loader A8=0x0 (OK)
|
||||
[.] result block @ 0x1882d00:
|
||||
+0x000 status 0x00000000
|
||||
+0x020 entry 0x018c0000
|
||||
+0x040 text_addr 0x018c0000
|
||||
+0x060 text_size 0x00000290
|
||||
+0x080 data_addr 0x018d0000
|
||||
+0x0a0 data_size 0x00000040
|
||||
+0x0c0 bss_addr 0x018d8000
|
||||
+0x0e0 bss_size 0x00000040
|
||||
+0x100 relocs 0x00000000
|
||||
+0x120 pcb 0x003fe310
|
||||
+0x140 nscns 0x00000003
|
||||
+0x160 coff_len 0x000001fe
|
||||
+0x180 loader_base 0x01880000
|
||||
[.] marker start 0x018c0000 (want 0x018c0000)
|
||||
[.] marker data 0xdeadbeef (want 0xdeadbeef)
|
||||
[.] marker data2 0x12345678 (want 0x12345678)
|
||||
[.] marker bss 0x00000000 (want 0x00000000)
|
||||
[.] marker count 269 -> 14890 (child scheduled)
|
||||
[+] PASS: status=0 pcb=0x003fe310 entry=0x018c0000 (tftp_marker_boot4)
|
||||
@@ -0,0 +1,30 @@
|
||||
[.] COFF /home/arti/code/k-space/vt1200/dwt/loader/build/xhello.coff: 774 B, 3 sections, entry=0x01840000 sha256=a8b3014d27deb97adcebb418a5d14da51fc3c11559e84923ede72e260d3e7271
|
||||
.data paddr=0x00000000 size=0 bits (0 B) nreloc=0
|
||||
.bss paddr=0x00000000 size=0 bits (0 B) nreloc=0
|
||||
.text paddr=0x01840000 size=3120 bits (390 B) nreloc=0
|
||||
[.] connected 192.168.99.2:771; opcode 7 -> flag=0x0 b'Done\n\x00'
|
||||
[.] jump returned 0x007c82d0 (8159952)
|
||||
[+] jump(malloc) -> 0x007c82d0; bit 0x007c82d0 = byte 0x0f905a, 774 bytes, bit range 0x007c82d0..0x007c9b00
|
||||
[+] COFF poked 774 B at 0x007c82d0 (387 words, 0 differing bytes)
|
||||
readback[0:774] 90 00 03 00 0c e0 d4 6a 2e 02 00 00 0c 00 00 00 1c 00 03 01 08 01 c7 00 30 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 84 01 00 00 00 00 2e 64 61 74 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 2e 62 73 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 2e 74 65 78 74 00 00 00 00 00 84 01 00 00 84 01 30 0c 00 00 a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 50 05 40 07 8f 09 00 ff 8f 07 20 04 89 01 8e 07 00 04 89 01 e0 09 01 00 00 00 80 07 40 01 89 01 cf a3 ee 09 00 20 89 01 e0 09 48 e9 ac 3f 0e 92 5f 0d d0 58 b4 3f af 07 20 04 89 01 ae 07 00 04 89 01 50 05 40 07 88 07 60 01 89 01 e0 09 04 00 00 00 08 48 00 cb 91 00 e0 09 02 00 00 00 80 07 40 01 89 01 cf a3 ee 09 00 20 89 01 e0 09 48 e9 ac 3f 0e 92 5f 0d 70 25 9c 3f af 07 20 04 89 01 ae 07 00 04 89 01 50 05 40 07 0b 4d 8b 07 00 01 89 01 6b 4d 72 ca e0 09 03 00 00 00 80 07 40 01 89 01 6a b7 80 04 4a b7 40 00 8a 07 10 01 89 01 cf a3 ee 09 00 20 89 01 e0 09 00 00 00 00 0e 92 0e 92 e0 09 02 00 00 00 0e 92 e0 09 c8 00 00 00 0e 92 e0 09 90 01 00 00 0e 92 e0 09 64 00 00 00 0e 92 0e 92 4e 93 6e 93 5f 0d 90 1b d4 3f af 07 20 04 89 01 ae 07 00 04 89 01 50 05 40 07 0a 4d 8a 07 20 01 89 01 e0 09 04 00 00 00 80 07 40 01 89 01 cf a3 ee 09 00 20 89 01 4e 93 6e 93 5f 0d b0 45 d6 3f af 07 20 04 89 01 ae 07 00 04 89 01 50 05 40 07 e0 09 05 00 00 00 80 07 40 01 89 01 cf a3 ee 09 00 20 89 01 e0 09 00 00 00 00 0e 92 6e 93 5f 0d b0 f6 d9 3f af 07 20 04 89 01 ae 07 00 04 89 01 50 05 40 07 88 07 30 01 89 01 e0 09 06 00 00 00 80 07 40 01 89 01 af 09 ff 00 e8 09 00 00 00 00 60 09 2e 74 65 78 74 00 00 00 00 00 84 01 03 00 00 00 03 01 30 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 64 61 74 61 00 00 00 00 00 00 00 01 00 00 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 62 73 73 00 00 00 00 00 00 00 00 02 00 00 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 74 65 78 74 00 00 00 00 00 84 01 03 00 00 00 02 00 65 74 65 78 74 00 00 00 30 0c 84 01 03 00 00 00 02 00 2e 64 61 74 61 00 00 00 00 00 00 00 01 00 00 00 02 00 65 64 61 74 61 00 00 00 00 00 00 00 01 00 00 00 02 00 2e 62 73 73 00 00 00 00 00 00 00 00 02 00 00 00 02 00 65 6e 64 00 00 00 00 00 00 00 00 00 02 00 00 00 02 00
|
||||
[+] loader poked 1220 B at 0x01880000 (610 words, 0 differing)
|
||||
[.] descriptor @ 0x01882c00: 44 4c 31 52 d0 82 7c 00 06 03 00 00 01 00 00 00 (magic 4C44/5231, buf=0x007c82d0, len=774, mode=1)
|
||||
[.] jump returned 0x00000000 (0)
|
||||
[.] loader A8=0x0 (OK)
|
||||
[.] result block @ 0x1882d00:
|
||||
+0x000 status 0x00000000
|
||||
+0x020 entry 0x01840000
|
||||
+0x040 text_addr 0x01840000
|
||||
+0x060 text_size 0x00000c30
|
||||
+0x080 data_addr 0x00000000
|
||||
+0x0a0 data_size 0x00000000
|
||||
+0x0c0 bss_addr 0x00000000
|
||||
+0x0e0 bss_size 0x00000000
|
||||
+0x100 relocs 0x00000000
|
||||
+0x120 pcb 0x003fe0d0
|
||||
+0x140 nscns 0x00000003
|
||||
+0x160 coff_len 0x00000306
|
||||
+0x180 loader_base 0x01880000
|
||||
[.] xhello stage=6 strlen=4
|
||||
[+] screenshot dwt/loader/evidence/hostload/hostload_xhello_boot3_xhello.png (6696 bytes), raw dwt/loader/evidence/hostload/hostload_xhello_boot3_xhello.vram
|
||||
[+] PASS: status=0 pcb=0x003fe0d0 entry=0x01840000 (xhello_boot3)
|
||||
@@ -0,0 +1,30 @@
|
||||
[.] COFF /home/arti/code/k-space/vt1200/dwt/loader/build/xhello.coff: 774 B, 3 sections, entry=0x01840000 sha256=a8b3014d27deb97adcebb418a5d14da51fc3c11559e84923ede72e260d3e7271
|
||||
.data paddr=0x00000000 size=0 bits (0 B) nreloc=0
|
||||
.bss paddr=0x00000000 size=0 bits (0 B) nreloc=0
|
||||
.text paddr=0x01840000 size=3120 bits (390 B) nreloc=0
|
||||
[.] connected 192.168.99.2:771; opcode 7 -> flag=0x0 b'Done\n\x00'
|
||||
[.] jump returned 0x007c9070 (8163440)
|
||||
[+] jump(malloc) -> 0x007c9070; bit 0x007c9070 = byte 0x0f920e, 774 bytes, bit range 0x007c9070..0x007ca8a0
|
||||
[+] COFF poked 774 B at 0x007c9070 (387 words, 0 differing bytes)
|
||||
readback[0:774] 90 00 03 00 0c e0 d4 6a 2e 02 00 00 0c 00 00 00 1c 00 03 01 08 01 c7 00 30 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 84 01 00 00 00 00 2e 64 61 74 61 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 40 00 00 00 2e 62 73 73 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 80 00 00 00 2e 74 65 78 74 00 00 00 00 00 84 01 00 00 84 01 30 0c 00 00 a8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 50 05 40 07 8f 09 00 ff 8f 07 20 04 89 01 8e 07 00 04 89 01 e0 09 01 00 00 00 80 07 40 01 89 01 cf a3 ee 09 00 20 89 01 e0 09 48 e9 ac 3f 0e 92 5f 0d d0 58 b4 3f af 07 20 04 89 01 ae 07 00 04 89 01 50 05 40 07 88 07 60 01 89 01 e0 09 04 00 00 00 08 48 00 cb 91 00 e0 09 02 00 00 00 80 07 40 01 89 01 cf a3 ee 09 00 20 89 01 e0 09 48 e9 ac 3f 0e 92 5f 0d 70 25 9c 3f af 07 20 04 89 01 ae 07 00 04 89 01 50 05 40 07 0b 4d 8b 07 00 01 89 01 6b 4d 72 ca e0 09 03 00 00 00 80 07 40 01 89 01 6a b7 80 04 4a b7 40 00 8a 07 10 01 89 01 cf a3 ee 09 00 20 89 01 e0 09 00 00 00 00 0e 92 0e 92 e0 09 02 00 00 00 0e 92 e0 09 c8 00 00 00 0e 92 e0 09 90 01 00 00 0e 92 e0 09 64 00 00 00 0e 92 0e 92 4e 93 6e 93 5f 0d 90 1b d4 3f af 07 20 04 89 01 ae 07 00 04 89 01 50 05 40 07 0a 4d 8a 07 20 01 89 01 e0 09 04 00 00 00 80 07 40 01 89 01 cf a3 ee 09 00 20 89 01 4e 93 6e 93 5f 0d b0 45 d6 3f af 07 20 04 89 01 ae 07 00 04 89 01 50 05 40 07 e0 09 05 00 00 00 80 07 40 01 89 01 cf a3 ee 09 00 20 89 01 e0 09 00 00 00 00 0e 92 6e 93 5f 0d b0 f6 d9 3f af 07 20 04 89 01 ae 07 00 04 89 01 50 05 40 07 88 07 30 01 89 01 e0 09 06 00 00 00 80 07 40 01 89 01 af 09 ff 00 e8 09 00 00 00 00 60 09 2e 74 65 78 74 00 00 00 00 00 84 01 03 00 00 00 03 01 30 0c 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 64 61 74 61 00 00 00 00 00 00 00 01 00 00 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 62 73 73 00 00 00 00 00 00 00 00 02 00 00 00 03 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 2e 74 65 78 74 00 00 00 00 00 84 01 03 00 00 00 02 00 65 74 65 78 74 00 00 00 30 0c 84 01 03 00 00 00 02 00 2e 64 61 74 61 00 00 00 00 00 00 00 01 00 00 00 02 00 65 64 61 74 61 00 00 00 00 00 00 00 01 00 00 00 02 00 2e 62 73 73 00 00 00 00 00 00 00 00 02 00 00 00 02 00 65 6e 64 00 00 00 00 00 00 00 00 00 02 00 00 00 02 00
|
||||
[+] loader poked 1220 B at 0x01880000 (610 words, 0 differing)
|
||||
[.] descriptor @ 0x01882c00: 44 4c 31 52 70 90 7c 00 06 03 00 00 01 00 00 00 (magic 4C44/5231, buf=0x007c9070, len=774, mode=1)
|
||||
[.] jump returned 0x00000000 (0)
|
||||
[.] loader A8=0x0 (OK)
|
||||
[.] result block @ 0x1882d00:
|
||||
+0x000 status 0x00000000
|
||||
+0x020 entry 0x01840000
|
||||
+0x040 text_addr 0x01840000
|
||||
+0x060 text_size 0x00000c30
|
||||
+0x080 data_addr 0x00000000
|
||||
+0x0a0 data_size 0x00000000
|
||||
+0x0c0 bss_addr 0x00000000
|
||||
+0x0e0 bss_size 0x00000000
|
||||
+0x100 relocs 0x00000000
|
||||
+0x120 pcb 0x003fe0d0
|
||||
+0x140 nscns 0x00000003
|
||||
+0x160 coff_len 0x00000306
|
||||
+0x180 loader_base 0x01880000
|
||||
[.] xhello stage=6 strlen=4
|
||||
[+] screenshot dwt/loader/evidence/hostload/hostload_xhello_boot4_xhello.png (6696 bytes), raw dwt/loader/evidence/hostload/hostload_xhello_boot4_xhello.vram
|
||||
[+] PASS: status=0 pcb=0x003fe0d0 entry=0x01840000 (xhello_boot4)
|
||||
@@ -0,0 +1,574 @@
|
||||
#!/usr/bin/env python3
|
||||
"""hostload.py -- end-to-end host-side app loader over the stock rdebug service.
|
||||
|
||||
One driver, one TCP connection to the terminal's `DEBUG TCP Port` (771):
|
||||
|
||||
rdebug ---- malloc(size) --> bit pointer
|
||||
---- poke COFF ---> that buffer
|
||||
---- poke loader -> bit 0x01880000
|
||||
---- poke descriptor @ 0x01882C00
|
||||
---- jump 0x01880000 -> status in A8 + result block
|
||||
---- peek markers / screenshot
|
||||
|
||||
The COFF loader itself (`dwt/loader/loader.asm`, 1220 B) is position-dependent
|
||||
and lives at bit `0x01880000`. This script only supplies its input and reads
|
||||
its result; it does not choose load addresses (the COFF section headers do) and
|
||||
does not patch the ROM.
|
||||
|
||||
Two transports for the COFF:
|
||||
|
||||
* default -- poke the file into a `malloc`'d buffer from the host.
|
||||
* --tftp -- poke the existing `dwt/tcpip/tftpc.bin` (bit 0x01870000), jump
|
||||
it, and read the buffer/length it fetched. The TFTP server must be serving
|
||||
the COFF *content* for any requested name, because tftpc.asm's RRQ name is
|
||||
fixed (`dwt/tcpip/probe.bin`):
|
||||
|
||||
sudo python3 -u dwt/tcpip/serve_probe.py 192.168.99.1 --bootp \
|
||||
--file dwt/loader/build/marker.coff
|
||||
|
||||
That server must already be answering BOOTP so the terminal has 192.168.99.2.
|
||||
|
||||
Addresses are TMS34010 **bit** addresses throughout; `poke`/`peek` convert by
|
||||
8 bits per byte, and the malloc return is used verbatim as a bit pointer.
|
||||
|
||||
Exit status: 0 only when the loader returned status 0, the result block is
|
||||
consistent, and the app's own evidence verifies (markers, or X stage + frame).
|
||||
|
||||
Examples:
|
||||
|
||||
# marker app: markers at 0x018E0000.. (start/data/data2/bss/counter)
|
||||
python3 dwt/loader/hostload.py --host 192.168.99.2 \
|
||||
--coff dwt/loader/build/marker.coff --marker \
|
||||
--out dwt/loader/evidence/hostload --tag marker
|
||||
|
||||
# xhello: X window, verified by stage==6 and a VRAM screenshot
|
||||
python3 dwt/loader/hostload.py --host 192.168.99.2 \
|
||||
--coff dwt/loader/build/xhello.coff \
|
||||
--out dwt/loader/evidence/hostload --tag xhello
|
||||
|
||||
# self-contained fetch: no COFF poke, tftpc fetches it into malloc memory
|
||||
python3 dwt/loader/hostload.py --host 192.168.99.2 --tftp \
|
||||
--coff dwt/loader/build/marker.coff --marker \
|
||||
--tftp-log dwt/loader/evidence/hostload/serve_tftp_marker.log \
|
||||
--tag tftp_marker
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import argparse
|
||||
import hashlib
|
||||
import os
|
||||
import struct
|
||||
import sys
|
||||
import time
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__)) # dwt/loader
|
||||
DWT = os.path.dirname(HERE) # dwt
|
||||
ROOT = os.path.dirname(DWT) # repo root
|
||||
sys.path.insert(0, DWT)
|
||||
|
||||
import exploit # noqa: E402
|
||||
|
||||
# --- fixed loader contract (dwt/notes/LOADER_CROSS.md) ---------------------
|
||||
LOADER_BASE = 0x01880000
|
||||
LOADER_PAGE_END = 0x01883200
|
||||
DESC = 0x01882C00
|
||||
RESULT = 0x01882D00
|
||||
MALLOC = 0x3F701230
|
||||
RAM_BITS = 0x2000000 # 4 MiB, in bits
|
||||
|
||||
# Result-block cell offsets. These are BIT offsets (loader.asm uses
|
||||
# `RESULT_BASE+020h`, and the TMS34010 assembler's addresses are bit
|
||||
# addresses), so 0x020 bits is byte +4, not +0x20 bytes. The block is 13
|
||||
# adjacent 32-bit cells, 52 bytes total.
|
||||
RESULT_CELLS = {
|
||||
0x000: "status",
|
||||
0x020: "entry",
|
||||
0x040: "text_addr",
|
||||
0x060: "text_size",
|
||||
0x080: "data_addr",
|
||||
0x0A0: "data_size",
|
||||
0x0C0: "bss_addr",
|
||||
0x0E0: "bss_size",
|
||||
0x100: "relocs",
|
||||
0x120: "pcb",
|
||||
0x140: "nscns",
|
||||
0x160: "coff_len",
|
||||
0x180: "loader_base",
|
||||
}
|
||||
RESULT_BYTES = 0x34 # 0x180 bits + 4 bytes
|
||||
|
||||
STATUS_NAMES = {
|
||||
0: "OK",
|
||||
1: "bad descriptor",
|
||||
2: "truncated COFF / section headers",
|
||||
3: "bad COFF magic",
|
||||
4: "section size not whole words",
|
||||
5: "target outside RAM",
|
||||
6: "target overlaps loader page or COFF buffer",
|
||||
7: "relocation records present (unsupported)",
|
||||
8: "target not in a free-list block",
|
||||
9: "no entry point",
|
||||
10: "create_process returned 0",
|
||||
}
|
||||
|
||||
# tftpc.asm markers (dwt/tcpip/tftpc.asm)
|
||||
TFTPC_BASE = 0x01870000
|
||||
TFTP_MARK = 0x0187C000
|
||||
TFTP_DONE = 0x05A5A5A5
|
||||
|
||||
# app marker cells
|
||||
MARKER_CELLS = [
|
||||
(0x018E0000, "start"),
|
||||
(0x018E0020, "data"),
|
||||
(0x018E0040, "data2"),
|
||||
(0x018E0060, "bss"),
|
||||
(0x018E0080, "count"),
|
||||
]
|
||||
XHELLO_STAGE = 0x01890140
|
||||
XHELLO_STRLEN = 0x01890160
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# small helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def parse_int(text: str) -> int:
|
||||
text = text.strip().replace("_", "")
|
||||
if text.lower().startswith("0x"):
|
||||
return int(text, 16)
|
||||
if any(c in "abcdefABCDEF" for c in text):
|
||||
return int(text, 16)
|
||||
return int(text, 10)
|
||||
|
||||
|
||||
def u16(d: bytes, off: int) -> int:
|
||||
return struct.unpack_from("<H", d, off)[0]
|
||||
|
||||
|
||||
def u32(d: bytes, off: int) -> int:
|
||||
return struct.unpack_from("<I", d, off)[0]
|
||||
|
||||
|
||||
def overlaps(a0: int, a1: int, b0: int, b1: int) -> bool:
|
||||
"""Half-open ranges [a0,a1) and [b0,b1) in the same unit."""
|
||||
return a0 < b1 and b0 < a1
|
||||
|
||||
|
||||
def parse_coff(data: bytes) -> dict:
|
||||
"""Minimal TI COFF header/section reader (same fields as coff.py)."""
|
||||
if len(data) < 20:
|
||||
raise ValueError("shorter than a COFF file header")
|
||||
magic, nscns = u16(data, 0), u16(data, 2)
|
||||
opthdr = u16(data, 16)
|
||||
if magic != 0x0090:
|
||||
raise ValueError(f"COFF magic {magic:#06x}, expected 0x0090")
|
||||
if 20 + opthdr > len(data):
|
||||
raise ValueError("optional header past EOF")
|
||||
entry = textstart = None
|
||||
if opthdr:
|
||||
entry = u32(data, 20 + 16)
|
||||
textstart = u32(data, 20 + 20)
|
||||
sections = []
|
||||
base = 20 + opthdr
|
||||
for i in range(nscns):
|
||||
off = base + i * 40
|
||||
if off + 40 > len(data):
|
||||
raise ValueError(f"section header {i} past EOF")
|
||||
name = data[off:off + 8].rstrip(b"\0").decode("latin-1")
|
||||
paddr = u32(data, off + 8)
|
||||
size = u32(data, off + 16)
|
||||
scnptr = u32(data, off + 20)
|
||||
nreloc = u16(data, off + 32)
|
||||
flags = u32(data, off + 36)
|
||||
sections.append(dict(name=name, paddr=paddr, size=size,
|
||||
scnptr=scnptr, nreloc=nreloc, flags=flags))
|
||||
return dict(magic=magic, nscns=nscns, opthdr=opthdr,
|
||||
entry=entry or 0, textstart=textstart or 0,
|
||||
sections=sections)
|
||||
|
||||
|
||||
def poke_bytes(rd: exploit.RDebug, bit_addr: int, data: bytes,
|
||||
chunk: int = exploit.MAX_XFER) -> None:
|
||||
for off in range(0, len(data), chunk):
|
||||
rd.poke(bit_addr + off * 8, data[off:off + chunk])
|
||||
|
||||
|
||||
def peek_bytes(rd: exploit.RDebug, bit_addr: int, length: int) -> bytes:
|
||||
out = bytearray()
|
||||
while len(out) < length:
|
||||
n = min(exploit.MAX_XFER, length - len(out))
|
||||
out += rd.peek(bit_addr + len(out) * 8, n)
|
||||
return bytes(out)
|
||||
|
||||
|
||||
def peek_u32(rd: exploit.RDebug, bit_addr: int) -> int:
|
||||
return struct.unpack("<I", peek_bytes(rd, bit_addr, 4))[0]
|
||||
|
||||
|
||||
def compare(rd: exploit.RDebug, bit_addr: int, data: bytes) -> tuple[int, int]:
|
||||
"""Peek *data* back and return (words, differing bytes)."""
|
||||
got = peek_bytes(rd, bit_addr, len(data))
|
||||
bad = sum(1 for a, b in zip(got, data) if a != b)
|
||||
return (len(data) + 1) // 2, bad
|
||||
|
||||
|
||||
def check_buffer(ptr: int, nbytes: int, coff: dict) -> list[str]:
|
||||
"""Sanity-check a malloc'd bit pointer. Returns a list of problems."""
|
||||
problems = []
|
||||
end = ptr + nbytes * 8
|
||||
if ptr == 0:
|
||||
problems.append("malloc returned 0")
|
||||
return problems
|
||||
if ptr % 8:
|
||||
problems.append(f"pointer {ptr:#010x} is not byte-aligned "
|
||||
f"(byte offset {ptr % 8})")
|
||||
if ptr < 0x100 or end > RAM_BITS:
|
||||
problems.append(f"range {ptr:#010x}..{end:#010x} is outside RAM")
|
||||
if overlaps(ptr, end, LOADER_BASE, LOADER_PAGE_END):
|
||||
problems.append("buffer overlaps the loader page")
|
||||
for sec in coff["sections"]:
|
||||
if sec["size"] and overlaps(ptr, end, sec["paddr"],
|
||||
sec["paddr"] + sec["size"]):
|
||||
problems.append(f"buffer overlaps section {sec['name']} "
|
||||
f"at {sec['paddr']:#010x}")
|
||||
for cell, name in MARKER_CELLS:
|
||||
if overlaps(ptr, end, cell, cell + 0x20):
|
||||
problems.append(f"buffer overlaps marker cell {name}")
|
||||
if overlaps(ptr, end, 0x01890100, 0x01890170):
|
||||
problems.append("buffer overlaps the xhello marker cells")
|
||||
return problems
|
||||
|
||||
|
||||
def describe_pointer(ptr: int, nbytes: int) -> str:
|
||||
return (f"bit {ptr:#010x} = byte {ptr >> 3:#08x}, {nbytes} bytes, "
|
||||
f"bit range {ptr:#010x}..{ptr + nbytes * 8:#010x}")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# screenshot / frame helpers
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def screenshot_vram(rd: exploit.RDebug, out_png: str,
|
||||
out_raw: str | None = None) -> bytes:
|
||||
"""Grab the 1024x1024 VRAM canvas using dwt/screenshot.py primitives."""
|
||||
import screenshot # imported here so marker-only runs need no PNG path
|
||||
|
||||
data = screenshot.grab(rd, 0, screenshot.HEIGHT, True)
|
||||
gray = screenshot.decode(data)
|
||||
screenshot.write_png(out_png, screenshot.WIDTH, screenshot.HEIGHT, gray)
|
||||
if out_raw:
|
||||
with open(out_raw, "wb") as fh:
|
||||
fh.write(data)
|
||||
return data
|
||||
|
||||
|
||||
def wait_for_frame(path: str, timeout: float) -> bool:
|
||||
end = time.monotonic() + timeout
|
||||
while time.monotonic() < end:
|
||||
if os.path.exists(path) and os.path.getsize(path) > 0:
|
||||
return True
|
||||
time.sleep(0.5)
|
||||
return os.path.exists(path) and os.path.getsize(path) > 0
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# the loader sequence
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def read_desc(rd: exploit.RDebug) -> bytes:
|
||||
return peek_bytes(rd, DESC, 16)
|
||||
|
||||
|
||||
def write_desc(rd: exploit.RDebug, buf: int, length: int) -> bytes:
|
||||
desc = struct.pack("<HHIII", 0x4C44, 0x5231, buf, length, 1)
|
||||
poke_bytes(rd, DESC, desc)
|
||||
got = read_desc(rd)
|
||||
if got != desc:
|
||||
raise RuntimeError(f"descriptor readback mismatch: wrote {desc.hex(' ')}, "
|
||||
f"read {got.hex(' ')}")
|
||||
return desc
|
||||
|
||||
|
||||
def read_result(rd: exploit.RDebug) -> dict:
|
||||
raw = peek_bytes(rd, RESULT, RESULT_BYTES)
|
||||
# RESULT_CELLS keys are bit offsets; the peeked buffer is bytes.
|
||||
return {name: u32(raw, off // 8) for off, name in RESULT_CELLS.items()}
|
||||
|
||||
|
||||
def run_loader(rd: exploit.RDebug, buf: int, coff_len: int,
|
||||
jump_wait: float) -> tuple[int, dict]:
|
||||
# Rewritten immediately before the call: create_process uses ARG_AREA
|
||||
# (0x01882B00) and its 0x100-bit call frame lands on the descriptor, so a
|
||||
# descriptor left from a previous run is not trustworthy.
|
||||
desc = write_desc(rd, buf, coff_len)
|
||||
print(f"[.] descriptor @ {DESC:#010x}: {desc.hex(' ')} "
|
||||
f"(magic 4C44/5231, buf={buf:#010x}, len={coff_len}, mode=1)")
|
||||
res = rd.jump(LOADER_BASE, [], wait=True, wait_timeout=jump_wait)
|
||||
if res is None:
|
||||
raise RuntimeError(f"loader at {LOADER_BASE:#010x} did not return within "
|
||||
f"{jump_wait}s")
|
||||
status = res[0]
|
||||
result = read_result(rd)
|
||||
print(f"[.] loader A8={status:#x} ({STATUS_NAMES.get(status, 'unknown')})")
|
||||
print("[.] result block @ {:#x} (cell offsets are bit offsets):".format(
|
||||
RESULT))
|
||||
for off, name in RESULT_CELLS.items():
|
||||
print(f" +{off:#05x} {name:<12} {result[name]:#010x}")
|
||||
problems = []
|
||||
if status != 0:
|
||||
problems.append(f"loader status {status} ({STATUS_NAMES.get(status, '?')})")
|
||||
if result["status"] != status:
|
||||
problems.append(f"result status {result['status']} != A8 {status}")
|
||||
if result["loader_base"] != LOADER_BASE:
|
||||
problems.append(f"result loader_base {result['loader_base']:#x} != "
|
||||
f"{LOADER_BASE:#x}")
|
||||
if result["pcb"] == 0:
|
||||
problems.append("create_process returned a null PCB")
|
||||
if result["coff_len"] != coff_len:
|
||||
problems.append(f"result coff_len {result['coff_len']} != {coff_len}")
|
||||
if problems:
|
||||
raise RuntimeError("; ".join(problems))
|
||||
return status, result
|
||||
|
||||
|
||||
def verify_markers(rd: exploit.RDebug, result: dict, settle: float) -> list[str]:
|
||||
problems = []
|
||||
vals = {name: peek_u32(rd, cell) for cell, name in MARKER_CELLS}
|
||||
time.sleep(settle)
|
||||
vals2 = {name: peek_u32(rd, cell) for cell, name in MARKER_CELLS}
|
||||
for name, want in (("start", result["entry"]), ("data", 0xDEADBEEF),
|
||||
("data2", 0x12345678), ("bss", 0)):
|
||||
got = vals[name]
|
||||
print(f"[.] marker {name:<6} {got:#010x} (want {want:#010x})")
|
||||
if got != want:
|
||||
problems.append(f"marker {name}={got:#x}, want {want:#x}")
|
||||
c0, c1 = vals["count"], vals2["count"]
|
||||
print(f"[.] marker count {c0} -> {c1} (child scheduled)")
|
||||
if c1 == c0:
|
||||
problems.append("marker counter did not advance")
|
||||
return problems
|
||||
|
||||
|
||||
def verify_xhello(rd: exploit.RDebug, out_dir: str, tag: str, settle: float,
|
||||
take_shot: bool) -> list[str]:
|
||||
problems = []
|
||||
time.sleep(settle)
|
||||
stage = peek_u32(rd, XHELLO_STAGE)
|
||||
strlen = peek_u32(rd, XHELLO_STRLEN)
|
||||
print(f"[.] xhello stage={stage} strlen={strlen}")
|
||||
if stage != 6:
|
||||
problems.append(f"xhello stage={stage}, want 6 (XSync done)")
|
||||
if strlen != 4:
|
||||
problems.append(f"xhello strlen={strlen}, want 4 "
|
||||
f"(calling-convention check)")
|
||||
if take_shot:
|
||||
png = os.path.join(out_dir, f"hostload_{tag}_xhello.png")
|
||||
data = screenshot_vram(rd, png)
|
||||
print(f"[+] screenshot {png} ({os.path.getsize(png)} bytes, "
|
||||
f"{len(data)} bytes of VRAM)")
|
||||
return problems
|
||||
|
||||
|
||||
def tftp_fetch(rd: exploit.RDebug, tftpc_path: str, coff_len: int,
|
||||
jump_wait: float) -> tuple[int, int]:
|
||||
tftpc = open(tftpc_path, "rb").read()
|
||||
poke_bytes(rd, TFTPC_BASE, tftpc)
|
||||
words, bad = compare(rd, TFTPC_BASE, tftpc)
|
||||
print(f"[.] tftpc poked {len(tftpc)} B at {TFTPC_BASE:#010x} "
|
||||
f"({words} words, {bad} differing)")
|
||||
if bad:
|
||||
raise RuntimeError("tftpc readback mismatch")
|
||||
res = rd.jump(TFTPC_BASE, [], wait=True, wait_timeout=jump_wait)
|
||||
if res is None:
|
||||
raise RuntimeError(f"tftpc at {TFTPC_BASE:#010x} did not return within "
|
||||
f"{jump_wait}s (server running? file served?)")
|
||||
marks = {name: peek_u32(rd, TFTP_MARK + off)
|
||||
for off, name in ((0x00, "stage"), (0x20, "fd"), (0x40, "buf"),
|
||||
(0x60, "total"), (0x80, "last"),
|
||||
(0xA0, "block"), (0xC0, "done"))}
|
||||
print("[.] tftpc markers: " + " ".join(
|
||||
f"{k}={v:#x}" if k in ("buf", "done", "block") else f"{k}={v}"
|
||||
for k, v in marks.items()))
|
||||
if marks["stage"] != 4 or marks["done"] != TFTP_DONE:
|
||||
raise RuntimeError("tftpc did not complete (stage/done marker wrong)")
|
||||
if marks["total"] != coff_len:
|
||||
raise RuntimeError(f"tftpc fetched {marks['total']} bytes, "
|
||||
f"COFF is {coff_len}")
|
||||
return marks["buf"], marks["total"]
|
||||
|
||||
|
||||
def print_tftp_rrq(path: str | None) -> None:
|
||||
if not path or not os.path.exists(path):
|
||||
return
|
||||
lines = [ln.rstrip() for ln in open(path, errors="replace") if "RRQ" in ln]
|
||||
if lines:
|
||||
print(f"[.] server RRQ ({path}): {lines[-1]}")
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# main
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def main(argv: list[str]) -> int:
|
||||
ap = argparse.ArgumentParser(
|
||||
description="End-to-end rdebug app loader: malloc -> poke COFF -> "
|
||||
"COFF loader @0x01880000 -> create_process -> verify.",
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter)
|
||||
ap.add_argument("--host", default="192.168.99.2")
|
||||
ap.add_argument("--port", type=int, default=771)
|
||||
ap.add_argument("--timeout", type=float, default=10.0)
|
||||
ap.add_argument("--coff", required=True, help="linked GSPLNK COFF image")
|
||||
ap.add_argument("--loader", default=os.path.join(HERE, "build", "loader.bin"),
|
||||
help="raw loader image (default dwt/loader/build/loader.bin)")
|
||||
ap.add_argument("--no-poke-loader", action="store_true",
|
||||
help="do not write the loader; verify it is already resident")
|
||||
ap.add_argument("--marker", action="store_true",
|
||||
help="verify marker.coff evidence cells (otherwise inferred "
|
||||
"from the file name)")
|
||||
ap.add_argument("--tftp", action="store_true",
|
||||
help="fetch the COFF with dwt/tcpip/tftpc.bin instead of "
|
||||
"poking it")
|
||||
ap.add_argument("--tftpc", default=os.path.join(ROOT, "dwt", "tcpip",
|
||||
"build", "tftpc.bin"),
|
||||
help="raw TFTP client image (default dwt/tcpip/build/tftpc.bin)")
|
||||
ap.add_argument("--tftp-log", default=None,
|
||||
help="server log to quote the RRQ line from (optional)")
|
||||
ap.add_argument("--frame", type=parse_int, default=None, metavar="N",
|
||||
help="wait for MAME's VT1200_DUMP_FRAME=N PPM (boot-relative; "
|
||||
"the dump must be configured on the MAME side)")
|
||||
ap.add_argument("--dump-dir", default=os.getcwd(),
|
||||
help="directory searched for vt1200-frame-N.ppm")
|
||||
ap.add_argument("--frame-timeout", type=float, default=120.0)
|
||||
ap.add_argument("--out", default=os.path.join(HERE, "evidence", "hostload"),
|
||||
help="evidence directory (default dwt/loader/evidence/hostload)")
|
||||
ap.add_argument("--tag", default=None,
|
||||
help="evidence file tag (default: COFF basename)")
|
||||
ap.add_argument("--settle", type=float, default=1.5,
|
||||
help="seconds to wait for the child/window after the load")
|
||||
ap.add_argument("--no-screenshot", action="store_true",
|
||||
help="do not grab VRAM for xhello")
|
||||
ap.add_argument("--jump-wait", type=float, default=20.0,
|
||||
help="seconds to wait for the loader call to return")
|
||||
ap.add_argument("--verbose", action="store_true")
|
||||
args = ap.parse_args(argv[1:])
|
||||
|
||||
coff_path = os.path.abspath(args.coff)
|
||||
coff = open(coff_path, "rb").read()
|
||||
try:
|
||||
info = parse_coff(coff)
|
||||
except ValueError as exc:
|
||||
print(f"error: {coff_path}: {exc}", file=sys.stderr)
|
||||
return 2
|
||||
tag = args.tag or os.path.splitext(os.path.basename(coff_path))[0]
|
||||
os.makedirs(args.out, exist_ok=True)
|
||||
marker_mode = args.marker or "marker" in os.path.basename(coff_path).lower()
|
||||
xhello_mode = "xhello" in os.path.basename(coff_path).lower()
|
||||
|
||||
print(f"[.] COFF {coff_path}: {len(coff)} B, {info['nscns']} sections, "
|
||||
f"entry={info['entry'] or info['textstart']:#010x} "
|
||||
f"sha256={hashlib.sha256(coff).hexdigest()}")
|
||||
for sec in info["sections"]:
|
||||
print(f" {sec['name']:<8} paddr={sec['paddr']:#010x} "
|
||||
f"size={sec['size']} bits ({sec['size'] // 8} B) "
|
||||
f"nreloc={sec['nreloc']}")
|
||||
|
||||
rd = exploit.RDebug(args.host, args.port, args.timeout, args.verbose)
|
||||
rc = 1
|
||||
try:
|
||||
rd.connect()
|
||||
flag, payload = rd.liveness(7)
|
||||
print(f"[.] connected {args.host}:{args.port}; opcode 7 -> "
|
||||
f"flag={flag:#x} {payload!r}")
|
||||
|
||||
# 1. allocate the COFF buffer (or fetch it with the TFTP client)
|
||||
if args.tftp:
|
||||
buf, fetched = tftp_fetch(rd, args.tftpc, len(coff), args.jump_wait)
|
||||
print_tftp_rrq(args.tftp_log)
|
||||
problems = check_buffer(buf, fetched, info)
|
||||
if problems:
|
||||
raise RuntimeError("unsafe TFTP buffer: " + "; ".join(problems))
|
||||
got = peek_bytes(rd, buf, fetched)
|
||||
if got != coff:
|
||||
diff = next((i for i, (a, b) in enumerate(zip(got, coff))
|
||||
if a != b), None)
|
||||
raise RuntimeError(f"TFTP buffer differs from {coff_path} "
|
||||
f"(first mismatch at {diff})")
|
||||
print(f"[+] TFTP fetch verified byte-for-byte: {fetched} B at "
|
||||
f"{buf:#010x} (sha256={hashlib.sha256(got).hexdigest()})")
|
||||
else:
|
||||
res = rd.jump(MALLOC, [len(coff)], wait=True,
|
||||
wait_timeout=args.jump_wait)
|
||||
if res is None:
|
||||
raise RuntimeError("jump(malloc) did not return")
|
||||
buf = res[0]
|
||||
print(f"[+] jump(malloc) -> {buf:#010x}; "
|
||||
f"{describe_pointer(buf, len(coff))}")
|
||||
problems = check_buffer(buf, len(coff), info)
|
||||
if problems:
|
||||
raise RuntimeError("unsafe malloc buffer: " + "; ".join(problems))
|
||||
# 2. poke the COFF and prove the readback
|
||||
poke_bytes(rd, buf, coff)
|
||||
words, bad = compare(rd, buf, coff)
|
||||
print(f"[+] COFF poked {len(coff)} B at {buf:#010x} "
|
||||
f"({words} words, {bad} differing bytes)")
|
||||
if bad:
|
||||
raise RuntimeError("COFF readback mismatch")
|
||||
first = min(exploit.MAX_XFER, len(coff))
|
||||
print(f" readback[0:{first}] {peek_bytes(rd, buf, first).hex(' ')}")
|
||||
|
||||
# 3. loader resident?
|
||||
loader = open(args.loader, "rb").read()
|
||||
if args.no_poke_loader:
|
||||
words, bad = compare(rd, LOADER_BASE, loader)
|
||||
print(f"[.] --no-poke-loader: {args.loader} readback "
|
||||
f"({words} words, {bad} differing)")
|
||||
if bad:
|
||||
raise RuntimeError("loader is not resident at "
|
||||
f"{LOADER_BASE:#010x}")
|
||||
else:
|
||||
poke_bytes(rd, LOADER_BASE, loader)
|
||||
words, bad = compare(rd, LOADER_BASE, loader)
|
||||
print(f"[+] loader poked {len(loader)} B at {LOADER_BASE:#010x} "
|
||||
f"({words} words, {bad} differing)")
|
||||
if bad:
|
||||
raise RuntimeError("loader readback mismatch")
|
||||
|
||||
# 4. descriptor + call + result block
|
||||
status, result = run_loader(rd, buf, len(coff), args.jump_wait)
|
||||
|
||||
# 5. app evidence
|
||||
if marker_mode:
|
||||
problems = verify_markers(rd, result, args.settle)
|
||||
elif xhello_mode:
|
||||
problems = verify_xhello(rd, args.out, tag, args.settle,
|
||||
not args.no_screenshot)
|
||||
else:
|
||||
problems = []
|
||||
print("[.] no app-specific verifier (name is neither marker nor "
|
||||
"xhello); status/result only")
|
||||
if problems:
|
||||
raise RuntimeError("app verification failed: " + "; ".join(problems))
|
||||
|
||||
# 6. optional MAME frame dump (boot-relative, externally configured)
|
||||
if args.frame is not None:
|
||||
ppm = os.path.join(args.dump_dir, f"vt1200-frame-{args.frame}.ppm")
|
||||
if wait_for_frame(ppm, args.frame_timeout):
|
||||
print(f"[+] frame dump {ppm} "
|
||||
f"({os.path.getsize(ppm)} bytes)")
|
||||
else:
|
||||
raise RuntimeError(f"no frame dump {ppm} within "
|
||||
f"{args.frame_timeout}s")
|
||||
|
||||
print(f"[+] PASS: status=0 pcb={result['pcb']:#010x} "
|
||||
f"entry={result['entry']:#010x} ({tag})")
|
||||
rc = 0
|
||||
except (OSError, exploit.ProtocolError, RuntimeError, ValueError) as exc:
|
||||
print(f"[-] FAIL: {exc}", file=sys.stderr)
|
||||
rc = 2
|
||||
finally:
|
||||
rd.close()
|
||||
return rc
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main(sys.argv))
|
||||
@@ -477,3 +477,97 @@ the descriptor in `A8`; `LOADER_SNAP=1` writes a PNG at `LOADER_END`.
|
||||
| `dwt/loader/evidence/xhello_run.log` | xhello run |
|
||||
| `dwt/loader/evidence/loader_frame2650.png` | the xhello window |
|
||||
| `dwt/loader/evidence/reloc_refused.log` | `.obj` refused with status 7 |
|
||||
|
||||
---
|
||||
|
||||
## 10. End-to-end host-side loader (rdebug): malloc -> poke -> load -> run
|
||||
|
||||
Date: 2026-10-18. Driver: `dwt/loader/hostload.py`. Evidence:
|
||||
`dwt/loader/evidence/hostload/` (its `README.md` indexes the logs and PNGs).
|
||||
This is the integration of the two existing halves; the loader and the apps are
|
||||
unchanged.
|
||||
|
||||
### Exact sequence (one TCP connection to `192.168.99.2:771`)
|
||||
|
||||
1. `opcode 7` liveness; the computed challenge is answered by
|
||||
`dwt/challenge.py` (the `RDebug` default).
|
||||
2. `jump 0x3F701230` (`malloc`) with **one** argument, the COFF byte length.
|
||||
`jump` returns the callee's `A8`, i.e. a **bit** pointer.
|
||||
3. Poke the COFF to that bit pointer in 1024-byte chunks
|
||||
(`bit + off*8`, never `bit + off`) and `peek` it back: 510/510 or 774/774
|
||||
bytes equal, sha256 matches the local file.
|
||||
4. Poke the raw loader (`build/loader.bin`, 1220 B) at bit `0x01880000`, then
|
||||
`peek` it back (610 words, 0 differing). `--no-poke-loader` skips the write
|
||||
and requires that readback to match.
|
||||
5. Build the 16-byte descriptor at bit `0x01882C00` from **bit** offsets
|
||||
+0/+0x10/+0x20/+0x40/+0x60 (bytes 0/2/4/8/12):
|
||||
`44 4c 31 52 <buf LE32> <len LE32> 01 00 00 00`.
|
||||
6. `jump 0x01880000` with **zero** arguments. The rdebug jump handler's
|
||||
zero-arg path is a bare `CALL` after `MOVE A9,A8` with `A9 = 0`, so the
|
||||
loader enters with `A8 = 0` and uses the fixed descriptor. (With N args the
|
||||
stubs do not set `A8` to the descriptor either; `A8 = 0` is the reliable
|
||||
calling convention from rdebug.)
|
||||
7. Read the result block at bit `0x01882D00`, then app evidence: marker cells
|
||||
by `peek`, or xhello `stage`/`strlen` plus a VRAM screenshot.
|
||||
|
||||
### What worked (two or three fresh boots each)
|
||||
|
||||
* `jump(malloc)` returns a usable, byte-aligned bit pointer in the firmware
|
||||
heap: `0x007c7290` (byte `0x0F8E52`), `0x007c8030` (byte `0x0F9006`),
|
||||
`0x007df450` (byte `0x0FBE8A`), `0x00adcd90`, `0x009fccd0`. These are far
|
||||
below the loader page (`0x01880000`, byte `0x310000`) and below the current
|
||||
apps (`.text` byte `0x318000`), and `hostload.py` rejects a pointer that
|
||||
overlaps either, the loader page or the marker cells.
|
||||
* The loader accepts a malloc'd buffer: status `0` and `A8 = 0` on every run.
|
||||
Its free-list check (status 8) passed for `.text 0x018C0000` and for
|
||||
`xhello` `.text 0x01840000`; the result block reports entry/text/data/bss,
|
||||
`pcb != 0`, `nscns=3`, and `loader_base=0x01880000`.
|
||||
* `create_process` really runs the app: `marker.coff` leaves
|
||||
`start=0x018C0000`, `data=0xDEADBEEF`, `data2=0x12345678`, `bss=0`, and a
|
||||
live counter; `xhello.coff` reaches `stage=6` (`XSync`) and its black
|
||||
400x200 window is visible at `(100,100)` in
|
||||
`hostload_xhello_boot{3,4}_xhello.png`.
|
||||
* `--tftp` also works: the existing `dwt/tcpip/tftpc.bin` (bit `0x01870000`)
|
||||
fetches into its own `malloc` buffer (`stage=4`, `total=510`,
|
||||
`done=0x05A5A5A5`); `peek` matches the COFF byte-for-byte, and that buffer is
|
||||
fed to the same descriptor/loader. Server RRQ, boot 3 and 4:
|
||||
`... requested 'dwt/tcpip/probe.bin' (510 bytes)`.
|
||||
|
||||
### Two traps found
|
||||
|
||||
1. **Result-block offsets are bits.** `loader.asm`'s `RESULT_BASE+020h` is
|
||||
+4 **bytes**, so the block is 13 adjacent 32-bit cells (52 B), not cells at
|
||||
byte intervals of 0x20. Reading at byte offsets `0x20, 0x40, ...` returns
|
||||
`0x55555555` from the free heap beyond the real block; that was a host
|
||||
parsing bug, not a loader failure.
|
||||
2. **The descriptor is clobbered after a load.** A successful
|
||||
`create_process` leaves a call frame at `0x01882C00`
|
||||
(`0d 00 00 00 <pcb> <ptr> 00 60 00 00`); `ARG_AREA` is `0x01882B00` and the
|
||||
frame is 0x100 bits wide. The loader has already consumed the descriptor,
|
||||
and the result block (`0x01882D00`) is untouched, but a second call must
|
||||
rewrite the descriptor. `hostload.py` does so immediately before every
|
||||
jump.
|
||||
|
||||
### Limits
|
||||
|
||||
* **No reservation.** `malloc` only finds a buffer; the loader's free-list
|
||||
check is still a check. The apps stay linked at byte `0x318000`/`0x308000`
|
||||
while allocations grow from the low free blocks; enough allocations on one
|
||||
boot would eventually split the big block up to them. Fresh-boot runs are
|
||||
safe; on a long-lived unit the caller must still choose a free link address.
|
||||
* **`--tftp` needs a server that serves the COFF under tftpc's fixed name**
|
||||
(`dwt/tcpip/probe.bin`); `tftpc.asm` has no filename argument. The server
|
||||
used here was
|
||||
`serve_probe.py 192.168.99.1 --bootp --file dwt/loader/build/marker.coff`.
|
||||
* **`--frame N` cannot trigger a MAME dump.** It only waits for
|
||||
`vt1200-frame-N.ppm` from an externally configured
|
||||
`VT1200_DUMP_FRAME(S)`; frame numbers are boot-relative, so the load-relative
|
||||
visual evidence is the rdebug VRAM screenshot.
|
||||
* The loader is still position-dependent and fixed at `0x01880000`, and the
|
||||
loaded images are position-dependent; none of this adds relocation.
|
||||
* rdebug process only: `create_process` is used for the *app*, not for the
|
||||
loader or the TFTP client. A `create_process` child previously returned `-1`
|
||||
from `socket()` (TCPIP.md), so the fetch stays in the rdebug process.
|
||||
* The real unit would need TCP 771 reachable and the same debug-gate state;
|
||||
the emulator run uses the documented `VT1200_SKIP_LEVEL1=1` divergence to
|
||||
reach the OS.
|
||||
Reference in new issue
Block a user