ILSpy、dnSpyEx、dotPeek 怎么选:2026 年 .NET 反编译器对比
本页目录
结论先行(以 2026-10-14 为准): 想要免费、开源、能在 Windows、macOS、Linux 上原生运行,还带一个可脚本化命令行版本(ilspycmd)的反编译器,选 ILSpy。需要在 Windows 上对没有源码的 .NET 代码单步调试,选 dnSpyEx。已经在用 JetBrains 全家桶、平台是 Windows,想要一个还能充当符号服务器的免费反编译器,选 dotPeek。原版 dnSpy 仓库从 2020 年起就已归档,dnSpyEx 是仍在维护的延续版本。
本文面向需要选一款反编译器的 .NET 开发者:可能是想看懂自己的构建产物,可能是某个依赖没附源码,也可能是自己维护的代码崩在了一个说不清的地方。内容包括当前版本、平台和许可证,用我自己写的一个 DLL 做的反编译实测,自动化方式,以及 REA(morluto 的开源项目)如何记录反编译结果。
范围与公平性说明。 下文所有事实都来自各项目自己的发布页或官网,核对日期 2026-10-14。ILSpy 的 ilspycmd 11.1 我亲自运行过。dnSpyEx 和 dotPeek 是 Windows 程序,而本文是在 macOS 上写的,所以这两款我没有运行,相关描述均来自官方文档,并在文中注明出处。dnSpyEx 还能编辑并保存程序集,本文不涉及这部分:请只用于你自己的代码,或你有权检查的代码。
三款工具一览
| ILSpy | dnSpyEx | dotPeek | |
|---|---|---|---|
| 最新版本(2026-10-14 核对) | 11.1,2026-09-23 | 6.6.0,2026-06-20 | 2026.2.3.1,2026-10-01 |
| 许可证 | MIT(开源) | GPL-3.0(开源) | 免费,闭源 |
| 平台 | Windows、macOS、Linux | Windows(WPF) | Windows(提供 x64、x86、ARM64 下载) |
| 反编译为 C# | 支持 | 支持 | 支持 |
| 调试器 | 无 | 有 | 无(可为调试器提供符号) |
| 命令行 | ilspycmd(dotnet tool) |
dnSpy.Console 导出 |
产品页未提及 |
| 单文件包 | 支持 | 我参考的资料里未提及 | 我参考的资料里未提及 |
出处:ILSpy 11.1 与 11.0 发布说明、dnSpyEx 6.6.0 发布说明及其 README、JetBrains 的 dotPeek 页面。dotPeek 的版本号和平台来自 JetBrains 公开的发布信息接口,其中只有 Windows 下载。
2026 年各自的现状
ILSpy:已经跨平台
ILSpy 11.0(2026 年 8 月)把界面从 WPF 移植到了 Avalonia。项目原话是:移植之后,ILSpy 除了 Windows 也能在 Linux 和 Mac 上使用,WPF 前端被整个移除。11.1 的发布页提供 Windows x64 和 ARM64 安装包、Linux 的 zip 以及 .deb、.rpm 包,还有 macOS ARM64 的 zip。长期以来“Mac/Linux 上有没有 dnSpy 替代品”这个问题,在浏览和反编译层面终于有了答案;但它没有调试器。
11.0 还专门为 agent 使用场景改进了 ilspycmd:新增单成员反编译的 --member 和导出元数据表的 --dump-table。发布说明提到这个 dotnet tool 的下载量已超过每周 7 万次,并把增长归功于 Claude 等 agent。
Visual Studio 调试器自带的反编译功能就是基于 ILSpy 的。微软的 调试时反编译文档 写明,源码生成基于开源的 ILSpy 项目,从 Visual Studio 2019 16.5 起可用。
dnSpy 与 dnSpyEx
GitHub 上原版 dnSpy/dnSpy 仓库已归档,最后一次推送是 2020-12-20。dnSpyEx 自称是 dnSpy 的非官方延续,一个调试器兼 .NET 程序集编辑器。6.6.0 是它两年来第一个稳定版:升级到 .NET 10,新增依赖系统已装 .NET 10 运行时的 dnSpy-net 发行包,新增 String References 窗口,修复了 runtime-async 方法导致的反编译崩溃。
发布页上有两点会影响你的选择:
- 它是 Windows 上的 WPF 程序。6.6.0 能检测自己是否运行在 Linux 的 Wine 下,并关闭 WPF 硬件加速以提高兼容性。这只是兼容性调整,不是 Linux 或 macOS 版本。
- 维护者明确表示,不会有官方的 dnSpy AI 集成或 MCP 服务器。
大多数人选它是为了调试器。README 列出的能力包括:无需源码即可调试 .NET Framework、.NET 和 Unity 程序集,可以在任意程序集里下断点,有局部变量、监视、调用栈等窗口。
dotPeek
JetBrains 对 dotPeek 的描述是:一款基于 ReSharper 内置反编译器的免费独立工具。它能把程序集反编译为 C# 或 IL,能把反编译结果保存为 Visual Studio 项目,还能充当符号服务器,让 Visual Studio 调试器单步进入反编译出来的库代码。当前帮助文档标注为 dotPeek 2026.2。JetBrains Rider 有自己的集成反编译器,也能调试反编译出的外部代码;按 Rider 2026.2 的 外部代码调试 帮助,在 ARM64 的 macOS 上暂不支持单步进入外部方法。Rider 是单独授权的 IDE,我没有测试。
同一个 DLL 的反编译结果
为了看输出质量,我写了一个小库,里面有 record、LINQ 链、async 方法和 switch 表达式,用 .NET 10 SDK 以 Release 配置编译(Demo.dll,10,240 字节):
public record Order(int Id, string Customer, decimal Total, bool Paid);
public static class OrderReport
{
public static IEnumerable<string> TopCustomers(IEnumerable<Order> orders, int count) =>
orders.Where(o => o.Paid)
.GroupBy(o => o.Customer)
.OrderByDescending(g => g.Sum(o => o.Total))
.Take(count)
.Select(g => $"{g.Key}: {g.Sum(o => o.Total):0.00}");
public static async Task<int> CountLinesAsync(string path, CancellationToken ct = default)
{
using var reader = new StreamReader(path);
var lines = 0;
while (await reader.ReadLineAsync(ct) is not null)
lines++;
return lines;
}
public static string Describe(Order o) => o switch
{
{ Paid: false } => "unpaid",
{ Total: > 1000m } => "large",
_ => "normal",
};
}
ilspycmd -t Demo.Order Demo.dll 还原出的 record 只有一行,和源码完全一样:
public record Order(int Id, string Customer, decimal Total, bool Paid);
ilspycmd -t Demo.OrderReport Demo.dll 的输出如下(省略了 using 行):
public static IEnumerable<string> TopCustomers(IEnumerable<Order> orders, int count)
{
return from g in (from o in orders
where o.Paid
group o by o.Customer into g
orderby g.Sum((Order o) => o.Total) descending
select g).Take(count)
select $"{g.Key}: {g.Sum((Order o) => o.Total):0.00}";
}
public static async Task<int> CountLinesAsync(string path, CancellationToken ct = default(CancellationToken))
{
using StreamReader reader = new StreamReader(path);
int lines = 0;
while (await reader.ReadLineAsync(ct) != null)
{
lines++;
}
return lines;
}
public static string Describe(Order o)
{
if ((object)o != null)
{
if (!o.Paid)
{
return "unpaid";
}
if (o.Total > 1000m)
{
return "large";
}
}
return "normal";
}
可以看出:
- record 和 async 方法基本按原样还原,编译器生成的状态机被隐藏了。
- LINQ 链逻辑正确,但被改写成了查询语法,lambda 参数还标上了显式类型。
- switch 表达式 变成了嵌套的
if,外加一个(object)o != null判断。逻辑一样,写法不一样。不同反编译器、不同版本之间,模式匹配往往是差别最大的地方。
在 Apple M5 Pro 上,反编译这一个类型耗时 0.98 秒,峰值内存 136 MB。dnSpyEx 和 dotPeek 我没有运行,所以无法给出它们对同一个 DLL 的输出。如果你要自己对比,用同一份构建,先看这四种语法结构。
没有源码时调试自己的代码
最常见的正当场景:崩溃发生在你依赖的某个库里,或者发生在自己应用的某个旧版本里,而那个版本的 PDB 已经找不到了。
- 先找源码。 如果包启用了 Source Link,或者 PDB 还在,普通调试器就能显示真实源码。微软的反编译文档也把启用了 Source Link 的库和 NuGet 包指向这条路。
- Visual Studio 2022 17.7 及更高版本 在关闭“仅我的代码”后单步进入外部 .NET 代码时,或者在调用栈窗口里双击某一帧时,会自动反编译,并且可以在生成的代码里下断点。微软列出的限制包括:优化过的构建可能把断点绑到错误的行,局部变量名可能丢失,async 代码可能反编译不完整。
- dnSpyEx 以独立 Windows 工具的形式提供同样的“无源码调试”能力,覆盖 .NET Framework、.NET 和 Unity。
- dotPeek 可以充当符号服务器,让 Visual Studio 调试器拿到没有 PDB 的程序集的源码。
ILSpy 自己不能调试。ilspycmd -genpdb 可以从反编译代码生成可移植 PDB,供调试器加载;这条路我在本文中没有测试。
自动化:ilspycmd 与 REA
ilspycmd 以 .NET tool 形式安装:
dotnet tool install ilspycmd --version 11.1.0.9782 --tool-path ./tools
./tools/ilspycmd --version
# ilspycmd: 11.1.0.9782
# ICSharpCode.Decompiler: 11.1.0.9782
我用到的选项:-t <type> 反编译单个类型,-m <token 或 doc id> 反编译单个成员,-l c 列出类,-p -o <dir> 导出可编译项目,--bundle-entry 和 -d 处理单文件包(见 这个 EXE 是不是 .NET 写的),脚本里加 --disable-updatecheck。遇到 NativeAOT 程序或原生 apphost,它会报 PE file does not contain any managed metadata.
REA 6.4.0 自己不运行反编译器。它的 .NET 命令直接读取元数据和 IL,参见 用 REA 做 .NET 程序集静态分析。它和 ILSpy 只有两个接触点:
- 设置了
REA_ILSPY_CMD_PATH时,rea doctor会检查它(必须是绝对路径)。在我的环境里,它报告ilspycmd ... (ilspycmd: 11.1.0.9782)状态正常。 import-managed-reconstruction(MCP 工具名import_managed_reconstruction)导入反编译结果,并把它绑定到产出它的那个方法上。decompiler 的family字段可选ilspy、dnspy、dnlib、mono-cecil或other。
我在 Demo.dll 上完整跑了一遍:
rea inspect-managed-members /abs/path/Demo.dll --json > members.json
ilspycmd --disable-updatecheck -m 0x06000017 Demo.dll > describe.cs
# import.json = { static_members: <members.json>, decompiler: {name, version, family, options},
# methods: [{ token, signature_sha256, normalized_il_sha256, reconstruction: {kind, language, text} }] }
rea import-managed-reconstruction import.json --json
0x06000017 就是 Describe。签名和 IL 哈希取自成员证据里的 signature.raw_sha256 与 body.normalized_il_sha256。REA 接受了这次导入,校验块如下:
{ "matched_static_member": true, "exact_build_required": true,
"canonical_observation": false, "confidence_floor": "inference" }
附带的限制说明是 “Decompiler output is imported as reconstruction evidence and analyst inference; metadata and IL observations remain canonical.” 我把 IL 哈希改成全零之后,它拒绝导入:Reconstruction method lock 0x06000017 does not match a static managed member observation。这正是它的价值所在:反编译出的 C# 始终被标为推断,也不会被误挂到另一个构建上。
什么时候根本不需要反编译器
很多问题只看元数据就能回答:目标框架、引用、版本号、P/Invoke 导入,或者文件到底是不是 .NET。本站的 .NET 元数据与 IL 查看器 在浏览器里显示这些信息以及每个方法的 IL,文件不上传。它不生成 C#。框架和版本相关的问题见 查看 .NET DLL 的目标框架。
到底选哪个
- 在 macOS、Linux 上,或者用于 CI 和 agent 工作流: ILSpy 加
ilspycmd。 - 在 Windows 上,必须单步调试没有源码的代码: 有 Visual Studio 就先用它内置的反编译,否则用 dnSpyEx。
- 已经在用 ReSharper 或 Rider,平台是 Windows: dotPeek 很顺手,它的符号服务器也能帮到 Visual Studio 调试器。
- 文件是 NativeAOT: 三个都不行,里面没有 IL,请改用原生工具。
常见问题
dnSpy 还在维护吗? 原版仓库已归档。dnSpyEx 仍在维护,2026 年 6 月发布了 6.6.0。
Mac 上有 dnSpy 吗? dnSpyEx 项目没有。ILSpy 11 可以在 macOS 和 Linux 上原生运行用于反编译,但没有调试器。
这几款工具免费吗? ILSpy(MIT)和 dnSpyEx(GPL-3.0)是开源的;dotPeek 免费但闭源。重新分发任何内容之前,请先看清各自的许可证。
混淆过的程序集能看懂吗? 反编译器只能展示 IL 里有的东西,被改名的符号依然是乱名。REA 的导入限制说明也写明,混淆名称和重构过的控制流不能当作证据。请只分析你拥有或有权检查的代码,并参阅本站 免责声明。
下一步
- 先弄清手里是哪种构建:这个 EXE 是不是 .NET 写的?
- 在浏览器里查看元数据和 IL:.NET 元数据与 IL 查看器
- 用 REA 做 .NET 静态分析和成员对比:.NET 程序集静态分析
- 对比其他逆向工具:REA 与 GhidraMCP、ida-pro-mcp 等的对比