MCP server for AI-assisted debugging of DOS binaries via GDB protocol. Features: - GDB remote protocol client for DOSBox-X debugging - 16 debugging tools: launch, attach, breakpoint management, registers, memory read/write, disassemble, step, continue, etc. - Docker container with DOSBox-X for consistent environment - Support for DOS segment:offset addressing - Comprehensive test suite (49 tests) Primary use case: Reverse engineering the unpublished Bezier algorithm in RIPTERM.EXE for the RIPscrip graphics protocol project.
157 lines
4.8 KiB
Python
157 lines
4.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Example: Tracing the Bezier algorithm in RIPTERM.EXE
|
|
|
|
This script demonstrates how to use the DOSBox-X MCP server to trace
|
|
the unpublished Bezier curve algorithm in RIPTERM.EXE.
|
|
|
|
The goal is to:
|
|
1. Launch DOSBox-X with RIPTERM
|
|
2. Set breakpoints at suspected Bezier drawing code
|
|
3. Feed a test RIPscrip file with Bezier commands
|
|
4. Capture register/memory state at each point
|
|
5. Reconstruct the algorithm from the captured data
|
|
|
|
Prerequisites:
|
|
- RIPTERM.EXE in the ./dos directory
|
|
- A test RIP file with Bezier commands
|
|
- DOSBox-X MCP server running
|
|
|
|
Usage:
|
|
python examples/ripterm_bezier.py
|
|
|
|
Note: This is a conceptual example. The actual addresses would need to be
|
|
determined through static analysis (e.g., in Ghidra) first.
|
|
"""
|
|
|
|
import json
|
|
import time
|
|
from pathlib import Path
|
|
|
|
|
|
def trace_bezier():
|
|
"""Trace the Bezier algorithm execution."""
|
|
|
|
# These would be determined from Ghidra analysis
|
|
# Hypothetical addresses for RIPTERM's Bezier code
|
|
BEZIER_ENTRY = "1234:0100" # Where Bezier processing starts
|
|
DRAW_POINT = "1234:0200" # Where individual points are drawn
|
|
CALCULATE = "1234:0300" # The core calculation routine
|
|
|
|
print("=" * 60)
|
|
print("RIPTERM Bezier Algorithm Tracer")
|
|
print("=" * 60)
|
|
print()
|
|
|
|
# This would use the MCP tools via Claude or direct API
|
|
# For demonstration, we'll show the intended flow:
|
|
|
|
print("Step 1: Launch DOSBox-X with RIPTERM")
|
|
print(" launch('/path/to/dos/RIPTERM.EXE')")
|
|
print()
|
|
|
|
print("Step 2: Attach to GDB stub")
|
|
print(" attach('localhost', 1234)")
|
|
print()
|
|
|
|
print("Step 3: Set breakpoints at key addresses")
|
|
print(f" breakpoint_set('{BEZIER_ENTRY}') # Bezier entry")
|
|
print(f" breakpoint_set('{DRAW_POINT}') # Draw point")
|
|
print(f" breakpoint_set('{CALCULATE}') # Calculation")
|
|
print()
|
|
|
|
print("Step 4: Continue execution until breakpoint")
|
|
print(" continue_execution()")
|
|
print()
|
|
|
|
print("Step 5: When breakpoint hit, capture state:")
|
|
print("""
|
|
# Read registers
|
|
regs = registers()
|
|
print(f"AX={regs['ax']} BX={regs['bx']} CX={regs['cx']} DX={regs['dx']}")
|
|
|
|
# Read stack (parameters often passed on stack)
|
|
stack_data = stack(16)
|
|
|
|
# Read data segment (for global variables)
|
|
mem = memory_read("DS:0000", 256)
|
|
|
|
# Step through to see calculation
|
|
for i in range(100):
|
|
step()
|
|
regs = registers()
|
|
# Log coordinate values
|
|
print(f"Step {i}: X={regs['cx']} Y={regs['dx']}")
|
|
""")
|
|
|
|
print("Step 6: Analyze captured data to reconstruct algorithm")
|
|
print()
|
|
|
|
# Example of what the captured data might look like
|
|
example_trace = [
|
|
{"step": 0, "x": 100, "y": 50, "note": "Control point 1"},
|
|
{"step": 10, "x": 112, "y": 58, "note": "Interpolated"},
|
|
{"step": 20, "x": 125, "y": 65, "note": "Interpolated"},
|
|
{"step": 30, "x": 138, "y": 71, "note": "Interpolated"},
|
|
{"step": 40, "x": 150, "y": 75, "note": "Control point 2 region"},
|
|
{"step": 50, "x": 162, "y": 71, "note": "Curving back"},
|
|
{"step": 60, "x": 175, "y": 65, "note": "Interpolated"},
|
|
{"step": 70, "x": 188, "y": 58, "note": "Interpolated"},
|
|
{"step": 80, "x": 200, "y": 50, "note": "End point"},
|
|
]
|
|
|
|
print("Example trace output:")
|
|
print("-" * 40)
|
|
for point in example_trace:
|
|
print(f" Step {point['step']:3d}: ({point['x']:3d}, {point['y']:3d}) - {point['note']}")
|
|
print()
|
|
|
|
print("From this data, we could determine:")
|
|
print(" - Whether it uses De Casteljau's algorithm")
|
|
print(" - The number of subdivisions")
|
|
print(" - Fixed-point vs floating-point math")
|
|
print(" - Any optimizations or approximations")
|
|
|
|
|
|
def create_test_rip():
|
|
"""Create a simple RIP file to test Bezier drawing."""
|
|
|
|
# RIPscrip Level 0 Bezier command
|
|
# The format is: !|z<x1><y1><x2><y2><x3><y3><x4><y4>
|
|
# Using MegaNum encoding
|
|
|
|
test_rip = """!|
|
|
!|E
|
|
!|c0F
|
|
!|z00320064009600C800C8006400640032
|
|
"""
|
|
|
|
# This draws a Bezier curve with:
|
|
# Start: (50, 100)
|
|
# Control 1: (150, 200)
|
|
# Control 2: (200, 100)
|
|
# End: (100, 50)
|
|
|
|
test_file = Path("dos/test-bezier.RIP")
|
|
test_file.parent.mkdir(exist_ok=True)
|
|
test_file.write_text(test_rip)
|
|
|
|
print(f"Created test file: {test_file}")
|
|
return test_file
|
|
|
|
|
|
def main():
|
|
"""Main entry point."""
|
|
print()
|
|
trace_bezier()
|
|
print()
|
|
print("=" * 60)
|
|
print("To actually run this:")
|
|
print("1. Use Ghidra to find the real Bezier addresses in RIPTERM.EXE")
|
|
print("2. Start the DOSBox-X MCP server")
|
|
print("3. Use Claude to interactively debug with these tools")
|
|
print("=" * 60)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|