5.7 KiB
5.7 KiB
.NET 混淆器脱混淆详解
主流 .NET 混淆器的识别、脱壳、anti-tamper 绕过。核心工具:de4dot(自动识别大多数壳)+ dnSpyEx(手动 patch)+ dnlib(脚本化)。
总决策表
| 混淆器 | de4dot type | 典型特征 | 自动脱壳 | 手动要点 |
|---|---|---|---|---|
| ConfuserEx 1.x/2.x | cfze |
anti-tamper、控制流变形、字符串加密、反调试 | ✅ 多数自动 | 新版需先 patch anti-tamper |
| ConfuserEx 3.x / 私改 | cfze |
同上 + 自定义 protector | ⚠️ 部分 | dump 运行时 / dnlib |
| SmartAssembly | sa |
字符串编码、资源压缩、方法调用隐藏 | ✅ 自动 | 资源解压 |
| Babel.NET | babel |
方法体加密、控制流、字符串 | ✅ 自动 | — |
| Eazfuscator.NET | eaz |
字符串/资源加密、表达式混淆 | ⚠️ 部分 | 字符串解密器 |
| .NET Reactor | reactor |
necrobit (代码段加密) + anti-tamper | ⚠️ 新版难 | dump + 重建 metadata |
| Themida .NET | — | 外壳 + 虚拟化 | ❌ de4dot 不行 | dump 内存,走 native 思路 |
| Agile.NET / CliSecure | agile |
方法体加密 | ✅ 自动 | — |
de4dot 标准用法
# 自动识别(多数情况够用)
de4dot target.exe -o target-clean.exe
# 显式指定 type(自动识别失败)
de4dot --type cfze target.exe -o target-clean.exe
# 先探测壳类型
de4dot --detect target.exe
# 批量
de4dot *.exe
# 只解字符串,不动控制流(最小干预)
de4dot --strtyp delegate --strtok METHOD_TOKEN target.exe
de4dot 的 --strtyp / strtok 模式:只解字符串解密器(指定解密方法 token),保留原控制流。适合"只想看明文字符串但不想碰 anti-tamper"的场景。
ConfuserEx(最常见)
特征识别
- 入口模块
<module>类带[MethodImpl(NoInlining)]的 anti-tamper 检查 - 大量
Dictionary<string, T>的字符串解密器调用 - 控制流平坦化(switch dispatch + state 变量)
- 资源里嵌
.cmp压缩资源 - dnSpyEx C# 视图:类名/方法名乱码(
\uXXXX或无意义字符),方法体里满屏int num = ...; switch(num)
脱壳流程
# 1. 标准脱壳
de4dot target.exe -o target-clean.exe
# 2. 如果 de4dot 报 "unknown" 或脱壳后打不开 → 新版/私改 ConfuserEx
# 先确认 anti-tamper:
dnSpyEx 打开 → 找 Module .cctor 或 Main 里的完整性校验
anti-tamper 绕过(新版 ConfuserEx 常见)
ConfuserEx 的 anti tamper 会在运行时校验方法体哈希,被改就崩。de4dot 通常能处理旧版,新版需手动:
方法 A — dnSpyEx 直接 patch 校验函数:
1. 找 anti-tamper 校验方法(通常在 <module> 的静态构造里调用)
2. IL 编辑:把校验方法体改成 ret(直接返回)
3. 保存 → 再喂给 de4dot
方法 B — 运行时 dump:
1. 用 MegaDumper / ExtremeDumper 跑起来 dump 内存中的 assembly
2. dump 出来的已经解密,再用 de4dot 清理残留
控制流还原后
de4dot 会把平坦化的 switch dispatch 还原成正常 if/while。如果没完全还原(看到残留 state 机),可再跑一次 de4dot 或手动跟 IL。
SmartAssembly
de4dot --type sa target.exe -o target-clean.exe
特征:
- 字符串用
SmartAssembly.Runtime.Strong系列编码 - 资源压缩(
{assembly}.Resources) - 方法调用隐藏(
ProcessCaller/ 间接 call)
de4dot 对 SmartAssembly 兼容性最好,基本一键搞定。
.NET Reactor(necrobit)
.NET Reactor 的 necrobit 把真实方法体加密存到资源,运行时解密注入,原方法体是空壳。de4dot 对老版本有效,新版本(4.x+)常失败。
当 de4dot 失败时:
1. 让程序跑起来(dotnet target.exe 或直接双击)
2. MegaDumper / ExtremeDumper dump 进程内存 → 导出解密后的 assembly
3. 用 de4dot 清理 dump 产物的残留混淆
4. 如果 metadata 损坏,用 dnlib 重建(见 common-workflow.md)
字符串解密器手动提取
混淆器把字符串加密,运行时调用解密方法还原。de4dot 多数能自动识别解密器,识别失败时手动:
1. dnSpyEx 找到解密方法(通常签名固定:static string Decrypt(int) 或 Decrypt(string, int))
- 特征:被大量调用、参数是数字常量、返回 string
2. 记下方法 token(如 0x06000012)
3. de4dot 指定解密器:
de4dot --strtyp delegate --strtok 0x06000012 target.exe -o target-clean.exe
如果连解密方法本身也被混淆(控制流平坦化),需要先脱控制流再定位解密器。
anti-debug 常见手法
| 手法 | 位置 | 绕过 |
|---|---|---|
Debugger.IsAttached 检查 |
任意方法 | IL 改 ldc.i4.0; ret 或 patch getter |
Debugger.IsLogging |
— | 同上 |
时间检测 (DateTime.Now 差值) |
方法入口 | patch 掉差值比较 |
CheckRemoteDebuggerPresent P/Invoke |
— | nop 掉调用 |
| 异常驱动控制流(try/catch 路径选择) | 主逻辑 | 不能简单 nop,要分析 catch 块真实路径 |
.NET anti-debug 比 native 简单 —— 多数是托管 API 调用,dnSpyEx IL 改一行即可。
de4dot 失败时的退路
- de4dot --detect 看识别结果,对照上表
- 运行时 dump(MegaDumper / ExtremeDumper / Process Hacker 导出模块)
- dnlib 脚本 手动解(见 common-workflow.md 的 dnlib 段)
- 动态优先:跑起来在解密点下断,直接看明文,不脱壳也能拿情报
社区参考:Washi 博客《misconceptions-about-dotnet》(IL 分析的常见误区)、看雪 .NET 逆向版块、Guided Hacking《Top 5 .NET RE Tools》。