From 1c1f804a131481d72c2a0353518046ff41c39490 Mon Sep 17 00:00:00 2001 From: SDD Date: Sun, 18 Oct 2026 16:32:58 +0300 Subject: [PATCH] dwt: real X11 app via rdebug -- hostload --real; xhello window on the terminal (status 0, stage 6) --- dwt/evidence/real-unit-xhello.png | Bin 0 -> 7108 bytes dwt/loader/hostload.py | 23 +++++++++++++++-------- dwt/notes/REAL_UNIT.md | 24 ++++++++++++++++++++++++ 3 files changed, 39 insertions(+), 8 deletions(-) create mode 100644 dwt/evidence/real-unit-xhello.png diff --git a/dwt/evidence/real-unit-xhello.png b/dwt/evidence/real-unit-xhello.png new file mode 100644 index 0000000000000000000000000000000000000000..078e4dd6c46b9e19a0643700ae838a2796b53e8f GIT binary patch literal 7108 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 str: # --------------------------------------------------------------------------- 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.""" + out_raw: str | None = None, real: bool = False) -> bytes: + """Grab the 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 real: + width, stride = screenshot.REAL_WIDTH, screenshot.REAL_STRIDE + else: + width, stride = screenshot.WIDTH_DEFAULT, screenshot.STRIDE_DEFAULT + data = screenshot.grab(rd, 0, screenshot.HEIGHT, stride, True) + gray = screenshot.decode(data, width, stride) + screenshot.write_png(out_png, width, screenshot.HEIGHT, gray) if out_raw: with open(out_raw, "wb") as fh: fh.write(data) @@ -350,7 +354,7 @@ def verify_markers(rd: exploit.RDebug, result: dict, settle: float) -> list[str] def verify_xhello(rd: exploit.RDebug, out_dir: str, tag: str, settle: float, - take_shot: bool) -> list[str]: + take_shot: bool, real: bool = False) -> list[str]: problems = [] time.sleep(settle) stage = peek_u32(rd, XHELLO_STAGE) @@ -363,7 +367,7 @@ def verify_xhello(rd: exploit.RDebug, out_dir: str, tag: str, settle: float, f"(calling-convention check)") if take_shot: png = os.path.join(out_dir, f"hostload_{tag}_xhello.png") - data = screenshot_vram(rd, png) + data = screenshot_vram(rd, png, real=real) print(f"[+] screenshot {png} ({os.path.getsize(png)} bytes, " f"{len(data)} bytes of VRAM)") return problems @@ -445,6 +449,9 @@ def main(argv: list[str]) -> int: 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("--real", action="store_true", + help="real-unit screenshot geometry (1280x1024, 256-byte " + "stride) instead of the emulator's 1024x1024/128") 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, @@ -541,7 +548,7 @@ def main(argv: list[str]) -> int: problems = verify_markers(rd, result, args.settle) elif xhello_mode: problems = verify_xhello(rd, args.out, tag, args.settle, - not args.no_screenshot) + not args.no_screenshot, real=args.real) else: problems = [] print("[.] no app-specific verifier (name is neither marker nor " diff --git a/dwt/notes/REAL_UNIT.md b/dwt/notes/REAL_UNIT.md index 6863a7a..8ec5dbe 100644 --- a/dwt/notes/REAL_UNIT.md +++ b/dwt/notes/REAL_UNIT.md @@ -163,3 +163,27 @@ Both backgrounds are captured at the correct geometry: `dwt/evidence/real-unit-1280-50pct.png` (50% `1010` root, the owner's preference). Only the root's image bytes change; the 256-byte stride and the 1280x1024 size are identical. + +### X11 app on the real unit (2026-10-18) + +The host-side loader ran end to end against the terminal: + +```sh +python3 dwt/loader/hostload.py --host 100.103.100.103 \ + --coff dwt/loader/build/xhello.coff --real +``` + +``` +jump(malloc) -> 0x007e7bf0 +COFF 774 B poked (0 differing) +loader 1220 B @ 0x01880000 (0 differing) +loader A8 = 0; entry 0x01840000; pcb 0x003f6510 +xhello stage=6 strlen=4 +``` + +Evidence: `dwt/evidence/real-unit-xhello.png` — a 400x200 WM-framed black +window over the Terminal Manager, on the real screen. + +**Caveat:** the loader and app are linked at fixed addresses (`0x01880000`, +`0x01840000`). Re-running while that app is live overwrites the running code. +Power-cycle (or choose new addresses) before loading again.