An open API service indexing awesome lists of open source software.

https://github.com/memoryforensics1/windbg-mcp

C# MCP server for kernel & user-mode Windows debugging — DbgEng COM, KDNET, Frida, dbgsrv, TTD, and integrated VM control. 29 tools for LLM agents.
https://github.com/memoryforensics1/windbg-mcp

ai-agent claude csharp dbgeng debugger dotnet exploit-development frida kernel-debugging llm malware-analysis mcp model-context-protocol reverse-engineering time-travel-debugging ttd vmware vulnerability-research windbg windows

Last synced: 12 days ago
JSON representation

C# MCP server for kernel & user-mode Windows debugging — DbgEng COM, KDNET, Frida, dbgsrv, TTD, and integrated VM control. 29 tools for LLM agents.

Awesome Lists containing this project

README

          

# WinDbg MCP Server

A [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server that gives AI agents complete control over a Windows VM for kernel debugging, reverse engineering, malware analysis, and vulnerability research.

Built in C# (.NET 8), it wraps the Windows Debugger Engine (DbgEng COM), VMware Workstation, Frida, and dbgsrv into **29 MCP tools** that any MCP-compatible LLM client can call.

![Architecture](https://img.shields.io/badge/.NET_8-512BD4?logo=dotnet&logoColor=white)
![Platform](https://img.shields.io/badge/Windows-0078D6?logo=windows&logoColor=white)
![VMware](https://img.shields.io/badge/VMware_Workstation-607078?logo=vmware&logoColor=white)
![License](https://img.shields.io/badge/license-MIT-green)

## Why this project?

Other WinDbg MCP servers exist — most are Python wrappers that launch `cdb.exe` or `windbg.exe` as a subprocess and drive it over stdin/stdout. That's easy to prototype but fragile in practice: the child debugger crashes, hangs on modal dialogs, deadlocks its own pipes, or dies mid-session and takes the agent's context with it.

This project takes a different approach:

- **Direct DbgEng COM** — calls the Windows Debugger Engine natively through its COM interface. No subprocess to babysit, no stdout parsing, no hung pipes. Commands execute inside the server process on a dedicated MTA COM thread with an event pump — so the debugger can't drag the whole MCP server down with it.
- **Kernel debugging is the primary use case, not an afterthought** — full KDNET integration: attach to a running kernel, set breakpoints, step, run any WinDbg command while the target is halted, wait for events with hard timeouts, detect BSODs, and pass first-chance exceptions through so Windows keeps running normally. Execution-control commands (`g`/`t`/`p`) are blocked in `kd_execute` so the LLM can't accidentally run away from a breakpoint — it has to use the explicit `kd_continue`/`kd_step` tools, which always return.
- **User-mode is covered too** — Frida (with eternalized hooks for persistent instrumentation across sessions), dbgsrv for noninvasive process inspection with full WinDbg command access, and TTD (Time Travel Debugging) — all behind the same server.
- **VM lifecycle is integrated with the debug session** — snapshot restore cleanly tears down KD/Frida/dbgsrv before reverting the VM; guest commands, file transfer, and process control are all gated on VM power state so the agent never trips on "wrong state" errors. `vm_set_target` lets a running server switch to a different VM at runtime.
- **Designed for LLM agents** — every tool has a hard timeout (nothing blocks forever), every error message explicitly tells the LLM what to do next, and `get_system_state` gives the model a single "where am I?" snapshot on demand. A `StateCoordinator` validates preconditions before every call so the agent gets useful feedback instead of silent failures.

## What Can It Do?

An LLM connected to this server can autonomously:

- **Control a VM** — start, stop, pause, resume, snapshot, restore, screenshot
- **Kernel debug** — connect via KDNET, set breakpoints, step, execute any WinDbg command, wait for events
- **Run commands in the guest** — execute programs, transfer files, list/kill processes
- **User-mode debug** — attach Frida to hook functions, inspect processes via dbgsrv, record TTD traces

All without the LLM ever needing direct access to WinDbg, a terminal, or the VM itself.

## Quick Start

### Prerequisites

| Requirement | Purpose |
|---|---|
| [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) | Build & run the server |
| [VMware Workstation Pro](https://www.vmware.com/products/workstation-pro.html) | VM management (vmrun) |
| Windows Guest VM | Target for debugging |
| KDNET enabled in guest | Kernel debugging (see [Setup](#vm-setup)) |
| [frida-tools](https://frida.re/) *(optional)* | User-mode instrumentation |
| [WinDbg Preview](https://aka.ms/windbg) *(optional)* | Provides dbgsrv.exe for remote user-mode debugging |

### 1. Clone & Build

```bash
git clone https://github.com/memoryforensics1/windbg-mcp.git
cd windbg-mcp
dotnet build src/WinDbgMCP.Server/WinDbgMCP.Server.csproj
```

### 2. Configure *(optional)*

Everything in appsettings.json is just a default — the LLM can change VM target, credentials, KDNET key, and more at runtime via vm_set_target. Expand only if you want to set a starting config.

Copy `src/WinDbgMCP.Server/appsettings.example.json` to `appsettings.json` and edit:

```json
{
"Vm": {
"VmxPath": "C:\\path\\to\\your\\vm.vmx",
"VmrunPath": "C:\\Program Files (x86)\\VMware\\VMware Workstation\\vmrun.exe",
"VmPassword": "",
"GuestUsername": "YourUser",
"GuestPassword": "YourPass"
},
"KernelDebug": {
"Transport": "kdnet",
"Kdnet": {
"Port": 50000,
"Key": "your.kdnet.key.here"
},
"SymbolPath": "srv*C:\\Symbols*https://msdl.microsoft.com/download/symbols"
},
"Guest": {
"FridaPort": 27042,
"DbgsrvPort": 5064
}
}
```

### 3. Add to Your MCP Client

**Claude Code** (`.mcp.json` in project root):
```json
{
"mcpServers": {
"windbg-mcp": {
"command": "dotnet",
"args": ["run", "--project", "C:\\path\\to\\windbg-mcp\\src\\WinDbgMCP.Server\\WinDbgMCP.Server.csproj"]
}
}
}
```

**Claude Desktop** (`claude_desktop_config.json`):
```json
{
"mcpServers": {
"windbg-mcp": {
"command": "C:\\Program Files\\dotnet\\dotnet.exe",
"args": ["run", "--project", "C:\\path\\to\\windbg-mcp\\src\\WinDbgMCP.Server\\WinDbgMCP.Server.csproj"]
}
}
}
```

### 4. Run

The server starts automatically when your MCP client connects. It communicates over stdio.

```bash
# Or run standalone for testing
dotnet run --project src/WinDbgMCP.Server/WinDbgMCP.Server.csproj
```

## Tool Catalog (29 tools)

### Meta
| Tool | Description |
|---|---|
| `get_system_state` | Full state overview — VM power, KD, guest ops, UMD. Always allowed. |

### VM Tools (8)
| Tool | Description |
|---|---|
| `vm_start` | Power on the VM |
| `vm_stop` | Shut down (graceful or hard) |
| `vm_pause` | Freeze entire VM |
| `vm_resume` | Unpause a paused VM |
| `vm_snapshot_restore` | Restore a named snapshot (debug sessions are cleanly torn down and can reconnect after) |
| `vm_snapshot_list` | List available snapshots |
| `vm_screenshot` | Capture VM display as PNG |
| `vm_set_target` | Switch the active VM target at runtime (VMX path + credentials) |

### Kernel Debug Tools (7)
| Tool | Description |
|---|---|
| `kd_connect` | Attach to kernel via KDNET. Target breaks on connect. |
| `kd_disconnect` | Detach from kernel. Resumes target so VM keeps running. |
| `kd_break` | Halt running target (Ctrl+Break) |
| `kd_continue` | Resume target execution |
| `kd_step` | Step one instruction (into or over) |
| `kd_execute` | Run any WinDbg command (`k`, `r`, `lm`, `!process 0 0`, `!analyze -v`, etc.) |
| `kd_wait_for_event` | Wait for breakpoint/exception with timeout. Always returns. |

### Guest Tools (5)
| Tool | Description |
|---|---|
| `guest_run_command` | Execute command in guest OS, capture stdout/stderr |
| `guest_transfer_to_vm` | Copy file from host to guest |
| `guest_transfer_from_vm` | Copy file from guest to host |
| `guest_list_processes` | List running processes with PIDs |
| `guest_kill_process` | Kill a process by PID |

### User-Mode Debug Tools (8)
| Tool | Description |
|---|---|
| `umd_frida_attach` | Attach Frida to a guest process |
| `umd_frida` | Inject JS, eval expressions, list processes, detach |
| `umd_frida_skill` | Frida best practices and API reference for LLMs |
| `umd_dbgsrv_connect` | Connect to remote dbgsrv in guest |
| `umd_dbgsrv_execute` | Attach to PID, run WinDbg commands, detach |
| `umd_dbgsrv_skill` | dbgsrv best practices and WinDbg command reference for LLMs |
| `umd_ttd` | Time Travel Debugging — record, stop, retrieve, list traces |
| `umd_ttd_query` | Query TTD traces *(not yet implemented)* |

## Example Workflows

### Inspect a Running Kernel

```
get_system_state
kd_connect
kd_execute("lm") # list loaded modules
kd_execute("!process 0 0") # list all processes
kd_execute("vertarget") # target version info
kd_disconnect
```

### Set Breakpoint and Catch It

```
kd_connect
kd_execute("bp nt!NtCreateFile") # set breakpoint
kd_continue # let target run
kd_wait_for_event(30) # wait up to 30s for hit
kd_execute("k") # show call stack
kd_execute("r") # show registers
kd_disconnect
```

### Deploy and Debug a Driver

```
guest_transfer_to_vm("MyDriver.sys", "C:\\Windows\\System32\\drivers\\MyDriver.sys")
guest_run_command("sc create MyDrv type= kernel binPath= C:\\Windows\\System32\\drivers\\MyDriver.sys")
guest_run_command("sc start MyDrv")
kd_connect
kd_execute("lm m MyDrv") # verify driver loaded
kd_execute("bp MyDrv!DriverEntry")
kd_disconnect
```

### Hook a Function with Frida

```
umd_frida_skill # read best practices first
umd_frida_attach(processName="target.exe")
umd_frida(action="eval", code="Process.enumerateModules().map(m=>m.name)")
umd_frida(action="inject", code="""
Interceptor.attach(Module.getExportByName('kernel32.dll','CreateFileW'), {
onEnter(args) { console.log('CreateFileW: ' + args[0].readUtf16String()); }
});
console.log('Hook installed');
""", timeoutSeconds=10)
umd_frida(action="detach")
```

### Inspect a Process with dbgsrv

```
umd_dbgsrv_skill # read best practices first
guest_run_command("start /b C:\\Tools\\DbgSrv\\dbgsrv.exe -t tcp:port=5064")
umd_dbgsrv_connect(vmIpAddress="192.168.x.x")
umd_dbgsrv_execute(action="attach", argument="")
umd_dbgsrv_execute(action="command", argument="lm")
umd_dbgsrv_execute(action="command", argument="!peb")
umd_dbgsrv_execute(action="command", argument="~*k")
umd_dbgsrv_execute(action="detach")
umd_dbgsrv_execute(action="disconnect")
```

### Crash Analysis

```
kd_connect # connect after BSOD
kd_execute("!analyze -v") # automated crash analysis
kd_execute("k") # faulting stack
kd_execute("r") # registers at crash
kd_execute(".trap") # switch to trap frame
kd_disconnect
```

## Architecture

```
┌─────────────────────────────────────────────────────────────┐
│ MCP Client (LLM) │
│ Claude Code / Claude Desktop │
└──────────────────────────┬──────────────────────────────────┘
│ stdio (JSON-RPC)
┌──────────────────────────▼──────────────────────────────────┐
│ WinDbgMCP.Server │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ VM Tools │ │ KD Tools │ │ Guest Tools │ │
│ │ (vmrun) │ │ (DbgEng) │ │ (vmrun guest) │ │
│ └──────┬───────┘ └──────┬───────┘ └──────┬───────────┘ │
│ │ │ │ │
│ ┌──────▼───────┐ ┌──────▼───────┐ ┌──────▼───────────┐ │
│ │ VmwareManager│ │ DbgEngManager│ │ GuestExecManager │ │
│ └──────────────┘ └──────┬───────┘ └──────────────────┘ │
│ │ │
│ ┌────────────────────────▼─────────────────────────────┐ │
│ │ StateCoordinator │ │
│ │ (precondition gate — validates every tool call) │ │
│ └───────────────────────────────────────────────────────┘ │
│ │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────────┐ │
│ │ UMD: Frida │ │ UMD: dbgsrv │ │ UMD: TTD │ │
│ │ (frida CLI) │ │ (DbgEng COM) │ │ (TTD.exe) │ │
│ └──────────────┘ └──────────────┘ └──────────────────┘ │
└──────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ Windows Guest VM │
│ (VMware Workstation Pro) │
│ │
│ KDNET (:50000) │ frida-server (:27042) │ dbgsrv (:5064)│
└─────────────────────────────────────────────────────────────┘
```

### Key Design Principles

1. **Every tool validates preconditions** — `StateCoordinator` checks VM power, KD state, guest ops availability before any operation executes
2. **Every operation has a timeout** — no blocking calls, ever. The LLM never hangs.
3. **Error messages are prompts** — every error tells the LLM exactly what to do next
4. **Execution-control commands are blocked** — `g`, `t`, `p` are blocked in `kd_execute`; use `kd_continue`/`kd_step` instead
5. **DbgEng COM thread affinity** — all COM calls marshaled to a dedicated MTA thread with an event pump
6. **BSOD detection** — bugchecks are detected and handled differently from normal breakpoints
7. **Snapshot restore resets everything** — KD, Frida, dbgsrv sessions are all cleaned up

## VM Setup

### Enable KDNET (Kernel Debugging)

In the guest VM (elevated cmd):

```cmd
bcdedit /debug on
bcdedit /dbgsettings net hostip: port:50000 key:
shutdown /r /t 0
```

Generate a key with `kdnet.exe` from the Windows SDK, or use any dotted-quad format key.

### Install Frida Server (Optional)

On the **host**:
```bash
pip install frida-tools
```

Download `frida-server--windows-x86_64.exe` from [Frida releases](https://github.com/frida/frida/releases), deploy to guest as `C:\Tools\frida-server.exe`, and run:
```cmd
frida-server.exe -l 0.0.0.0:27042
```

### Install dbgsrv (Optional)

Copy `dbgsrv.exe`, `dbgeng.dll`, and `dbghelp.dll` from WinDbg Preview (or Windows SDK) to the guest, then run:
```cmd
dbgsrv.exe -t tcp:port=5064
```

### Firewall

The host firewall must allow:
- UDP port 50000 inbound (KDNET)
- TCP port 27042 outbound (Frida)
- TCP port 5064 outbound (dbgsrv)

## Project Structure

```
src/WinDbgMCP.Server/
├── Program.cs # Entry point, MCP server setup, DI
├── appsettings.json # Configuration (VM creds, KDNET, timeouts)
├── Configuration/
│ └── ServerConfig.cs # Typed configuration model
├── State/
│ ├── SystemState.cs # State model + enums
│ ├── StateCoordinator.cs # Precondition gate (heart of system)
│ ├── ErrorMessages.cs # LLM-friendly error catalog
│ └── ToolResult.cs # Result type
├── Vmware/
│ └── VmwareManager.cs # vmrun wrapper
├── KernelDebug/
│ ├── DbgEngThread.cs # Dedicated MTA thread for COM
│ ├── DbgEngManager.cs # Kernel debug session manager
│ ├── DebugEventCallbacks.cs # Breakpoint/exception/module events
│ ├── OutputCapture.cs # Command output capture
│ └── Interop/ # P/Invoke, constants
├── Guest/
│ └── GuestExecManager.cs # Guest command execution + file transfer
├── UserModeDebug/
│ ├── FridaManager.cs # Frida CLI wrapper
│ ├── DbgsrvManager.cs # Remote user-mode debugging via dbgsrv
│ └── TtdManager.cs # Time Travel Debugging
└── Tools/
├── VmTools.cs # vm_* tools
├── KernelDebugTools.cs # kd_* tools
├── GuestTools.cs # guest_* tools
├── UserModeDebugTools.cs # umd_* tools
└── MetaTools.cs # get_system_state

src/WinDbgMCP.Tests/ # Unit tests (126 tests)
```

## Running Tests

```bash
dotnet test src/WinDbgMCP.Tests/WinDbgMCP.Tests.csproj
```

## Tech Stack

| Component | Technology |
|---|---|
| Runtime | .NET 8 (C#) |
| MCP SDK | [ModelContextProtocol](https://github.com/modelcontextprotocol/csharp-sdk) 0.1.0-preview.12 |
| DbgEng | Native COM interop (`dbgeng.dll`) |
| VM Control | VMware vmrun CLI |
| User-Mode Hooking | Frida (frida-tools Python CLI) |
| Remote Debugging | dbgsrv.exe (WinDbg component) |
| TTD | TTD.exe (Time Travel Debugging) |

## License

MIT