windbg_mcp
by 276793422
README.md
# WinDbg / cdb 会话式调试 MCP
一个把系统自带的 **cdb.exe**(Debugging Tools for Windows 里的命令行调试器)暴露为
MCP 工具的服务端。**零三方调试库**——不依赖任何 Python 调试绑定,直接驱动你装 WinDbg
时就已经有的 cdb。
## 设计思想
调试本质上是一个**持久的、有状态的交互会话**,不是一堆孤立命令。因此本 MCP 采用
**token_key 会话生命周期**架构:
```
open(target) ──► token_key 打开 dump / 启动 exe / attach 进程 / 连内核
run(token_key, 命令) ──► output 在会话里执行任意 cdb 命令(上下文跨命令保留)
interrupt(token_key) 中断当前命令(阻塞的 g)
close(token_key) 关闭会话
sessions() 列出活跃会话
```
`run` 下的是**真正的 cdb/WinDbg 命令**(`!analyze`、`kv`、`r`、`~Ns`、`.frame N`、`dv`、
`bp`、`g`、`p`、`!heap`、`!process` ……),会话上下文(符号 / 当前线程 / 栈帧 / 断点 /
当前进程)在同一个 token_key 内跨命令保留——**和坐在 cdb 前操作完全一致**。WinDbg/cdb
的全部命令都可直接用,远比预先封装的几十个结构化工具完整。
## 前置
- **Windows**
- **Debugging Tools for Windows**(提供 `cdb.exe`;装 WinDbg 时一并就有)。本服务会自动在
常见位置(Windows Kits、Store 版 WinDbg、PATH)查找;找不到时设环境变量
`WINDBGMCP_CDB` 指向 `cdb.exe` 全路径。
- **Python 3.10+**
- **符号路径**(强烈建议):设环境变量
`_NT_SYMBOL_PATH=srv*C:\Symbols*https://msdl.microsoft.com/download/symbols`,
cdb 子进程会继承,否则符号解析多半失败。
## 安装
```bat
cd windbg_mcp
pip install -r requirements.txt # 只装 mcp SDK
```
## 接入客户端
启动方式统一:`python <本目录>/server.py`。
**Claude Code**
```bat
claude mcp add windbg-mcp -- py -3.13 C:\path\to\windbg_mcp\server.py
```
**手写 `.mcp.json`**
```json
{
"mcpServers": {
"windbg-mcp": {
"command": "py",
"args": ["-3.13", "C:/path/to/windbg_mcp/server.py"],
"env": {
"_NT_SYMBOL_PATH": "srv*C:\\Symbols*https://msdl.microsoft.com/download/symbols"
}
}
}
}
```
改完配置**重启客户端**并批准 `windbg-mcp`。
## 工具总览(44 个)
分两层:**会话生命周期(7)** + **基础命令封装(37)**。封装是便捷,`run` 是统一原始接口。
### 会话生命周期(7)
| 工具 | 作用 |
|---|---|
| `open(target, args?, kind?, initial_commands?)` | 打开会话 → `token_key` |
| `run(token_key, command, timeout_ms?)` | **统一原始接口**:执行任意 cdb 命令 |
| `interrupt(token_key)` | 中断当前命令(阻塞的 g 等) |
| `close(token_key)` | 关闭会话(终止被调试进程) |
| `detach(token_key)` | 分离会话(被调试进程继续运行,cdb qd) |
| `sessions()` | 列出活跃会话(自动清理死会话,含 kind/target) |
| `list_dumps(directory, pattern?, limit?)` | 列出目录下转储文件(不需会话) |
`open` 的 `kind`:`dump` / `launch` / `attach` / `kernel` / `remote` / `auto`(默认,按 target 形态判断)。
### 基础命令封装(37)
封装内部都走会话的 `run`,参数结构化、不用记 cdb 语法。**没有封装的命令仍用 `run` 直接发。**
| 分组 | 工具(对应 cdb 命令) |
|---|---|
| 执行 | `go`(g) · `step(into?)`(p/t) · `step_out`(gu) · `goto(expr)`(g expr) · `trace(count)`(t N) · `analyze`(!analyze -v) |
| 寄存器/内存 | `regs`(r) · `set_reg`(r name=val) · `read_mem`(db) · `write_mem`(eb) · `read_str`(da/du) · `read_ptr`(dps) · `poi`(dps L1) · `disasm`(u $ip) · `mem_info`(!vprot) · `mem_list`(!address) |
| 符号/模块 | `resolve`(?) · `find_symbols`(x) · `addr_to_symbol`(ln) · `modules`(lm) · `module_info`(lm vm) · `get_exports`(x mod!*) |
| 栈/线程/帧/局部 | `stack`(kv) · `threads`(~) · `select_thread`(~Ns) · `frame`(.frame N) · `locals`(dv) · `get_teb`(r $teb) · `get_peb`(r $peb) · `get_handles`(!handle 0 f) |
| 断点 | `bp`(bp) · `hw_bp`(ba) · `breakpoints`(bl) · `enable_bp`(be) · `disable_bp`(bd) · `remove_bp`(bc) |
| 状态捕获 | `capture_state`(手动快照:寄存器 + 调用栈 + 栈顶内存 + 当前 ip 反汇编) |
`regs` / `read_mem` / `resolve` 会把输出解析成结构化字段(`registers` / `hex`+`ascii` / `addr`);其余返回干净文本(提示符已去掉)。
## 典型工作流
### 崩溃 dump 分析(交互式,!analyze 只是起点)
```
1. open("C:/crashes/x.dmp") -> t
2. analyze(t) 起点:故障模块 / 异常 / 故障栈
3. threads(t) 列出所有线程
4. select_thread(t, 3) 切到故障线程 3
5. stack(t) 该线程带参数的调用栈
6. frame(t, 2) 切到第 2 栈帧
7. locals(t) 当前帧的局部变量
8. regs(t) 寄存器(结构化 registers)
9. disasm(t, count=8) 反汇编崩溃点附近
10. run(t, "!heap -stat") 没封装的命令,走统一 run 接口
11. read_mem(t, "@rsp", 64) 读栈内存(结构化 hex/ascii)
12. close(t)
```
第 4 步切线程、第 6 步切栈帧——后续 `stack`/`locals`/`regs` 都作用在切完后的状态上,这才是真实调试。封装之外的命令(如 `!heap`)随时用 `run` 兜底。
### 活进程调试 / 漏洞利用验证
```
1. open("C:/target/vuln.exe", args="input.bin") -> t
2. bp(t, "vuln!processInput+0x2A")
3. go(t) 继续;命中断点返回,或超时则 interrupt(t)
4. regs(t) 看 rip(registers.rip=0x4141...=可控)
5. stack(t) 看栈
6. step(t) 单步越过
7. close(t)
```
### attach 到运行中的进程
```
1. open("1234", kind="attach") -> t
2. run(t, "~"); run(t, "kv"); ...
3. close(t) detach 后进程继续运行
```
### 内核 / 驱动调试
```
1. open("net:port=50000,key=1.2.3.4", kind="kernel") -> t
2. run(t, "!process 0 0")
3. run(t, "lm m nt")
4. close(t)
```
## 重要注意事项
- **Windows 专属**:cdb.exe 仅 Windows 可用。
- **`run` 的 timeout 与中断**:`g`、`p`、等待事件类命令会阻塞到事件发生;到 `timeout_ms`
仍未返回时结果里 `timed_out=true`,调用 `interrupt(token_key)`(发 `CTRL+BREAK`)中断。
- **命令完成判定**:服务通过识别 cdb 提示符(`0:000>` / `kd>` / `lkd>` 等)判断命令结束。
极少数情况(命令输出含疑似提示符的行)可能提前返回,重发命令即可。
- **cdb 伪寄存器(实测)**:`$ip`(当前指令指针)、`$teb`、`$peb`、`$exentry` 可用;**`$sp` 不存在**——
读栈指针用 `regs()` 取 esp/rsp,或命令里用 `@esp`/`@rsp`(寄存器引用需 `@` 前缀)。封装已规避
(`disasm` 用 `$ip`、`capture_state` 用解析出的栈指针)。
- **`mem_list`(!address)**:首次会建立内存映射(输出 'Building memory map...' 进度),耗时且输出
可能延迟到下一条命令;建议单独调用或会话开始预热一次。`mem_info`(!vprot)轻量、无此问题。
- **编码**:cdb 输出默认按系统首选编码解码(中文系统=gbk/cp936);若乱码设
`WINDBGMCP_ENCODING=gbk` 或 `utf-8`。
- **cdb 路径**:设 `WINDBGMCP_CDB=<cdb.exe 全路径或其目录>` 可强制指定。
- **日志**:写 stderr;`WINDBGMCP_LOG_LEVEL=DEBUG` 调高 verbosity。
- **安全(.shell 拦截)**:`run` / `initial_commands` 默认拦截 `.shell` / `.pcan`(cdb 可
借此执行系统命令);确需放行设 `WINDBGMCP_ALLOW_DANGEROUS=1`。
- **会话数上限**:默认最多 8 个并发会话(`open` 超限报错);改 `WINDBGMCP_MAX_SESSIONS`(0=不限)。
死会话由 `sessions()` 自动清理,server 退出时 `atexit` 关闭全部。
- **并发**:同一 token_key 的命令自动串行化(不会交错);不同 token_key 并发。
- **权限与授权**:能 attach 任意进程、写内存、内核调试,权限极大。仅用于安全研究与授权测试。
## 测试
`tests/selftest.py` 是自测脚本,验证 cdb 交互机制 + 调试流程(不经 MCP 协议,直接驱动
`CdbSession`,同步快速)。换机器 / 升级 cdb / 改 server 后跑一遍即可回归。
**完整说明见 [tests/README.md](tests/README.md)。**
在 `windbg_mcp/` 目录下快速跑:
```bat
py tests/selftest.py --exe "<被调试程序>" --cdb-path "<cdb.exe 或目录>" --symbol-path "<符号路径>"
```
末尾 `PASS=x WARN=y FAIL=z`,FAIL=0 即核心机制可用。
## 声明
仅供安全研究、学习与授权测试。使用者需自行确保对分析对象拥有合法授权。
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues