dnSpy MCP服务器
A. 模型上下文协议(MCP) 嵌入在dnSpy中的服务器,暴露完整。NET程序集分析、编辑、调试、内存转储和去模糊功能,可用于任何兼容MCP的AI助手。
版本: 1.8.0 | 工具: 100+ | 状态:beta| 目标: .净值4.8+。NET 10.0操作系统
______________________________________________________________________
目录
- 装配工具 - 类型和成员工具 - 方法和反编译工具 - IL工具 - 控制流工具 - 分析和交叉参考工具 - 编辑工具 - 嵌入式资源工具 - 调试工具 - 源代码映射工具 - 运行时反转工具 - 内存转储和PE工具 - 静态PE分析 - 消毒工具 - 窗口/对话框工具 - 效用
______________________________________________________________________
特性
1.8.0版本发生了什么变化
- 可流式HTTP传输
POST /mcp现在是主MCP表面 - 使用Echo添加了受控CIL控制流分析
- 添加了受HoLLy启发的非UI SourceMap支持
- 运行时反向支持通过本机导出解析、Iced反汇编、补丁跟踪、PEB检查、线程挂起和DLL注入进行了扩展
- 通过以下方式添加了持久管理拦截
trace_method和hook_function - 工具可发现性现在包括目录元数据,例如
category,hidden_by_default,is_legacy,以及preferred_replacement
| 类别 | 功能 |
|---|---|
| 装配 | 列出加载的程序集、命名空间、类型计数、P/Invoke导入 |
| 类型 | 检查类型、字段、属性、事件、嵌套类型、属性、继承 |
| 反编译 | 将整个类型或单个方法分解为C# |
| 国际劳工组织 | 查看IL指令、原始字节、局部变量、异常处理程序 |
| 控制流 | 使用Echo为CIL方法构建托管CFG和简化的基本块视图 |
| 分析 | 查找调用者/用户、跟踪字段读/写、调用图、死代码、跨程序集依赖关系 |
| 编辑 | 重命名成员、更改访问修饰符、编辑元数据、修补方法、注入类型、保存到磁盘 |
| 资源 | 列出、读取、添加、删除嵌入式资源(ManifestResource表);提取Costura。Fody嵌入式组件 |
| 调试 | 管理断点(具有别名感知条件)、启动/附加进程、暂停/恢复/停止会话、单步执行(覆盖/进入/退出)、检查调用堆栈、读取本地值、计算表达式 |
| 拦截 | 持久的托管跟踪和断点支持的拦截 trace_method 和 hook_function |
| 源码图 | 在没有HoLLy UI的情况下查询、更新、列出、保存和加载SourceMap条目 |
| 运行时反转 | 解析导出,使用Iced反汇编本机函数,修补/恢复导出,检查PEB,挂起/恢复线程,注入本机/托管DLL |
| 内存转储 | 列出运行时模块,转储。NET或本机模块从内存中读取/写入进程内存,提取PE部分 |
| 静态PE分析 | 扫描原始PE字节以查找字符串;多功能ConfusedEx拆包器 |
| 脱毒 | de4dot集成:检测混淆器,重命名损坏的符号,解密字符串。两者都在处理中(deobfuscate_assembly)外部过程(run_de4dot)所有版本中都有可用的模式 |
| 窗口/对话框 | 列出活动对话框/消息框窗口(Win32 #32770 +WPF)在dnSpy进程中;通过按名称单击任何按钮来取消它们(支持EN和ES) |
| 搜索 | 在所有加载的程序集中进行Glob和正则表达式搜索 |
Echo集成
dnSpy.MCP.Server 仅集成Echo的稳定管理子集:
Echo.CoreEcho.ControlFlowEcho.Platforms.Dnlib
MCP服务器会 不 端口HoLLy UI、MSAGL、AsmResolver后端或符号执行。Echo集成仅限于可序列化的CIL控制流分析,MCP客户端和LLM可以可靠地使用该分析。
______________________________________________________________________
构建和安装
先决条件
| 要求 | 版本 |
|---|---|
| .NET SDK | 10.0+(适用于net10.0-windows目标) |
| .NET Framework SDK | 4.8(适用于net48目标) |
| 操作系统 | Windows(WPF依赖关系) |
| dnSpy | dnSpyEx(此仓库) |
de4dot集成 --de4dot库捆绑在libs/de4dot/(net48)和libs/de4dot-net8/(网络8/网络10)。不需要外部依赖;这两个构建目标中都提供了所有的debuscation工具。
克隆和还原
git clone https://github.com/dnSpyEx/dnSpy --recursive
cd dnSpy构建命令
# Build only the MCP Server extension (Debug)
dotnet build Extensions/dnSpy.MCP.Server/dnSpy.MCP.Server.csproj -c Debug
# Build only the MCP Server extension (Release)
dotnet build Extensions/dnSpy.MCP.Server/dnSpy.MCP.Server.csproj -c Release
# Build the full dnSpy solution (both targets)
dotnet build dnSpy.sln -c Debug
# Build for a specific target framework only
dotnet build Extensions/dnSpy.MCP.Server/dnSpy.MCP.Server.csproj -c Release -f net10.0-windows
dotnet build Extensions/dnSpy.MCP.Server/dnSpy.MCP.Server.csproj -c Release -f net48
# Restore NuGet packages without building
dotnet restore Extensions/dnSpy.MCP.Server/dnSpy.MCP.Server.csproj
# Clean build artifacts
dotnet clean Extensions/dnSpy.MCP.Server/dnSpy.MCP.Server.csproj输出位置
| 目标 | 输出路径 |
|---|---|
| .NET 10.0操作系统 | dnSpy/dnSpy/bin/Release/net10.0-windows/dnSpy.MCP.Server.x.dll |
| .NET框架4.8 | dnSpy/dnSpy/bin/Release/net48/dnSpy.MCP.Server.x.dll |
MCP服务器DLL直接输出到dnSpy的bin目录中,因此当您启动dnSpy时,它会自动加载。
验证构建
# Check for errors (expects "Compilación correcta" or "Build succeeded")
dotnet build Extensions/dnSpy.MCP.Server/dnSpy.MCP.Server.csproj -c Release --nologo 2>&1 | tail -5运行时
- 启动dnSpy——MCP服务器自动启动
http://localhost:3100 - 验证它是否正在运行:
curl http://localhost:3100/health
curl -i -X POST http://localhost:3100/mcp -H "Content-Type: application/json" -d "{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"probe\",\"version\":\"1.0\"}}}"- 配置您的MCP客户端(见下一节)
______________________________________________________________________
客户端配置
服务器现在使用 MCP流式HTTP 作为主要交通工具 http://localhost:3100/mcp.
运输摘要
GET /health返回一个简单的健康有效负载POST /mcp接受JSON-RPC MCP请求initialize返回协商的协议版本和Mcp-Session-Id响应头- 随后的
tools/list和tools/call请求必须包括Mcp-Session-Id
通用MCP客户端配置
{
"mcpServers": {
"dnspy": {
"type": "http",
"url": "http://localhost:3100/mcp"
}
}
}最小HTTP示例
curl -X POST http://localhost:3100/mcp \
-H "Content-Type: application/json" \
-d '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-03-26",
"capabilities": {},
"clientInfo": { "name": "example-client", "version": "1.0" }
}
}'一些MCP客户端仍然将流式HTTP标记为http,streamable-http,或remote这取决于它们的配置格式。端点是相同的:http://localhost:3100/mcp.
______________________________________________________________________
工具参考
所有工具在MCP上称为 tools/call 使用JSON参数对象。 标记的参数 必需的 必须始终提供;所有其他选项都是可选的。
______________________________________________________________________
装配工具
用于列出和检查的工具。NET程序集已加载到dnSpy中。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
list_assemblies | 列出dnSpy中当前打开的每个程序集,包括版本、区域性和公钥标记 | -- | -- |
get_assembly_info | 一个程序集的详细信息:模块、命名空间、类型计数 | assembly_name | cursor |
list_types | 使用类/接口/枚举标志列出程序集中的类型。通过以下方式支持glob和regex name_pattern | assembly_name | namespace, name_pattern, cursor |
list_native_modules | 列出通过导入的本机DLL [DllImport],按DLL名称和使用它们的托管方法分组 | assembly_name | — |
load_assembly | 加载a。NET程序集从磁盘上的文件转换为dnSpy 或 通过PID控制正在运行的进程。支持普通PE布局和原始内存布局转储 | -- | file_path, memory_layout, pid, module_name |
select_assembly | 在dnSpy文档树中选择一个程序集,并在活动选项卡中打开它;更改当前程序集上下文以进行后续操作 | assembly_name | file_path |
close_assembly | 从dnSpy中关闭(删除)特定程序集 | assembly_name | file_path |
close_all_assemblies | 关闭dnSpy中当前加载的所有程序集,清除文档树 | -- | -- |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
assembly_name | string | dnSpy中显示的短程序集名称(例如。 UnityEngine.CoreModule) |
namespace | string | 精确的命名空间筛选器(例如。 System.Collections.Generic) |
name_pattern | string | 类型名称上的Glob或正则表达式过滤器——请参阅 模式语法 |
cursor | string | 不透明的base-64分页光标 nextCursor 在之前的回复中 |
file_path | string | (load_assembly)通往a的绝对路径。NET程序集或内存转储 |
memory_layout | boolean | (load_assembly)何时 true,将文件视为原始内存布局(VA,而不是文件偏移量)。默认 false |
pid | 整数 | (load_assembly)运行的PID。NET进程从中转储。需要活动调试会话。 |
module_name | string | (load_assembly)使用时要选择的模块名称/文件名 pid。默认为第一个EXE模块。 |
file_path | string | (select_assembly, close_assembly)绝对路径(来自的FilePath list_assemblies)当多个程序集共享相同的短名称时,消除歧义 |
______________________________________________________________________
类型和成员工具
用于检查特定类型内部构件的工具。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
get_type_info | 完整类型概述:可见性、基本类型、接口、字段、属性、方法(分页) | assembly_name, type_full_name | cursor |
search_types | 按名称搜索类型 全部 装载组件 | query | cursor |
get_type_fields | 列出与名称模式匹配的字段,包括类型、可见性和 readonly/const 旗帜 | assembly_name, type_full_name, pattern | cursor |
get_type_property | 单个属性的完整细节:getter/setter签名、属性 | assembly_name, type_full_name, property_name | — |
list_properties_in_type | 具有读/写标志的所有属性的摘要列表 | assembly_name, type_full_name | cursor |
list_events_in_type | 所有活动 add/remove 方法信息 | assembly_name, type_full_name | — |
list_nested_types | 所有嵌套类型递归(全名、可见性、种类) | assembly_name, type_full_name | — |
get_custom_attributes | 类型或其成员之一的自定义属性 | assembly_name, type_full_name | member_name, member_kind |
analyze_type_inheritance | 完整继承链(基类+接口) | assembly_name, type_full_name | — |
find_path_to_type | BFS遍历属性/字段引用,以查找一种类型如何到达另一种类型 | assembly_name, from_type, to_type | max_depth |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
type_full_name | string | 完全限定的类型名称(例如。 MyNamespace.MyClass) |
query | string | 匹配的子字符串、glob或正则表达式 FullName |
pattern | string | 用于字段名匹配的Glob或正则表达式;使用 * 列出所有 |
property_name | string | 精确的属性名(不区分大小写) |
member_name | string | 属性查找的成员名称(省略以获取类型级属性) |
member_kind | string | 消除重载名称的歧义: method, field, property,或 event |
from_type | string | BFS路径搜索起始类型的全名 |
to_type | string | 目标类型的名称或子字符串 |
max_depth | integer | BFS深度限制(默认值 5) |
______________________________________________________________________
方法和反编译工具
用于反编译代码和探索方法元数据的工具。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
decompile_type | 将整个类型(类/结构/接口/枚举)分解为C# | assembly_name, type_full_name | — |
decompile_method | 将单个方法分解为C# | assembly_name, type_full_name, method_name | — |
list_methods_in_type | 列出具有返回类型、可见性、静态、虚拟和参数计数的方法。按可见性或名称模式过滤 | assembly_name, type_full_name | visibility, name_pattern, cursor |
get_method_signature | 一个方法的完整签名:参数、返回类型、泛型约束 | assembly_name, type_full_name, method_name | — |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
method_name | string | 方法名(重载存在时首先匹配;使用 get_method_signature 为了消除歧义) |
visibility | string | 筛选器: public, private, protected,或 internal |
name_pattern | string | 方法名称上的Glob或正则表达式(例如。 Get*, ^On[A-Z], Async$) |
______________________________________________________________________
IL工具
方法体的低水平IL检查。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
get_method_il | IL指令列表,包括偏移量、操作码、操作数和局部变量表 | assembly_name, type_full_name, method_name | — |
get_method_il_bytes | 原始IL字节为十六进制字符串和Base64 | assembly_name, type_full_name, method_name | — |
get_method_exception_handlers | try/catch/final/故障区域表(偏移量和处理程序类型) | assembly_name, type_full_name, method_name | — |
dump_cordbg_il | 对于暂停模块中的每个MethodDef,读取 ICorDebugFunction.ILCode.Address 和 ILCode.Size 通过CorDebug COM API(通过反射)。报告IL地址是位于PE映像内部(加密存根)还是外部(JIT挂钩缓冲区)。可用于ConfusedEx JIT钩子分析。需要活动的暂停调试会话 | -- | module_name, output_path, max_methods, include_bytes |
参数详细信息(dump_cordbg_il)
| 参数 | 类型 | 说明 |
|---|---|---|
module_name | string | 模块名称或文件名筛选器(默认值:第一个EXE模块) |
output_path | string | 将完整JSON结果保存到磁盘的可选路径 |
max_methods | integer | 要扫描的MethodDef令牌的最大数量(默认值 10000) |
include_bytes | boolean | 何时 true,包括每种方法的Base64编码IL字节(默认值 false) |
______________________________________________________________________
控制流工具
在dnlib支持的方法体上使用Echo对CIL方法进行可序列化的托管控制流分析。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
get_control_flow_graph | 包含块、边、条目块和摘要度量的完整CFG视图 | assembly_name, type_full_name, method_name | — |
get_basic_blocks | 简化了基本块摘要视图,旨在快速使用LLM | assembly_name, type_full_name, method_name | — |
get_basic_blocks有意采用紧凑的摘要形式get_control_flow_graph.
______________________________________________________________________
分析和交叉参考工具
所有加载程序集的调用图、使用情况和依赖关系分析。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
find_who_calls_method | 查找IL包含 call/callvirt 到目标 | assembly_name, type_full_name, method_name | — |
find_who_uses_type | 查找引用类型的所有类型、方法和字段(基类、接口、字段类型、参数、返回类型) | assembly_name, type_full_name | — |
find_who_reads_field | 查找通过以下方式读取字段的所有方法 ldfld/ldsfld IL说明 | assembly_name, type_full_name, field_name | — |
find_who_writes_field | 查找通过以下方式写入字段的所有方法 stfld/stsfld IL说明 | assembly_name, type_full_name, field_name | — |
analyze_call_graph | 为一个方法构建一个递归调用图,显示它调用到可配置深度的所有方法 | assembly_name, type_full_name, method_name | max_depth |
find_dependency_chain | 通过BFS在基类型、接口、字段、参数和返回类型上查找两种类型之间的所有依赖路径 | assembly_name, from_type, to_type | max_depth |
analyze_cross_assembly_dependencies | 为所有加载的程序集计算一个依赖矩阵,显示每个程序集所依赖的 | -- | -- |
find_dead_code | 识别从未被调用或引用的方法和类型(静态近似;不跟踪虚拟调度和反射) | assembly_name | — |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
field_name | string | 用于搜索读/写访问权限的确切字段名 |
max_depth | integer | 调用图或BFS遍历的递归深度限制(默认值 5) |
______________________________________________________________________
编辑工具
内存元数据编辑。更改会立即应用于dnlib的内存模型,并持续到 save_assembly 被调用或dnSpy关闭而不保存。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
change_member_visibility | 更改类型或其成员之一的访问修饰符 | assembly_name, type_full_name, member_kind, new_visibility | member_name |
rename_member | 重命名类型或其成员之一 | assembly_name, type_full_name, member_kind, old_name, new_name | — |
save_assembly | 使用dnlib将(可能修改过的)程序集写入磁盘 ModuleWriter | assembly_name | output_path |
get_assembly_metadata | 读取程序集级元数据:名称、版本、区域性、公钥、标志、哈希算法、模块计数、自定义属性 | assembly_name | — |
edit_assembly_metadata | 编辑程序集级元数据字段:名称、版本、区域性或哈希算法 | assembly_name | name, version, culture, hash_algorithm |
set_assembly_flags | 设置或清除单个程序集属性标志(例如。 PublicKey, Retargetable,处理器架构) | assembly_name, flag_name, value | — |
list_assembly_references | 列出清单模块中的所有程序集引用(AssemblyRef表条目) | assembly_name | — |
add_assembly_reference | 通过从磁盘加载DLL来添加程序集引用。创建一个TypeForwarder来锚定引用 | assembly_name, dll_path | — |
remove_assembly_reference | 删除AssemblyRef条目和所有针对它的TypeForwarder条目。如果代码中的TypeRefs仍然使用该引用,则返回警告 | assembly_name, reference_name | — |
inject_type_from_dll | 将类型(字段、带IL的方法、属性、事件)从外部DLL深度克隆到目标程序集中 | assembly_name, dll_path, type_full_name | — |
list_pinvoke_methods | 列出所有P/Invoke(DllImport)类型中的声明:托管名称、令牌、DLL名称、本机函数名称 | assembly_name, type_full_name | — |
patch_method_to_ret | 用最小返回存根替换方法的IL体(nop + ret)中和它。也适用于P/Invoke方法(转换为托管存根) | assembly_name, type_full_name, method_name | — |
参数详细信息
| 参数 | 类型 | 值/描述 |
|---|---|---|
member_kind | 字符串 | type, method, field, property,或 event |
new_visibility | 字符串 | public, private, protected, internal, protected_internal, private_protected |
old_name | string | 当前成员名称 |
new_name | string | 所需的新名称 |
output_path | string | 输出文件的绝对路径。默认为原始文件位置。 |
flag_name | string | 要切换的程序集标志(例如。 PublicKey, Retargetable, PA_MSIL, PA_x86, PA_AMD64) |
value | 布尔值 | true 为了设置标志, false 清除它 |
dll_path | string | 源DLL的绝对路径 |
备注: rename_member 仅更改元数据名称。确实如此 不 更新调用站点、字符串文字或XML文档。备注: patch_method_to_ret 非常适合在保存和重新分析之前禁用防调试、防篡改或许可证检查例程。______________________________________________________________________
嵌入式资源工具
从ManifestResource表中读取、写入和提取条目。所有写入操作都在内存中,直到 save_assembly 被称为。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
list_resources | 列出所有ManifestResource条目:名称、类型(嵌入式/链接/组装链接)、大小、可见性以及它是否看起来像Costura。Fody嵌入式组件 | assembly_name | — |
get_resource | 将嵌入式资源提取为Base64(最多4 MB内联)和/或保存到磁盘 | assembly_name, resource_name | output_path, skip_base64 |
add_resource | 将磁盘中的文件作为新的EmbeddedResource嵌入到程序集中 | assembly_name, resource_name, file_path | is_public |
remove_resource | 按名称删除ManifestResource条目 | assembly_name, resource_name | — |
extract_costura | 检测并提取Costura。Fody嵌入式组件(costura.*.dll.compressed 资源)。自动解压缩gzip。可用于分析装有Costura的组件 | assembly_name, output_directory | decompress |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
resource_name | string | 精确的资源名称(使用 list_resources 找到它) |
output_path | string | (get_resource)写入原始资源字节的绝对路径 |
skip_base64 | boolean | (get_resource)在响应中省略Base64;在将大量资源保存到磁盘时非常有用(默认 false) |
is_public | boolean | (add_resource)资源可见性-- true =公共(默认), false =私人 |
output_directory | string | (extract_costura)将写入提取的DLL/PDB的目录 |
decompress | boolean | (extract_costura)解压缩gzip压缩资源(默认 true) |
科斯图拉。Fody工作流程:list_resources(确认costura.*条目存在)→extract_costura output_directory=C:\extracted→load_assembly每个提取的DLL→ 使用MCP工具正常分析。
______________________________________________________________________
技能知识库
存储在中的持久逆向工程知识库 %APPDATA%\dnSpy\dnSpy.MCPServer\skills\每个技能都是一对文件:一个Markdown叙述({id}.md)JSON技术记录({id}.json).技能捕捉了分步过程、魔术值、加密密钥、算法、偏移量和通用提示——因此,一旦你反转了打包器或混淆器,这些知识就可以重复使用。
工作流程:在分析新二进制文件之前,调用 search_skills 检查现有知识。完成分析后,致电 save_skill 记录调查结果。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
list_skills | 列出知识库中的所有技能,包括ID、名称、描述、标签和目标 | -- | tag |
get_skill | 检索技能的完整Markdown叙述和JSON技术记录 | skill_id | — |
save_skill | 创建或更新技能。写入Markdown和/或JSON。使用 merge=true 在不覆盖现有数据的情况下附加发现 | skill_id | name, description, tags, targets, markdown, json_data, merge |
search_skills | 在所有技能Markdown和JSON文件中进行全文搜索。返回与上下文片段匹配的结果 | query 或 tag | query, tag |
delete_skill | 永久删除技能(两者 .md 和 .json 文件) | skill_id | — |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
skill_id | string | 技能标识符--将被模糊化(例如。 confuserex-unpacking).使用 list_skills 查看现有ID |
name | string | 人类可读的技能名称 |
description | string | 技能涵盖内容的简短总结 |
tags | string | 逗号分隔或JSON标记数组(例如。 packer,confuserex,unpacking) |
targets | string | 逗号分隔或JSON数组的目标二进制名称或哈希值,此技能适用于 |
markdown | string | Markdown叙事:做什么,为什么,关键观察,散文中的程序步骤 |
json_data | string | 带技术细节的JSON对象: procedure (步骤与 tool/prompt/expected), magic_values, crypto_keys, algorithms, offsets, findings, prompts (识别/应用/验证/故障排除) |
merge | boolean | 如果 true,深度合并 json_data 添加到现有记录中,而不是替换它(默认 false) |
query | string | (search_skills)要在所有技能文件中搜索的关键字或短语 |
tag | string | (list_skills, search_skills)将结果筛选到包含此标签子字符串的技能 |
JSON技能记录结构示例
{
"id": "confuserex-unpacking",
"name": "ConfuserEx Unpacking",
"version": "1",
"tags": ["packer", "confuserex", "unpacking"],
"targets": ["MyProtectedApp.exe"],
"description": "Step-by-step procedure to unpack ConfuserEx 1.x protected assemblies",
"procedure": [
{ "step": 1, "tool": "detect_obfuscator", "prompt": "Detect which obfuscator was applied", "expected": "ConfuserEx v1.x" },
{ "step": 2, "tool": "start_debugging", "prompt": "Launch under dnSpy with break_kind=EntryPoint", "expected": "Paused at entry point after .cctor" },
{ "step": 3, "tool": "dump_module_from_memory", "prompt": "Dump decrypted module from RAM", "expected": "Raw PE bytes" }
],
"magic_values": { "key_offset": "0x1234", "xor_key": "0xDEADBEEF" },
"crypto_keys": [],
"algorithms": ["XOR", "AES-128-ECB"],
"prompts": {
"identify": "Use detect_obfuscator on the assembly. If ConfuserEx, proceed with this skill.",
"apply": "Follow procedure steps 1-3. After dump, reload and deobfuscate.",
"verify": "Decompile Main() — if readable C# appears, unpacking succeeded.",
"troubleshoot": "If dump_module_from_memory fails, try dump_module_unpacked with fix_pe_header=true."
}
}______________________________________________________________________
调试工具
与dnSpy的集成调试器交互。大多数工具都需要一个活动的调试会话。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
get_debugger_state | 当前状态: IsDebugging, IsRunning,包含线程/运行时计数的进程列表 | -- | -- |
list_breakpoints | 所有具有启用状态、绑定计数和位置的已注册代码断点 | -- | -- |
set_breakpoint | 在方法入口点或特定IL偏移处设置断点。支持别名感知条件,例如 $arg0, $local0, arg(0), local(0), field("Name"),以及 memberByToken("0x06001234") | assembly_name, type_full_name, method_name | il_offset, condition, file_path |
set_breakpoint_ex | 扩展兼容性别名 set_breakpoint 具有相同的别名感知条件支持 | assembly_name, type_full_name, method_name | il_offset, condition, file_path |
remove_breakpoint | 删除特定断点 | assembly_name, type_full_name, method_name | il_offset |
clear_all_breakpoints | 删除所有可见断点 | -- | -- |
continue_debugger | 恢复所有暂停的进程(RunAll) | — | — |
break_debugger | 暂停所有正在运行的进程(BreakAll). safe_pause=true 仅使用dnSpy管理的暂停,从不呼叫 Debugger.Break() | — | safe_pause |
stop_debugging | 终止所有活动的调试会话 | -- | -- |
get_call_stack | 当前选定(或第一个暂停)线程的调用堆栈--最多50帧 | -- | -- |
step_over | 跳过当前的声明。阻塞,直到步骤完成(或超时)。返回新的执行位置(令牌、IL偏移、模块)。 | — | thread_id, process_id, timeout_seconds |
step_into | 进入下一个调用的方法。阻断行为与 step_over. | — | thread_id, process_id, timeout_seconds |
step_out | 运行,直到当前方法返回给调用者。 | — | thread_id, process_id, timeout_seconds |
get_current_location | 无需步进即可读取顶部框架执行位置。需要暂停调试器。 | — | thread_id, process_id |
wait_for_pause | 轮询,直到任何进程暂停(在 continue_debugger 或 start_debugging).返回暂停、抛出的进程信息 TimeoutException 否则。 | — | timeout_seconds |
start_debugging | 在dnSpy调试器下启动EXE。默认情况下,中断时间为 EntryPoint (模块后 .cctor 已运行,因此ConfusedEx解密体位于RAM中) | exe_path | arguments, working_directory, break_kind |
attach_to_process | 将dnSpy调试器附加到运行中。NET进程的PID | process_id | — |
set_exception_breakpoint | 抛出特定异常类型时中断。可配置的第一次机会(捕获前)和第二次机会(未处理)。默认值:启用第一次机会。 | exception_type | first_chance, second_chance, category |
remove_exception_breakpoint | 删除特定异常类型的异常断点 | exception_type | category |
list_exception_breakpoints | 列出所有活动异常断点(至少设置了一个机会标志的断点) | -- | -- |
batch_breakpoints | 在一次调用中创建多个断点以减少往返 | items | — |
get_method_by_token | 通过元数据令牌解析方法,并在可用时返回签名、RVA、JIT/加载状态提示和本机地址元数据 | assembly_name, token | — |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
il_offset | integer | 方法体中的IL字节偏移量(默认值 0 =方法条目) |
condition | string | 每次断点命中时计算的C#表达式。别名感知表单包括 $arg0, $local0, arg(0), local(0), field("Name"),以及 memberByToken("0x06001234") |
exe_path | string | 要启动的EXE的绝对路径 |
arguments | string | 要传递给进程的命令行参数 |
working_directory | string | 已启动进程的工作目录 |
break_kind | 字符串 | EntryPoint (默认情况下,暂停后 .cctor)或 ModuleCctorOrEntryPoint (之前停顿 .cctor) |
thread_id | integer | 显式线程ID以执行步骤/检查。默认为当前线程,然后是第一个暂停的线程。 |
timeout_seconds | integer | 等待步骤或暂停完成的最大秒数(默认值 30) |
exception_type | string | 异常类名(例如。 System.NullReferenceException, System.IO.IOException) |
first_chance | boolean | 在a之前打断 catch 块处理异常(默认 true) |
second_chance | boolean | 未处理的异常中断(默认 false) |
category | string | 异常类别字符串(默认 DotNet).使用 DotNet 用于管理异常。 |
小贴士:使用start_debugging+break_kind: EntryPoint对于ConfusedEx打包的程序集,方法体在断点命中时被解密。然后使用dump_module_from_memory或unpack_from_memory.
步骤工作流程:break_debugger(或等待BP)→get_current_location→step_over/step_into→ 检查get_local_variables或eval_expression→ 重复。
______________________________________________________________________
源代码映射工具
SourceMap支持从HoLLy有用的非UI部分移植而来。这些工具将命名数据保存在MCP缓存中,而不依赖于HoLLy选项卡或菜单。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
get_source_map_name | 解析类型或成员的当前SourceMap名称 | assembly_name, type_full_name | member_kind, member_name |
set_source_map_name | 在MCP缓存中设置或更新SourceMap条目 | assembly_name, type_full_name, mapped_name | member_kind, member_name |
list_source_map_entries | 列出程序集的所有缓存SourceMap条目 | assembly_name | — |
save_source_map | 将程序集的当前SourceMap缓存持久化到磁盘 | assembly_name | output_path |
load_source_map | 将SourceMap XML文件加载到MCP缓存中 | assembly_name, input_path | — |
______________________________________________________________________
运行时反转工具
流程级反向和持久拦截工具。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
get_proc_address | 解析已加载模块中的导出函数地址 | module, function | process_id |
patch_native_function | 修补内存中的本机导出和可选的自动包装保护更改 | module, function | hex_bytes, bytes, bytes_base64, process_id, auto_virtual_protect |
revert_patch | 通过以下方式还原跟踪的补丁 patch_id | patch_id | auto_virtual_protect |
list_active_patches | 列出MCP服务器创建的跟踪本机补丁 | -- | -- |
disassemble_native_function | 使用Iced进行面向符号的本地拆卸 | module, function | size, process_id |
read_native_memory | 在中读取本机内存 hex, ascii,或 disasm 形式 | address, size | format, process_id |
suspend_threads | 冻结目标进程中的所有或选定线程 | -- | process_id, thread_ids |
resume_threads | 仅恢复之前通过MCP服务器冻结的线程 | -- | process_id, thread_ids |
get_peb | 尽最大努力读取PEB反调试字段 | -- | process_id |
inject_native_dll | 通过以下方式注入本机DLL LoadLibraryW 和 CreateRemoteThread | dll_path | process_id |
inject_managed_dll | 通过CLR或Mono入口点调用进行管理注入 | dll_path, type_name, method_name | argument, copy_to_temp, process_id |
trace_method | 不暂停执行的持久托管跟踪 | assembly_name, type_full_name, method_name | token, file_path, il_offset, condition, max_calls, max_log_entries |
hook_function | 持续管理拦截 break, log,或 count 行动 | assembly_name, type_full_name, method_name | token, file_path, il_offset, condition, action, max_calls, max_log_entries |
list_active_interceptors | 拦截器会话摘要视图 | -- | include_inactive |
get_interceptor_log | 一个拦截器会话的详细命中日志 | session_id | — |
remove_interceptor | 删除拦截器会话及其底层断点 | session_id | — |
hook_function故意拒绝modify_return而不是暴露一个不稳定的实现。
______________________________________________________________________
内存转储和PE工具
从已调试的进程中提取原始字节。除非另有说明,否则需要活动调试会话。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
list_runtime_modules | 枚举所有。NET模块加载到调试进程中, IsDynamic, IsInMemory,以及AppDomain | -- | process_id, name_filter |
dump_module_from_memory | 提取a。NET模块从进程内存到文件(尽可能保留文件布局) | module_name, output_path | process_id |
read_process_memory | 从任何进程地址读取高达64KB的数据;返回格式化的十六进制转储和Base64 | address, size | process_id |
write_process_memory | 将字节写入进程地址(热修补)。接受 bytes_base64 (base64)或 hex_bytes (例如。 "90 90 C3").可用于在不接触磁盘上的二进制文件的情况下禁用检查。 | address, (bytes_base64 或 hex_bytes) | process_id |
get_local_variables | 从暂停的堆栈帧中读取局部变量和参数;返回复杂对象的基元、字符串和地址 | -- | frame_index, process_id |
eval_expression | 在当前暂停的帧上下文中计算C#表达式(相当于监视窗口)。返回类型值:基元、字符串或对象地址 | expression | frame_index, process_id, func_eval_timeout_seconds |
get_pe_sections | 列出进程内存中模块的PE节标头(名称、虚拟地址、大小、特性) | module_name | process_id |
dump_pe_section | 提取特定的PE部分(例如。 .text, .data, .rsrc)来自进程存储器中的模块;写入文件和/或返回Base64 | module_name, section_name | output_path, process_id |
dump_module_unpacked | 使用内存到文件布局转换转储完整模块(生成有效的可加载PE)。手柄。NET、本机和混合模式模块 | module_name, output_path | process_id |
dump_memory_to_file | 将连续的进程内存范围保存到文件中。支持高达256 MB | address, size, output_path | process_id |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
process_id | integer | 目标进程ID(使用 get_debugger_state 找到它)。默认为第一个暂停的进程。 |
name_filter | string | 模块名称或文件名上的Glob或正则表达式过滤器 |
module_name | string | 模块名称、完整文件名或基本名称(例如。 MyApp.dll).使用 list_runtime_modules 找到确切的名字。 |
output_path | string | 写入转储字节的绝对路径。父目录是自动创建的。 |
address | string | 十六进制内存地址(0x7FF000)或十进制 |
size | integer | 要读取/转储的字节数 |
bytes_base64 | string | 以base64格式写入的字节数(与 write_process_memory) |
hex_bytes | string | 要写入十六进制字符串的字节数-- "90 90 C3", "9090C3", "0x90 0x90" 全部接受 |
frame_index | integer | 堆栈帧索引(0=顶部/最内层,默认值 0) |
expression | string | 要在当前帧上下文中求值的C#表达式(例如。 "myObj.Field", "arr.Length") |
func_eval_timeout_seconds | integer | 调试对象中函数求值调用的超时(默认值 5) |
section_name | string | PE节名称(例如。 .text, .data, .rsrc) |
布局说明:dump_module_from_memory报告IsFileLayout在其回应中。如果false,使用dump_module_unpacked而是用于校正PE布局。
______________________________________________________________________
静态PE分析
对原始PE文件字节进行操作的工具——不需要调试会话。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
scan_pe_strings | 扫描原始PE文件字节,查找可打印的ASCII和UTF-16字符串。用于在打包/模糊程序集中查找URL、API密钥、IP地址和嵌入的明文 | assembly_name | min_length, encoding |
unpack_from_memory | All-in-one ConfusedEx解包器:在调试器下启动EXE(暂停在 EntryPoint 解密后),使用PE布局修复转储主模块,并可选择停止会话。输出可以加载到dnSpy中或传递给 deobfuscate_assembly | exe_path | output_path, stop_after_dump |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
min_length | integer | 要包含的最小字符串长度(默认值 4) |
encoding | 字符串 | ascii, unicode,或 both (默认值 both) |
exe_path | string | 要解包的打包EXE的绝对路径 |
output_path | string | 解压缩PE的目标(默认值: _unpacked.exe 输入旁边) |
stop_after_dump | boolean | 转储后是否停止调试会话(默认 true) |
工作流程:scan_pe_strings→ 了解打包的二进制文件包含什么→unpack_from_memory→deobfuscate_assembly→ 在dnSpy中加载干净的文件。
______________________________________________________________________
消毒工具
两种de4dot集成模式: 过程中的 (deobfuscate_assembly --使用捆绑的de4dot库,在所有版本中都可用)以及 外部进程 (run_de4dot --产卵 de4dot.exe,支持动态字符串解密,在所有版本中都可用)。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
list_deobfuscators | 列出进程内de4dot引擎支持的所有混淆器类型 | -- | -- |
detect_obfuscator | 检测哪个混淆器应用于。NET程序集文件在磁盘上的检测 | file_path | — |
deobfuscate_assembly | 去除毒素。NET程序集进程内:重命名损坏的符号,取消控制流,解密字符串 | file_path, output_path | obfuscator_type, rename_symbols |
save_deobfuscated | 返回一个之前已去模糊的文件,作为Base64编码的blob。当无法直接访问输出文件时有用 | file_path | — |
run_de4dot | 快跑 de4dot.exe 作为一个外部过程。支持需要单独进程的动态字符串解密和ConfusedEx方法解密 | file_path | output_path, obfuscator_type, dont_rename, no_cflow_deob, string_decrypter, extra_args, de4dot_path, timeout_ms |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
file_path | string | 到的绝对路径。磁盘上的NET程序集 |
output_path | string | 已清理输出程序集的绝对路径 |
obfuscator_type | string | 强制使用特定的混淆器类型代码(cr 对于ConfusedEx来说, un 未知/自动等)。省略让de4dot自动检测。 |
rename_symbols | boolean | (deobfuscate_assembly)是否重命名模糊符号(默认 true) |
dont_rename | boolean | (run_de4dot)如果出现以下情况,则跳过符号重命名 true (默认值 false) |
no_cflow_deob | boolean | (run_de4dot)如果出现以下情况,则跳过控制流去雾 true (默认值 false) |
string_decrypter | string | (run_de4dot)字符串解密器模式: none, default, static, delegate, emulate |
extra_args | string | (run_de4dot)逐字传递其他de4dot命令行参数 |
de4dot_path | string | (run_de4dot)覆盖路径 de4dot.exe。默认为众所周知的搜索路径。 |
timeout_ms | 整数 | (run_de4dot)等待de4dot完成的最长毫秒数(默认值 120000) |
______________________________________________________________________
窗口/对话框工具
枚举和关闭对话框(Win32 MessageBox, #32770 对话框和WPF窗口),例如阻止调试会话的错误弹出窗口。不需要调试会话。
| 工具 | 说明 | 必需参数 | 可选参数 |
|---|---|---|---|
list_dialogs | 列出所有活动的对话框/消息框窗口。返回每个 | -- | --的标题、HWND(十六进制)、消息文本和可用按钮标签 |
close_dialog | 单击命名按钮关闭对话框。通过HWND解析目标或选择第一个活动对话框 | -- | hwnd, button |
参数详细信息
| 参数 | 类型 | 说明 |
|---|---|---|
hwnd | string | 目标对话框的十六进制HWND,由返回 list_dialogs (例如。 "1A2B3C").如果省略,则使用第一个活动对话框 |
button | string | 要单击的按钮(不区分大小写,EN和ES): ok/aceptar, yes/sí, no, cancel/cancelar, retry/reintentar, ignore/omitir默认值: ok |
按钮匹配 --该工具首先检查常见的精确标记(EN+ES),然后回退到子字符串匹配。如果没有匹配的按钮, WM_CLOSE 发送到对话框。示例
// List all open dialogs
{ "tool": "list_dialogs" }
// Dismiss the first dialog by clicking OK
{ "tool": "close_dialog" }
// Dismiss a specific dialog by HWND, clicking Cancel
{ "tool": "close_dialog", "arguments": { "hwnd": "1A2B3C", "button": "cancel" } }______________________________________________________________________
效用
| 工具 | 说明 | 必填参数 |
|---|---|---|
list_tools | 以JSON格式返回每个注册工具的完整模式 | -- |
get_mcp_config | 返回当前MCP服务器配置和路径 mcp-config.json | — |
reload_mcp_config | 重新加载 mcp-config.json 从磁盘而不重新启动dnSpy | -- |
______________________________________________________________________
模式语法
一些工具接受 name_pattern 或 query 同时支持两者的参数 通配符 和 正则表达式 语法。发动机自动检测模式。
| 模式 | 检测时间 | 示例 | |
|---|---|---|---|
| 全局 | 模式仅包含 * 或 ? 通配符 | Get*, *Controller, On?Click | |
| 正则表达式 | 图案包含以下任何一项 `^ $ [ ( \ | + {` | ^Get[A-Z], Controller$, ^I[A-Z].*Service$ |
| 子字符串 | 无特殊字符(用于 search_types 仅) | Player, Manager |
所有模式匹配都是 不区分大小写.
# Find all types whose name starts with "Player"
name_pattern: "Player*"
# Find all interfaces (start with I, followed by uppercase)
name_pattern: "^I[A-Z]"
# Find methods ending in "Async"
name_pattern: "Async$"
# Find all Get* or Set* methods
name_pattern: "^(Get|Set)[A-Z]"______________________________________________________________________
分页
列表操作返回分页结果。默认页面大小为 50个项目.
{
"items": [ ... ],
"total_count": 312,
"returned_count": 50,
"nextCursor": "eyJvZmZzZXQiOjUwLCJwYWdlU2l6ZSI6NTB9"
}要获取下一页,请传递 nextCursor 值为 cursor 下次通话中的争论。当 nextCursor 如果不存在,您已到达最后一页。
______________________________________________________________________
使用示例
工作流程:探索未知程序集
1. list_assemblies → find "UnityEngine.CoreModule"
2. get_assembly_info assembly=UnityEngine… → see namespaces
3. list_types assembly=… namespace=UnityEngine name_pattern="*Manager"
4. get_type_info assembly=… type=UnityEngine.NetworkManager
5. decompile_method … method=Awake使用正则表达式在所有程序集中搜索
{ "tool": "search_types", "arguments": { "query": "^I[A-Z].*Repository$" } }从内存中转储Unity游戏模块
{ "tool": "list_runtime_modules", "arguments": { "name_filter": "Assembly-CSharp*" } }
{ "tool": "dump_module_from_memory", "arguments": {
"module_name": "Assembly-CSharp.dll",
"output_path": "C:\\dump\\Assembly-CSharp_dump.dll"
}}设置断点并检查调用堆栈
{ "tool": "set_breakpoint", "arguments": {
"assembly_name": "Assembly-CSharp",
"type_full_name": "PlayerController",
"method_name": "TakeDamage"
}}
{ "tool": "get_call_stack" }将私有方法更改为公共方法并保存
{ "tool": "change_member_visibility", "arguments": {
"assembly_name": "MyAssembly",
"type_full_name": "MyNamespace.MyClass",
"member_kind": "method",
"member_name": "InternalHelper",
"new_visibility": "public"
}}
{ "tool": "save_assembly", "arguments": {
"assembly_name": "MyAssembly",
"output_path": "C:\\patched\\MyAssembly.dll"
}}在已知地址读取进程内存
{ "tool": "read_process_memory", "arguments": {
"address": "0x7FFE00001000",
"size": 256
}}打开一个受ConfusedEx保护的EXE文件并将其删除
1. scan_pe_strings assembly_name=MyApp → confirm it's packed (few readable strings)
2. unpack_from_memory exe_path=C:\MyApp.exe output_path=C:\MyApp_unpacked.exe
3. detect_obfuscator file_path=C:\MyApp_unpacked.exe → identify remaining obfuscation
4. deobfuscate_assembly file_path=C:\MyApp_unpacked.exe output_path=C:\MyApp_clean.dll修补反调试存根并保存干净的二进制文件
1. list_pinvoke_methods assembly=MyApp type=AntiDebugClass
→ finds "CheckRemoteDebuggerPresent" → kernel32.dll
2. patch_method_to_ret assembly=MyApp type=AntiDebugClass method=CheckRemoteDebuggerPresent
3. save_assembly assembly=MyApp output_path=C:\MyApp_patched.exe从磁盘或正在运行的进程加载程序集
// Load a .NET DLL from disk
{ "tool": "load_assembly", "arguments": {
"file_path": "C:\\dump\\MyApp_unpacked.dll"
}}
// Load a raw memory-layout dump (VAs instead of file offsets)
{ "tool": "load_assembly", "arguments": {
"file_path": "C:\\dump\\MyApp_memdump.bin",
"memory_layout": true
}}
// Dump from a running process and load directly into dnSpy
{ "tool": "load_assembly", "arguments": {
"pid": 1234,
"module_name": "MyPlugin.dll"
}}关闭阻止调试会话的对话框
{ "tool": "list_dialogs" }
// → [1] Title: "Error de depuración"
// Hwnd: 1A2B3C | Type: Win32 (#32770)
// Message: "No se puede continuar la operación."
// Buttons: Aceptar, Cancelar
{ "tool": "close_dialog", "arguments": { "hwnd": "1A2B3C", "button": "aceptar" } }
// → Clicked 'Aceptar' in dialog 'Error de depuración'.查找可疑类型的所有调用者和用法
{ "tool": "find_who_uses_type", "arguments": {
"assembly_name": "MyAssembly",
"type_full_name": "MyNamespace.ObfuscatedLicenseChecker"
}}
{ "tool": "find_who_writes_field", "arguments": {
"assembly_name": "MyAssembly",
"type_full_name": "MyNamespace.ObfuscatedLicenseChecker",
"field_name": "isValid"
}}______________________________________________________________________
建筑
设计原则
dnSpy.MCP.Server是dnSpy内部托管的扩展;它不会分叉或嵌入自定义dnSpy树- MCP功能在内部实现
dnSpy.MCP.Server无需修补dnSpy源 - 只有当HoLLy启发的功能可以作为稳定、可序列化、非UI MCP工具公开时,才会进行移植
- Echo集成仅限于可以为LLM干净序列化的稳定托管CFG子集
目录元数据
工具目录现在公开了旨在提高客户端可发现性的元数据:
categoryhidden_by_defaultis_legacypreferred_replacementnotes
tools/list 隐藏标记的工具 hidden_by_default 除非客户端明确请求完整目录。 list_tools 在band中镜像相同的行为并返回相同的目录元数据。
| 文件 | 责任 |
|---|---|
src/Communication/McpServer.cs | 流式HTTP侦听器和JSON-RPC调度 |
src/Application/McpTools.cs | 中央工具注册表、模式定义、路由 |
src/Application/AssemblyTools.cs | 程序集/类型列表、P/Invoke分析 |
src/Application/TypeTools.cs | 类型细节、方法、IL、BFS路径分析 |
src/Application/EditTools.cs | 元数据编辑、反编译、汇编保存、方法修补 |
src/Application/DebugTools.cs | 调试器状态、断点、步进、进程启动/连接 |
src/Application/DumpTools.cs | 运行时模块枚举、内存转储、PE部分工具 |
src/Application/MemoryInspectTools.cs | 从暂停的调试帧检查局部变量 |
src/Application/UsageFindingCommandTools.cs | 跨程序集IL使用情况分析(调用者、字段读/写) |
src/Application/CodeAnalysisHelpers.cs | 静态调用图、依赖链、死代码分析 |
src/Application/De4dotTools.cs | de4dot进程内集成;在所有版本中都可用 |
src/Application/SkillsTools.cs | 持久技能知识库(Markdown+JSON) %APPDATA%\dnSpy\dnSpy.MCPServer\skills\ |
src/Application/ScriptTools.cs | Roslyn C#脚本(run_script) |
src/Application/WindowTools.cs | Win32+WPF对话框枚举和解除 |
src/Presentation/TheExtension.cs | MEF入口点,服务器生命周期 |
src/Contracts/McpProtocol.cs | MCP DTO(工具信息、调用工具结果等) |
______________________________________________________________________
项目结构
dnSpy.MCP.Server/
├── dnSpy.MCP.Server.csproj # Multi-target: net48 + net10.0-windows
├── CHANGELOG.md
├── README.md
├── RELEASE_NOTES.md
└── src/
├── Application/
│ ├── AssemblyTools.cs # Assembly & type listing
│ ├── TypeTools.cs # Type internals + IL
│ ├── EditTools.cs # Metadata editing, method patching
│ ├── DebugTools.cs # Debugger integration
│ ├── DumpTools.cs # Memory dump & PE tools
│ ├── MemoryInspectTools.cs # Local variable inspection
│ ├── UsageFindingCommandTools.cs # IL usage analysis
│ ├── CodeAnalysisHelpers.cs # Call-graph & dependency analysis
│ ├── De4dotTools.cs # de4dot deobfuscation (all builds)
│ ├── SkillsTools.cs # Skills knowledge base (MD + JSON)
│ ├── ScriptTools.cs # Roslyn C# scripting
│ ├── WindowTools.cs # Win32/WPF dialog management
│ └── McpTools.cs # Tool registry & routing
├── Communication/
│ └── McpServer.cs # streamable HTTP server
├── Contracts/
│ └── McpProtocol.cs # DTO types
├── Helper/
│ └── McpLogger.cs
└── Presentation/
├── TheExtension.cs # MEF export / entry point
├── ToolbarCommands.cs
├── McpSettings.cs
└── McpSettingsPage.cs______________________________________________________________________
配置
mcp-config.json
A. mcp-config.json 文件在首次运行时自动创建在MCP服务器DLL旁边。编辑它以更改网络或de4dot设置-- 无需重建.
{
"host": "localhost",
"port": 3100,
"requireApiKey": false,
"apiKey": "",
"enableRunScript": false,
"de4dotExePath": "",
"de4dotSearchPaths": [],
"de4dotMaxSearchDepth": 6
}| 字段 | 默认值 | 描述 |
|---|---|---|
host | "localhost" | 绑定地址。使用 "0.0.0.0" 监听所有接口(用于从沙箱或VM进行远程调试)。见下文注释。 |
port | 3100 | 服务器监听的TCP端口 |
requireApiKey | false | 需要 X-API-Key / Authorization: Bearer 在每一个请求。 |
apiKey | "" | API密钥值。生成方式 openssl rand -hex 32. |
enableRunScript | false | 启用 run_script 工具(Roslyn C#脚本)。吃起来 true 仅在受信任的环境中。 |
de4dotExePath | "" | 绝对路径 de4dot.exe。留空以供自动发现。 |
de4dotSearchPaths | [] | 要搜索的额外目录 de4dot.exe (相对于此文件的绝对值或相对值)。 |
de4dotMaxSearchDepth | 6 | 自动发现兄弟时向上移动的目录级别 de4dot 存储库。 |
远程访问 --何时host是"0.0.0.0"或"*",HttpListener使用通配符绑定+。这需要一次性URL ACL保留(以管理员身份运行): ``netsh http add urlacl url=http://+:3100/ user=Everyone`然后将您的MCP客户端指向http://:3100/mcp`.
编辑后 mcp-config.json,呼叫 reload_mcp_config 或重新启动dnSpy以应用更改。
验证服务器是否正在运行
# Windows (PowerShell)
Invoke-RestMethod http://localhost:3100
# Windows (cmd)
curl http://localhost:3100
# Check port is listening
netstat -ano | findstr :3100______________________________________________________________________
故障排除
| 症状 | 可能原因 | 解决方案 | |
|---|---|---|---|
| 扩展未加载 | DLL不在dnSpy bin文件夹中 | 使用重建 -c Release;检查中的输出路径 .csproj | |
Connection refused 在端口3100上 | 服务器启动失败 | 检查dnSpy的日志窗口;端口3100可能正在使用中-- `netstat -ano \ | findstr :3100` |
工具返回 Unknown tool: … | 名称拼写错误或过时的客户端缓存 | 调用 list_tools 查看当前工具列表 | |
Assembly not found | 名称不匹配 | 呼叫 list_assemblies 并使用精确的 Name 显示的值 | |
Type not found | 错了 type_full_name | 使用 list_types 或 search_types 查找确切的全名 | |
Debugger is not active | 没有调试会话正在运行 | 通过启动调试 start_debugging 或dnSpy的 调试 菜单 | |
No paused process found | 进程仍在运行 | 调用 break_debugger 首先 | |
dump_module_from_memory 不返回字节 | 模块没有地址(纯动态) | 反射发射发出的某些内存模块无法转储 | |
倾倒 IsFileLayout: false | 内存布局转储 | 使用 dump_module_unpacked 相反,它会自动执行布局修复 | |
unpack_from_memory 由于反调试错误而失败 | 进程在EntryPoint之前自行终止 | 使用 patch_method_to_ret 要首先取消反调试方法,请保存修补的二进制文件,然后重试 | |
Failed to connect 添加MCP服务器时 | 传输类型或端点错误 | 使用可流式传输的HTTP端点 http://localhost:3100/mcp 并确保客户端配置为HTTP/可流式HTTP,而不是SSE | |
dump_cordbg_il 返回E_NOINTERFACE错误 | COM STA单元线程 | ICorDebugModule COM对象属于CorDebug引擎线程;来自另一STA的呼叫失败。这是一个已知的限制——使用 dump_module_unpacked 而是用于内存转储。 | |
Connection refused 来自VM/沙盒 | host 仍然 "localhost" | 设置 "host": "0.0.0.0" 在 mcp-config.json 然后跑 netsh http add urlacl url=http://+:3100/ user=Everyone 作为管理员。 | |
Access denied 当绑定到 0.0.0.0 | 缺少URL ACL | 运行 netsh http add urlacl url=http://+:3100/ user=Everyone 作为管理员(替换 3100 使用您配置的端口)。 | |
| 调试会话出现冻结/无响应 | 对话框阻塞UI线程 | 调用 list_dialogs 要检测打开的对话框,则 close_dialog 关闭它们并取消阻止会话。 |
______________________________________________________________________
贡献
- 分叉或分支
master - 在下实施您的更改
src/Application/或src/Communication/ - 在中注册新工具
McpTools.cs(GetAvailableTools+ExecuteTool开关) - 构建于
dotnet build … --nologo--必须生产 0个错误,0个警告 - 通过任何MCP客户端手动测试(
list_tools验证注册) - 提交一份PR,说明新工具及其参数
______________________________________________________________________
许可证
版权所有(C)2026@chichicaste。
根据GNU通用公共许可证第3版或您选择的任何更高版本进行许可。看 许可证 了解详情。
