使用说明
Winggy MCP
一个MCP(模型上下文协议)服务器,它公开了每个pybag Windows调试器 作为原生MCP工具。它为任何MCP兼容客户端(Claude Desktop, Claude Code、Cowork、OpenAI Codex CLI、Cursor和自定义代理)完全控制 用户模式进程、内核会话和崩溃转储分析——全部通过类型化 具有结构化JSON响应的工具调用。
需求
- 仅限Windows --pybag需要Microsoft Windows调试工具
- Python 3.10+
- Microsoft Windows调试工具(Windows SDK的一部分)
安装
1.克隆存储库
git clone https://github.com/your-username/windbg-mcp.git
cd windbg-mcp
2.安装Python依赖项
pip install pybag mcp
3.安装Microsoft调试工具
下载Windows SDK并选择 Windows调试工具 在设置过程中: https://developer.microsoft.com/en-us/windows/downloads/windows-sdk/
连接到LLM IDE和客户
服务器作为本地stdio进程运行。以下所有客户端都以相同的方式启动它--
python <path-to>/windbg_mcp.py --但每个都有自己的配置格式。
克劳德桌面
编辑Claude Desktop配置文件并添加 windbg-mcp 条目:
配置文件位置:
- 窗户:
%APPDATA%\Claude\claude_desktop_config.json - macOS:
~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"windbg-mcp": {
"command": "python",
"args": ["C:\\path\\to\\windbg-mcp\\windbg_mcp.py"]
}
}
}
重新启动克劳德桌面。所有55个调试器工具将自动出现。
克劳德代码(CLI)
运行以下命令一次以注册服务器。Claude Code存储条目 在其自己的MCP配置中,并在每个后续会话中提供这些工具。
claude mcp add windbg-mcp python C:\path\to\windbg-mcp\windbg_mcp.py
要验证服务器是否已注册:
claude mcp list
要稍后删除它,请执行以下操作:
claude mcp remove windbg-mcp
克劳德协作
有两种方法可以将Winge-MCP添加到Cowork中:通过JSON配置(快速)或
通过将其安装为 .mcpb 插件包(可移植、可共享)。
选项A——JSON配置
- 打开Claude桌面应用程序并转到 设置→ MCP服务器.
- 点击 添加服务器 并粘贴以下内容:
{
"windbg-mcp": {
"command": "python",
"args": ["C:\\path\\to\\windbg-mcp\\windbg_mcp.py"]
}
}
- 保存并重新启动Cowork。这些工具将在您的下一次会话中可用。
选项B——作为 .mcpb 插件包
A. .mcpb 该文件是Cowork可以安装的插件目录的zip存档
直接。当与团队共享服务器或
跨机器。
第一步——构建 .mcpb 文件
从克隆存储库的根目录运行:
powershell -Command "Compress-Archive -Path '.\*' -DestinationPath 'windbg-mcp.zip'; Rename-Item 'windbg-mcp.zip' 'windbg-mcp.mcpb'"
这创造了 windbg-mcp.mcpb 在当前目录中,捆绑 windbg_mcp.py,
manifest.json,以及任何其他项目文件。
第2步——在协作中安装
- 打开克劳德桌面应用程序。
- 首选 设置→ 插件 (或 扩展).
- 点击 安装插件 并选择
windbg-mcp.mcpb. - 合作阅读
manifest.json从捆绑包中注册MCP服务器,以及 使所有工具立即可用,无需手动配置路径。
这 manifest.json 此仓库中捆绑的已正确配置:
{
"manifest_version": "0.2",
"name": "windbg-mcp",
"version": "1.0.0",
"description": "WinDbg MCP — full Windows debugger control via MCP tools",
"server": {
"type": "python",
"entry_point": "windbg_mcp.py",
"mcp_config": {
"command": "python",
"args": ["${__dirname}/windbg_mcp.py"]
}
}
}
${__dirname} 在安装时解析为Cowork解压缩的目录
bundle,因此您不需要硬编码任何路径。
OpenAI Codex命令行界面
将服务器添加到Codex CLI配置文件中。该文件通常位于
~/.codex/config.json (Linux/macOS)或 %USERPROFILE%\.codex\config.json (Windows)。
{
"mcpServers": {
"windbg-mcp": {
"command": "python",
"args": ["C:\\path\\to\\windbg-mcp\\windbg_mcp.py"]
}
}
}
保存后,开始新的Codex会话。Winchester工具将可用于 模型调用。
光标
- 打开 光标→ 偏好→ 光标设置.
- 导航到 主控程序 选项卡。
- 点击 添加新的全局MCP服务器 并使用此配置:
{
"windbg-mcp": {
"command": "python",
"args": ["C:\\path\\to\\windbg-mcp\\windbg_mcp.py"]
}
}
- 保存。Cursor将在其下一个Composer会话中连接到服务器。
Continue.dev
将以下内容添加到您的 ~/.continue/config.json (或工作空间级别
.continue/config.json):
{
"experimental": {
"modelContextProtocolServers": [
{
"transport": {
"type": "stdio",
"command": "python",
"args": ["C:\\path\\to\\windbg-mcp\\windbg_mcp.py"]
}
}
]
}
}
重新加载Continue扩展。55个调试器工具将出现在工具列表中。
自定义代理和MCP SDK
如果您正在构建自己的代理或自动化管道,请连接到Winchester MCP 通过标准MCP stdio传输。服务器通过stdin/stdout传输JSON-RPC 2.0。
Python(使用 mcp SDK)
import asyncio
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
server_params = StdioServerParameters(
command="python",
args=[r"C:\path\to\windbg-mcp\windbg_mcp.py"],
)
async def main():
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
# List all available tools
tools = await session.list_tools()
print([t.name for t in tools.tools])
# Load a crash dump
result = await session.call_tool(
"load_dump",
arguments={"path": r"C:\crashes\crash.dmp"},
)
print(result.content)
# Read 64 bytes at RSP
result = await session.call_tool(
"read_mem",
arguments={"addr": "0x00000000001FF000", "size": 64},
)
print(result.content)
asyncio.run(main())
Types/Node.js(使用 @modelcontextprotocol/sdk 包装)
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
import { StdioClientTransport } from "@modelcontextprotocol/sdk/client/stdio.js";
const transport = new StdioClientTransport({
command: "python",
args: ["C:\\path\\to\\windbg-mcp\\windbg_mcp.py"],
});
const client = new Client({ name: "my-agent", version: "1.0.0" }, {});
await client.connect(transport);
// Call a tool
const result = await client.callTool({
name: "load_dump",
arguments: { path: "C:\\crashes\\crash.dmp" },
});
console.log(result.content);
await client.close();
语言链/语言图
from langchain_mcp_adapters.tools import load_mcp_tools
from mcp import ClientSession, StdioServerParameters
from mcp.client.stdio import stdio_client
server_params = StdioServerParameters(
command="python",
args=[r"C:\path\to\windbg-mcp\windbg_mcp.py"],
)
async def get_tools():
async with stdio_client(server_params) as (read, write):
async with ClientSession(read, write) as session:
await session.initialize()
return await load_mcp_tools(session)
通过stdio直接JSON-RPC(语言无关)
服务器通过换行符分隔的JSON-RPC 2.0消息进行通信。你可以开车 通过写入进程的stdin并从stdout读取,可以从任何语言读取:
→ {"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"my-client","version":"1.0"}}}
← {"jsonrpc":"2.0","id":1,"result":{"protocolVersion":"2024-11-05","capabilities":{...},"serverInfo":{"name":"WinDbg MCP","version":"1.0.0"}}}
→ {"jsonrpc":"2.0","id":2,"method":"tools/call","params":{"name":"load_dump","arguments":{"path":"C:\\crashes\\crash.dmp"}}}
← {"jsonrpc":"2.0","id":2,"result":{"content":[{"type":"text","text":"{\"status\": \"ok\", ...}"}]}}
可用工具(共55个)
会话管理
| 工具 | 参数 | 返回 |
|---|---|---|
status |
— | {connected, type, pid, bitness} |
list_processes |
— | [{pid, name, description}] |
create |
path (必填), args, initial_break |
{status, pid, bitness} |
attach |
pid 或 name (不是两者), initial_break |
{status, pid, bitness} |
kernel_attach |
connect_string (必填), initial_break |
{status, type, connect_string} |
load_dump |
path (必填) |
{status, bitness, rip, symbol_at_rip} |
connect |
options (必填) |
{status, options} |
detach |
— | {status} |
terminate |
— | {status} |
create --在调试器下启动新进程。集 initial_break=True (默认)在进程入口点中断。
attach --附加到正在运行的进程。提供其中之一 pid (整数)或 name (进程文件名)。不要两者都提供。
kernel_attach --连接到远程内核调试器。 connect_string 使用KD语法,例如。 "net:port=55000,key=1.2.3.4".
load_dump --打开a .dmp 验尸分析文件。立即返回崩溃地址和最近的符号。
connect --连接到进程服务器进行远程用户模式调试。 options 使用DbgEng连接语法,例如。 "tcp:server=192.168.1.10,port=5555".
执行控制
| 工具 | 参数 | 返回 |
|---|---|---|
go |
timeout (毫秒,默认30000) |
{status, rip, symbol, new_captures, captures} |
step_into |
count (默认值1) |
{rip, instruction, symbol} |
step_over |
count (默认值1) |
{rip, instruction, symbol} |
step_out |
— | {rip, instruction, symbol} |
goto |
expr (必填) |
{rip, symbol} |
trace |
count (默认值10) |
{instructions: [{rip, instruction, symbol}], count} |
go --恢复执行并阻塞,直到下一个调试事件(断点、异常或超时)。返回新的RIP和运行时收集的任何捕获。
step_into --在调用被调用的函数之后,进入下一条指令。
step_over --逐步执行下一条指令,将通话视为一个步骤。
step_out --运行直到当前函数返回。
goto --运行直到达到特定的符号或十六进制地址,例如。 "Kernel32!ExitProcess" 或 "0x7fff12340000".
trace --执行N次单步迭代,并记录访问的每条指令。
断点
| 工具 | 参数 | 返回 |
|---|---|---|
bp |
expr (必填), capture, action, oneshot, passcount |
{id, expr, addr, capture} |
hw_bp |
addr (必填), size, access, capture, action, oneshot |
{id, addr, size, access} |
list_bps |
— | [{id, expr, type, capture, action, ...}] |
remove_bp |
id (必填) |
{status, id} |
enable_bp |
id (必填) |
{status, id} |
disable_bp |
id (必填) |
{status, id} |
bp --在符号或地址处设置软件(代码)断点。
expr:符号("ntdll!NtCreateFile")或十六进制地址("0x7ff800001234")capture:当true(默认),每次触发此断点时,都会自动将完整状态(寄存器、堆栈、内存)保存到捕获缓冲区action:"go"(默认)捕获后继续执行;"break"停止oneshot:在断点触发一次后将其删除passcount:只有在N通过该位置后才会开火
hw_bp --设置硬件/数据断点(监视点)。
addr:要监视的十六进制地址size:监视宽度(以字节为单位)--1,2,4,或8(默认值4)access:"e"执行,"w"写入(默认),"r"读capture,action,oneshot:语义与bp
list_bps --返回所有当前活动的断点及其ID、表达式、类型和设置。
remove_bp / enable_bp / disable_bp --通过以下方式管理断点 id 返回自 bp 或 hw_bp.
州捕获
断点为 capture: true (默认)自动保存完整调试器
每次开火时都要拍快照。快照包括所有寄存器、调用堆栈、,
RSP处的64字节堆栈存储器和RIP处的32字节代码。快照不断累积
在缓冲区中,可以随时使用 get_captures.
| 工具 | 参数 | 返回 |
|---|---|---|
get_captures |
— | {count, captures: [{bp_id, expr, timestamp, registers, rip, symbol_at_rip, instruction, stack, context_memory}]} |
clear_captures |
— | {status} |
capture_state |
— | {timestamp, registers, rip, symbol_at_rip, instruction, disasm_5, stack_at_rsp, call_stack} |
get_captures --返回自上次以来收集的所有捕获 clear_captures。每次捕获都包含:
registers--所有寄存器值均为{name: "0x..."}十六进制字符串rip--捕获时的指令指针symbol_at_rip--离RIP最近的符号instruction--RIP指令的拆卸stack--带有地址和返回地址的前10个调用堆栈帧context_memory.stack_at_rsp--RSP为64字节,十六进制、格式化和ASCIIcontext_memory.code_at_rip--RIP为十六进制并格式化为32个字节
clear_captures --清除捕获缓冲区。在开始新的跑步之前有用。
capture_state --立即按需拍摄当前状态的快照。在已被闯入时使用此功能,而不是等待断点触发。
记忆
| 工具 | 参数 | 返回 |
|---|---|---|
read_mem |
addr (必填), size (默认值16) |
{addr, size, hex, formatted, ascii} |
write_mem |
addr (必填), data (必填,十六进制字符串) |
{status, addr, bytes_written} |
read_ptr |
addr (必填), count (默认值1) |
{addr, values: ["0x..."]} |
poi |
addr (必填) |
{addr, value} |
read_str |
addr (必填), wide (默认为false) |
{addr, value, wide} |
dump_mem |
addr (必填), count (默认值8) |
{addr, output} |
mem_info |
addr (必填) |
{addr, info} |
mem_list |
— | [region_description_strings] |
read_mem --阅读 size 原始字节来自 addr。返回数据如下 hex (紧凑型), formatted (空格分隔字节),以及 ascii (可打印字符, . 不可打印)。
write_mem --将字节写入内存。 data 是一个十六进制字符串--空格和 \x 前缀会自动删除,例如。 "90909090", "\\x90\\x90\\x90\\x90",或 "90 90 90 90".
read_ptr --阅读 count 从以下位置开始的连续指针大小值(32位4个字节,64位8个字节) addr.
poi --在以下位置取消引用单个指针 addr (感兴趣的指针)。
read_str --读取以null结尾的字符串。Set wide=true 适用于UTF-16LE(Windows WCHAR)。
dump_mem --格式化的dword/指针转储,相当于 dd/dp 在Winge。
mem_info --返回包含以下内容的页面的内存区域属性 addr:基址、大小、类型、状态和保护标志。
mem_list --列出目标进程地址空间中的所有虚拟内存区域。
寄存器
| 工具 | 参数 | 返回 |
|---|---|---|
get_regs |
— | {rax, rbx, rcx, rdx, rsi, rdi, rbp, rsp, rip, r8–r15, eflags, ...} |
get_reg |
name (必填) |
{name, value} |
set_reg |
name (必填), value (必填) |
{status, name, value} |
get_pc |
— | {value, symbol, instruction} |
get_sp |
— | {value} |
get_regs --将每个可用注册表返回为 {name: "0x..."}确切的设置取决于目标架构(x86与x64)。
get_reg --返回单个寄存器,例如。 name="rax", name="eflags".
set_reg --覆盖注册表。 value 接受十六进制字符串("0x1234")或十进制整数字符串。
get_pc --返回具有符号分辨率的指令指针和该地址处的解码指令文本。
get_sp --返回当前堆栈指针值。
符号和拆卸
| 工具 | 参数 | 返回 |
|---|---|---|
resolve |
name (必填) |
{name, addr} 或 {name, addr: null, error} |
find_symbols |
pattern (必填) |
[symbol_strings] |
addr_to_symbol |
addr (必填) |
{addr, symbol} |
disasm |
addr (默认:当前RIP), count (默认值10) |
{addr, output} |
whereami |
addr (可选,默认:当前RIP) |
{description} |
resolve --将符号名称解析为其虚拟地址。使用 Module!Function 格式,例如。 "Kernel32!WriteFile", "ntdll!NtCreateFile".
find_symbols --通配符符号搜索,例如。 "ntdll!*Alloc*", "kernel32!*File*"。返回所有匹配的符号字符串。
addr_to_symbol --反向将虚拟地址解析为最接近的符号名称。
disasm --拆卸 count 说明开始于 addr。如果没有给出地址,则默认为当前RIP。
whereami --返回给定地址处模块、函数和偏移量的人类可读描述。
模块
| 工具 | 参数 | 返回 |
|---|---|---|
list_modules |
— | [{name, base, size}] |
module_info |
name (必填) |
{name, entry_point, sections} |
get_exports |
name (必填) |
[export_strings] |
get_imports |
name (必填) |
[import_strings] |
list_modules --列出目标中加载的所有模块及其基址和大小。
module_info --返回特定模块的入口点和部分列表(名称、虚拟地址、大小),例如。 "kernel32.dll", "ntdll.dll".
get_exports --以字符串列表的形式返回模块的完整导出表。
get_imports --以字符串列表的形式返回模块的完整导入表。
线程和堆栈
| 工具 | 参数 | 返回 |
|---|---|---|
list_threads |
— | [thread_description_strings] |
get_thread |
— | {current_thread} |
set_thread |
id (必填) |
{status, thread} |
get_stack |
frames (默认值20) |
{frames: [{frame, addr, return_addr, frame_ptr}], count} |
get_teb |
— | {addr} |
get_peb |
— | {addr} |
list_threads --列出目标进程中的所有线程。
get_thread --返回当前活动的线程上下文。
set_thread --按线程ID切换活动线程上下文(从 list_threads).
get_stack --将调用堆栈作为结构化数据返回。每个帧包括指令地址、返回地址和帧指针。
get_teb --返回当前线程的线程环境块的地址。
get_peb --返回进程环境块的地址。
工艺与公用工程
| 工具 | 参数 | 返回 |
|---|---|---|
get_handles |
— | [handle_description_strings] |
get_bitness |
— | {bits} |
raw |
cmd (必填) |
{output} |
get_handles --列出目标进程中所有打开的句柄。
get_bitness --退货 32 或 64 这取决于目标架构。
raw --执行任何Winkey命令字符串,并将输出作为文本返回。将此用作其他工具未覆盖的任何东西的逃生口:
raw(cmd="!heap -stat")
raw(cmd="dt _PEB @$peb")
raw(cmd="!locks")
raw(cmd="lm")
raw(cmd="!address @rsp")
典型工作流程
漏洞验证
1. create(path="C:/target/vuln.exe", args="exploit_input.bin")
2. bp(expr="vuln!processInput+0x2A", action="break")
3. go(timeout=15000)
4. get_captures()
在 get_captures,检查 captures[0].registers.rip:
"0x4141414141414141"--您使用“A”字节控制RIP- 任何与您的模式匹配的值都受控制
- 一个看起来有效的地址——崩溃但尚未控制
检查 captures[0].context_memory.stack_at_rsp.formatted 查看堆栈上的填充、返回地址或外壳代码字节。
碰撞倾倒分析
1. load_dump(path="C:/crashes/crash.dmp")
2. get_regs() → full register state at crash time
3. get_stack(frames=30) → call stack at crash
4. get_sp() → read RSP value
5. read_mem(addr=<rsp>, size=64) → stack contents
6. disasm() → instructions at the crash address
堆喷验证
1. attach(name="target.exe")
2. hw_bp(addr="0x1001F000", size=8, access="w", action="break")
3. go()
4. get_captures() → see what wrote to the spray address
5. read_mem(addr="0x1001EFC0", size=128) → surrounding memory context
ASLR检查
1. create(path="C:/target/target.exe")
2. resolve(name="kernel32!WriteFile") → record base address
3. terminate()
4. create(path="C:/target/target.exe")
5. resolve(name="kernel32!WriteFile") → compare: changed = ASLR on, same = ASLR off
远程内核调试
1. kernel_attach(connect_string="net:port=55000,key=1.2.3.4")
2. list_modules() → all loaded kernel modules
3. module_info(name="ntoskrnl.exe") → entry point and sections
4. raw(cmd="!process 0 0") → list all processes from kernel context
5. raw(cmd="!pcr") → processor control region
螺纹检查
1. attach(pid=1234)
2. list_threads() → all thread IDs
3. set_thread(id=2) → switch context
4. get_stack(frames=20) → call stack for that thread
5. get_regs() → registers for that thread
6. get_teb() → TEB address
提示
符号路径 --如果符号解析未返回结果,请配置Microsoft符号服务器:
raw(cmd=".sympath srv*C:\\symbols*https://msdl.microsoft.com/download/symbols")
raw(cmd=".reload")
超时调整 — go() 默认为30秒。对于在到达断点之前运行时间较长的目标:
go(timeout=120000) # 2 minutes
go(timeout=300000) # 5 minutes
地址格式 --全部 addr 参数接受十六进制字符串("0x1234abcd", "7fff12340000")或纯整数。这 0x 前缀对于十六进制值是可选的。
Shellcode验证 --捕获后,使用 read_mem 和 disasm 在您的shellcode应该着陆的地址上。如果 disasm 显示了您的预期指令,有效载荷完好无损地到达。
之后 terminate 或 detach --所有捕获和断点都会自动清除。呼叫 create 或 attach 开始新的会议。
capture_state 对比 get_captures --使用 capture_state 当已经在断点处停止时,用于按需快照。使用 get_captures 检索在每次触发断点时自动保存的状态 go 电话。
内核 raw 命令 --运行良好的通用内核调试扩展 raw:
raw(cmd="!process 0 0") → list all processes
raw(cmd="!thread") → current thread details
raw(cmd="!irql") → current IRQL
raw(cmd="!pcr") → processor control region
raw(cmd="!pte <addr>") → page table entry for an address
raw(cmd="dt nt!_EPROCESS @$proc") → dump EPROCESS structure
许可证
麻省理工学院
