Created
July 23, 2026 22:30
-
-
Save sudocurse/20787d09a8e36a00b0a5cf0692c4e7a7 to your computer and use it in GitHub Desktop.
real mode
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/env python3 | |
| import argparse | |
| import subprocess | |
| import tempfile | |
| import pathlib | |
| import sys | |
| PRESETS = { | |
| "ivt_int0": (0x0000, 0x0000, "IVT: int 0 (divide-by-zero) handler offset"), | |
| "ivt_int0_seg": (0x0000, 0x0002, "IVT: int 0 handler segment"), | |
| "ivt_int10": (0x0000, 0x0040, "IVT: int 0x10 (video) handler offset"), | |
| "ivt_int13": (0x0000, 0x004C, "IVT: int 0x13 (disk) handler offset"), | |
| "bios_equip": (0x0000, 0x0410, "BIOS Data Area: equipment word"), | |
| "bios_memkb": (0x0000, 0x0413, "BIOS Data Area: base memory size (KB)"), | |
| "bios_tick": (0x0000, 0x006C, "BIOS Data Area: timer tick counter (live!)"), | |
| "video_mem": (0xB800, 0x0000, "Video memory: char+attr of top-left screen cell"), | |
| } | |
| def build_asm(seg: int, off: int, label: str) -> str: | |
| live = (label == PRESETS["bios_tick"][2]) | |
| return f""" | |
| BITS 16 | |
| ORG 0x7C00 | |
| mov ax, {seg:#06x} | |
| mov ds, ax | |
| { '.watch:' if live else '' } | |
| mov bx, [{off:#06x}] | |
| mov cx, 4 | |
| .loop: | |
| rol bx, 4 | |
| mov al, bl | |
| and al, 0x0F | |
| add al, '0' | |
| cmp al, '9' | |
| jbe .p | |
| add al, 7 | |
| .p: | |
| mov ah, 0x0E | |
| int 0x10 | |
| loop .loop | |
| { 'mov ah, 0x0E' if live else '' } | |
| { "mov al, 13" if live else '' } | |
| { "int 0x10" if live else '' } | |
| { "jmp .watch" if live else "hlt" } | |
| times 510 - ($ - $$) db 0 | |
| dw 0xAA55 | |
| """ | |
| def main(): | |
| parser = argparse.ArgumentParser( | |
| description="Boot a tiny NASM stub in QEMU that dumps a real-mode memory location to the screen." | |
| ) | |
| parser.add_argument( | |
| "preset", | |
| nargs="?", | |
| choices=sorted(PRESETS.keys()), | |
| help="Which memory location to peek at.", | |
| ) | |
| parser.add_argument( | |
| "-l", "--list", | |
| action="store_true", | |
| help="List available presets and exit.", | |
| ) | |
| args = parser.parse_args() | |
| if args.list or not args.preset: | |
| print("Available presets:\n") | |
| for name, (seg, off, label) in PRESETS.items(): | |
| print(f" {name:14s} {seg:04x}:{off:04x} {label}") | |
| if not args.preset: | |
| print("\nUsage: python3 peek.py <preset>") | |
| sys.exit(0 if args.list else 1) | |
| return | |
| seg, off, label = PRESETS[args.preset] | |
| asm_src = build_asm(seg, off, label) | |
| with tempfile.TemporaryDirectory() as tmp: | |
| asm_path = pathlib.Path(tmp, "b.asm") | |
| img_path = pathlib.Path(tmp, "b.img") | |
| asm_path.write_text(asm_src) | |
| print(f"Peeking at {seg:04x}:{off:04x} — {label}") | |
| subprocess.run(["nasm", "-f", "bin", str(asm_path), "-o", str(img_path)], check=True) | |
| subprocess.run(["qemu-system-i386", "-fda", str(img_path), "-boot", "a"], check=True) | |
| if __name__ == "__main__": | |
| main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment