没有源码也能救场:ILSpyCmd 命令行反编译的 8 个实战场景
先把结论放在前面:ILSpyCmd 是 ILSpy 项目自带的命令行反编译工具,安装后一条命令就能把 DLL 还原成可读的 C# 代码,还能生成可编译工程、PDB 调试文件,甚至交互式架构图。这篇文章不讲干巴巴的参数表,而是按 8 个真实场景展开,帮你快速判断"哪种处境该用哪个命令、坑在哪里"。
凌晨两点,你面前摆着一个没有源码的"黑盒"
几乎每个 .NET 开发者都遇到过这样的时刻:
- 接手一个遗留项目,源码早就失传,只剩一堆编译好的 DLL;
- 第三方库出了诡异 bug,文档语焉不详,只能自己扒代码;
- 同事离职时留下一个"能跑但没人看得懂"的模块,没人敢动它。
面对这些情况,过去我们只能打开图形界面的反编译软件,点半天菜单,再把结果一段段复制出来。而 ILSpyCmd 的思路完全不同——它把反编译变成了一条可在终端里随时调用、也能写进脚本的命令。这就像别人给你一把钥匙,你既能在门口试试,也能把它配进自动化的大门里。
第一次见面:一条命令装好,十秒跑通
安装过程简单到不需要思考,.NET 开发者用 CLI 工具即可:
dotnet tool install --global ilspycmd
装完就能用。最简单的反编译只需要指定一个程序集,结果直接打印到终端:
ilspycmd sample.dll
输出太多看不过来?加一个 -o 指定输出目录,它会把结果写进文件,而不是刷屏:
ilspycmd -o ./decompiled sample.dll
到这一步,你已经完成了"从二进制到源码"的第一步。接下来才是重头戏。
场景一:只想盯住一个类,别把整个程序集都倒出来
现实中的程序集动辄几千个类,全量反编译既慢又难读。当你只想搞懂某个类的实现时,用 -t 指定完全限定名:
ilspycmd -t "Your.Namespace.ClassName" sample.dll
如果连类都不需要,只想看某个方法的逻辑,用 -m 加上 XML 文档 ID 或元数据 token:
ilspycmd -m "M:System.String.Concat(System.String,System.String)" sample.dll
适用场景:定位某个具体 bug、对比两个版本间的行为差异。与其把整座图书馆搬回家,不如只借一本书。
场景二:C# 里看不出的细节,直接下潜到 IL
反编译出来的 C# 偶尔会"失真"——比如某些内联优化、异常的异常处理结构。这时候需要看到最底层的中间语言,也就是 IL:
ilspycmd --ilcode sample.dll
想连调试时命中的源码位置一起看,用 --il-sequence-points(它会自动带上 --ilcode)。
适用场景:排查栈溢出、验证编译器优化是否符合预期、研究某个库到底在底层做了什么。C# 是"翻译后的文章",IL 是"原文",有些真相只有原文里才有。
场景三:把"黑盒"变回一个能编译的工程
只读代码还不够,很多时候你希望直接改完重新编译。-p 参数会生成完整的工程文件(.csproj),每个类型一个源文件,就像从源码仓库里拉下来的一样:
ilspycmd -p -o ./decompiled sample.dll
注意:-p 必须搭配 -o,否则它会直接报错提醒你。项目体量大时,加上 --nested-directories 让目录按命名空间分层,结构更清爽:
ilspycmd --nested-directories -p -o ./decompiled sample.dll
如果程序集里带 WPF 界面,还能用 --decompile-baml 把二进制界面资源还原成 XAML 源码,而不是一堆字节流。适用场景:遗留系统重建、给老项目补测试、把第三方组件改造进自己的产品线。
场景四:调试第三方库之前,先补一张"调试地图"
没有 PDB 文件,断点根本进不了第三方库的源码。ILSpyCmd 可以反过来生成 portable PDB:
ilspycmd --generate-pdb sample.dll
反过来,如果你手里恰好有一份旧的 PDB,想让反编译结果里的变量名更接近原始代码,用 -usepdb 读取它:
ilspycmd -usepdb sample.pdb sample.dll
适用场景:调试第三方库、分析线上崩溃转储。有了这张"地图",调试器就能带你在陌生的代码里自由行走。
场景五:文档和代码脱节?让架构图自己"长"出来
写架构文档最痛苦的不是画图,而是图永远赶不上代码的变化。--generate-diagrammer 会基于程序集中的类型关系,生成一份交互式 HTML 架构图:
ilspycmd sample.dll --generate-diagrammer
默认输出在与程序集同级的 diagrammer 文件夹。类型太多时,用正则白名单和黑名单控制范围:
ilspycmd sample.dll --generate-diagrammer \
--generate-diagrammer-include "Your\.Models\..+" \
--generate-diagrammer-exclude ".+\+Metadata"
适用场景:代码审查前的架构梳理、新人入职指引、技术方案评审材料。让文档跟着发布流程自动更新,而不是靠某个人记得去维护。
场景六:资源文件里也藏着不少秘密
程序集里嵌入的资源往往被人忽视,但它们可能包含图标、配置、甚至完整的 XAML 界面。先列出清单:
ilspycmd --list-resources sample.dll
然后按名字提取单个资源。名字以 .baml 结尾的会自动还原成 XAML,其余按原始字节输出:
ilspycmd --resource sample.g.resources/mainwindow.baml -o ./decompiled sample.dll
适用场景:找回丢失的设计稿、确认某个配置是否被打进了包、审计程序集里到底塞了什么私货。
场景七:把反编译挂进 CI,文档从此自动更新
ILSpyCmd 的价值在自动化场景里最能放大。比如让每次发布后自动重新生成架构图,只需要在工程文件里加一个 MSBuild Target:
<Target Name="GenerateHtmlDiagrammer" AfterTargets="Publish">
<Exec Command="ilspycmd $(TargetPath) --generate-diagrammer --outputdir $(PublishDir)diagrammer" />
</Target>
在完全自动化的流水线里,建议加上 --disable-updatecheck 关掉更新检查,避免每次调用都去做网络请求拖慢流程。适用场景:持续集成、批量脚本处理、夜间文档任务。
场景八:给程序集做一次"全身体检"
反编译之外,ILSpyCmd 还能当诊断工具用。--dump-table 可以导出任意 ECMA-335 元数据表的原始内容,配合 --json 输出结构化结果:
ilspycmd --dump-table TypeDef --json sample.dll
想快速摸清程序集的组成,用 -l 列出各类实体(c=类、i=接口、s=结构体、d=委托、e=枚举);想拿到内部打包的子程序集,用 -d 一键解包。适用场景:安全审计、格式分析、写自动化测试前的摸底。多程序集可以一次全给,命令会自动逐个处理:
ilspycmd assembly1.dll assembly2.dll assembly3.exe
给新手的避坑提示
踩过的坑写下来,帮你少走弯路:
-p忘了带-o会直接报错,这不是 bug,是设计——它不想让你把工程文件洒得到处都是。- 反编译结果依赖引用程序集。缺依赖时用
-r指定引用目录;个别类型反编译失败,可以加--ignore-decompilation-errors让它"能出多少出多少",失败信息仍会列在 stderr。 - 架构图别贪大。几千个类型一次性全画,构建慢、文件大、浏览器也卡。先用 ILSpy 图形界面摸清结构,再用
--generate-diagrammer-include缩小范围,分领域生成多张图效果更好。 - 想要最新版本,直接跑
dotnet tool update --global ilspycmd;想从源码自己构建,clone 下来编译ICSharpCode.ILSpyCmd工程即可(仓库地址:git clone https://gitcode.com/gh_mirrors/il/ILSpy)。
写在最后
回到开头的那个凌晨:接盘老项目也好,排查第三方库也好,ILSpyCmd 的意义在于——它把"反编译"从一次性的手工操作,变成了一条随时可调用、可重复、可自动化的命令。完整的命令说明可以查阅项目内的 ICSharpCode.ILSpyCmd/README.md,所有参数的定义都在 ICSharpCode.ILSpyCmd/IlspyCmdProgram.cs 里,架构图生成器的实现则在 ICSharpCode.ILSpyX/MermaidDiagrammer/。
下次再遇到"没源码"的局面,先别慌。打开终端,敲下 ilspycmd,让代码自己开口说话。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



