关于 analyzing-dotnet-assemblies
面向恶意软件分析人员及无源码 Windows 应用审查者的 .NET 程序集分析安全技能。内容涵盖反编译、混淆与加壳、运行时转储,以及恶意软件行为检查。
主要功能
- 01识别托管程序集和发布模式
- 02将程序集反编译为可读代码
- 03检测并处理常见混淆器
- 04从内存转储托管模块
- 05使用 dnSpyEx 调试和修补程序集
适用场景
- 01无源码审查 Windows 应用或服务
- 02分析 .NET 恶意软件加载器及其后续阶段
- 03恢复内存中 PowerShell 或 C# 加载器的逻辑
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ trilwu/ secskills --skill analyzing-dotnet-assemblies安装后在 Claude Code 中输入/analyzing-dotnet-assemblies确认已加载。
详细介绍
分析 .NET 程序集
.NET 会编译为带有完整元数据的 IL,因此未混淆的程序集可以反编译为接近原始代码的 C#。所以有趣的问题不是“如何读取它”,而是“有什么在阻碍”:加壳器、混淆器、运行时加载器,或是将托管代码隐藏在本机宿主中的发布模式。
适用场景
file报告文件为 PE,且二进制文件包含 CLR 标头或mscoree.dll- ILSpy 或 dnSpy 可以打开程序集,但名称已被篡改或方法体为空
- 分析 .NET 恶意软件、加载器或红队工具
- 在没有源代码的情况下审查 Windows 桌面应用或服务应用
- 从 PowerShell 或 C# 内存加载器中恢复逻辑
不适用场景
- Unity IL2CPP — 使用
reversing-unity-il2cpp;C# 已编译为本机代码 - Xamarin/MAUI 移动应用 — 使用
reversing-xamarin-maui提取容器,然后返回此处处理 DLL - 疑似恶意软件,尚未隔离时 — 首先使用
analyzing-malware - Go 或 Rust 二进制文件 — 使用对应的技能
确认它是托管代码
# Linux
file target.exe # "Mono/.Net assembly"
rg -a -o 'BSJB|mscoree\.dll|System\.Private\.CoreLib' target.exe | head
# Windows
dotnet-tool: ildasm /text target.exe | head
# CLR header presence in the optional header data directory 14 is the real test
| 发现的内容 | 发布模式 | 处理方法 |
|---|---|---|
托管 PE,引用了 mscorlib/System.Private.CoreLib | 依赖框架 | 直接反编译 |
| 包含嵌入式托管捆绑包的本机 PE | 单文件发布 | 先提取捆绑包 |
| 没有任何 IL 元数据的本机 PE | NativeAOT | 不属于 .NET 逆向工程 — 使用 analyzing-binaries |
没有入口点的 .dll | 库 | 反编译;在其他位置查找调用方 |
# Single-file publish: the managed assemblies are appended as a bundle
# Extract with a bundle extractor, or carve on the manifest header
ilspycmd --list-bundle target.exe 2>/dev/null || binwalk -Me target.exe
反编译
ilspycmd target.dll -o ./decompiled -p # -p writes a project structure
# GUI: dnSpyEx (maintained fork), ILSpy, dotPeek
# dnSpyEx also debugs and edits assemblies, which is why it is the default choice
rg -n 'https?://|ConnectionString|ApiKey|password|Convert\.FromBase64String' ./decompiled | head -40
按以下顺序阅读:入口点、以产品命名的类型,然后是引用网络、加密或进程 API 的内容。除非要跟踪特定闭包,否则跳过生成的类型(<>c__DisplayClass、<Module>)。
在处理混淆前先识别混淆器
明确混淆工具后,反混淆成本很低;不明确时,成本就很高。
detect-it-easy target.exe # or DIE's CLI: diec
# Look for: ConfuserEx, .NET Reactor, SmartAssembly, Eazfuscator, Babel,
# Dotfuscator, Agile.NET, Obfuscar
rg -a -o 'ConfuserEx|Reactor|SmartAssembly|Eazfuscator|Babel|DotNetPatcher' target.exe
# de4dot handles the classic obfuscators automatically
de4dot target.exe -o cleaned.exe
de4dot -p cr target.exe # force a specific profile when detection fails
# ConfuserEx specifically: use a maintained unpacker fork, since de4dot's
# built-in support predates later ConfuserEx versions
各混淆层的表现及处理方法:
| 混淆层 | 表现 | 处理方法 |
|---|---|---|
| 名称篡改 | Class1.method_3、Unicode/不可见名称 | 仅影响外观 — 阅读时重命名;de4dot 可还原部分名称 |
| 字符串加密 | 到处都是 <Module>.Decrypt(12345) | 运行解密器:使用 de4dot,或动态调用该方法 |
| 控制流扁平化 | 针对状态变量的大型 switch | 使用 de4dot 的 CFG 清理功能,或动态读取 |
| 代理/委托调用 | 每次调用都通过辅助函数 | 使用 de4dot 进行去虚拟化 |
| 防篡改/反调试 | 在 dnSpy 调试器下运行失败 | 修补检查,或在解密后转储 |
| 虚拟化(Agile.NET、KoiVM) | 完全无法识别 IL | 使用去虚拟化工具(KoiVM 可用 OldRod)或动态分析 |
| 本机桩代码封装 IL | 运行时解密托管代码 | 从内存转储 — 这是可靠的方法 |
**从内存转储是通用的脱困方法。**无论使用什么加壳器,CLR 最终都必须持有真实 IL 才能执行。让它加载,然后转储:
# MegaDumper / ExtremeDumper / pe-sieve — dump loaded managed modules from a
# running process, then decompile the dump
pe-sieve /pid <pid> /dmode 3
这与加壳本机恶意软件的“让它自行解包”方法相同;运行任何可疑内容前,请参阅 analyzing-malware 了解隔离措施。
调试和修补
# dnSpyEx: set breakpoints in decompiled C#, inspect locals, edit method bodies,
# and save the modified assembly. This is unusually powerful — you can change a
# license check or a validation result and immediately re-run.
修补工作流:在 dnSpyEx 中编辑 IL 或反编译后的 C#,保存程序集,然后重新运行。保存时强名称签名会失效 — 可以移除强名称要求;如果应用会自行验证哈希,则挂钩该检查。对于应用本身会验证的签名程序集,修补通常不是合适的工具;应改为在运行时挂钩。
.NET 恶意软件笔记
.NET 被广泛用于加载器和常见 RAT,其特征很鲜明:
Assembly.Load(byte[])— 在内存中解密的第二阶段。找到解密例程,离线运行并分析生成的程序集。这是最常见的 .NET 恶意软件模式。Activator.CreateInstance加反射,用于隐藏真实的调用图。AmsiScanBuffer/EtwEventWrite补丁 — 搜索字节模式,或搜索此前调用的GetProcAddress。- P/Invoke 声明(
[DllImport])揭示原生能力:VirtualAlloc、CreateRemoteThread、SetWindowsHookEx。 - 资源和卫星程序集中可能存放加密载荷 — 务必枚举资源节。
rg -n 'DllImport|Assembly\.Load|CreateInstance|FromBase64String|RijndaelManaged|AmsiScanBuffer' ./decompiled | head -30
ilspycmd --list-resources target.dll
提取出的第二阶段交由此技能处理;能力和 IOC 输出交给 analyzing-malware,检测内容交给 engineering-detections。
应当驳斥的理由
- “名称毫无意义,混淆太严重了。” 名称混淆是最薄弱的一层。结构、字符串和 P/Invoke 都完好无损。
- “de4dot 失败了,所以无法反混淆。” 找出混淆器并使用对应的专用解包器,或者从内存中转储。
- “这是原生 EXE,所以不是 .NET。” 检查是否使用了单文件发布,以及是否存在包装托管代码的原生存根。
- “字符串已加密。” 解密器就在程序集里。调用它。
- “我反编译了加载器,那就是恶意软件。” 加载器只是第一阶段。找到
Assembly.Load,并还原它加载的内容。 - “我会手动阅读扁平化的控制流。” 运行清理工具,或者在 dnSpyEx 中调试并观察实际执行路径。
参考资料
analyzing-malware— 遏制、能力模型和 IOCanalyzing-binaries— NativeAOT 和原生存根分析reversing-unity-il2cpp、reversing-xamarin-maui— 其他 .NET 容器engineering-detections— 将还原出的行为转化为规则- dnSpyEx、ILSpy/ilspycmd、de4dot、Detect It Easy、pe-sieve、OldRod
评论
支持 Markdown