# ConfuserEx_Modified **Repository Path**: yjcf/confuser-ex_-modified ## Basic Information - **Project Name**: ConfuserEx_Modified - **Description**: 。。。。。。。。。。 - **Primary Language**: C# - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2026-07-03 - **Last Updated**: 2026-07-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # ConfuserEx CLI 魔改版 这是一个以 `Confuser.CLI` 为核心维护的 ConfuserEx 魔改仓库。 当前仓库的定位不是原版的 WPF 桌面混淆器,而是一个偏实战、偏命令行、偏自动化的加壳/混淆工具链,核心目标是: - 保留原始 ConfuserEx 的项目格式、保护框架和插件能力 - 加入本仓库额外实现的保护能力,例如 `vx.s8`、`wr.s4`、`dp.s9` - 强化命令行使用体验,支持直接对 `exe/dll` 进入自动模式 - 在 `WinForms/WPF` 这类容易“加壳后能启动但功能异常”的程序上,尽量做兼容性收敛 这份 README 按当前仓库代码整理,重点说明“现在实际有什么”和“现在实际怎么工作”,不保留无法从实现中直接证明的旧说明。 ## 仓库结构 当前仓库主要包含下面这些组件: - `Confuser.CLI` - 命令行入口 - 支持直接输入托管程序集或 `*.crproj` - 支持自动模式、自动依赖扫描、自动模板生成 - `Confuser.Core` - 核心引擎 - 项目格式 - 服务注册 - 保护/打包器/插件发现 - `Confuser.Protections` - 主要保护实现 - 包括本仓库新增的若干保护 - `Confuser.Renamer` - 重命名相关逻辑 - WinForms/WPF/BAML 相关兼容处理 - `Confuser.Runtime` - 运行时注入代码 - 目标框架为 `net20` - `Confuser.MSBuild.Tasks` - MSBuild 集成 - `installer` - CLI 安装器 - 安装脚本 - Chocolatey 打包模板 ## 适用范围 这里要区分两层: - 被保护程序支持什么 - 工具本身跑在什么环境上 ### 被保护程序 按当前仓库结构和运行时目标框架来看,本仓库主要面向传统 `.NET Framework` 程序: - 支持方向以 `.NET Framework 2.0/3.0/3.5/4.x` 为主 - `Confuser.Runtime` 是 `net20` - 自动模板明显围绕以下程序类型做了兼容: - `WinForms` - `WPF` - 传统托管 `exe` - 传统托管 `dll` 对于 `.NET Core` / `.NET 5+` / `.NET 6+` / `.NET 7+` / `.NET 8+` / `.NET 9+`: - 当前 README 不把它们写成“已正式支持” - 仓库里没有清晰的兼容承诺 - 如果你要保护这类程序集,建议先做最小样本验证,不要默认认为自动模式一定可用 ### 工具与组件目标框架 - `Confuser.CLI`:`net461` - `installer/Confuser.CLI.Setup`:`net461` - `Confuser.Core`:`net461` + `netstandard2.0` - `Confuser.Protections`:`net461` + `netstandard2.0` - `Confuser.DynCipher`:`net461` + `netstandard2.0` - `Confuser.Renamer`:`net461` + `netstandard2.0` - `Confuser.MSBuild.Tasks`:`net461` + `netstandard2.0` - `Confuser.Runtime`:`net20` ## 当前可见功能 ### 原有/常规能力 - 符号重命名 - WPF/BAML 相关处理 - 反调试 - 反内存转储 - 反篡改 - 控制流混淆 - 常量加密 - 资源保护 - 引用代理 - 反 ILDasm 标记 - 无效元数据干扰 - 类型扰乱 `typescramble` - 输出压缩 `compressor` - 插件与探测目录扩展 ### 本魔改版新增或强化的能力 - `vx.s8` - VM 保护 - 把方法体编译为自定义 VM 字节码并通过运行时解释执行 - `wr.s4` - 元数据保护 - 更准确地说是运行后的内存元数据扰动/加密,不是磁盘文件静态整体加密 - `dp.s9` - 注入后整理/加固阶段 - 会尝试把某些保护注入的辅助静态调用重新压回调用点,减少显眼特征 - `Confuser.CLI` 自动模式 - 直接输入托管 `exe/dll` - 自动识别程序集类型 - 自动生成保护模板 - 自动设置输出目录 - 自动加入本地托管依赖 ## 快速开始 ### 1. 直接拖文件或命令行输入程序集 如果输入的是托管程序集而不是 `*.crproj`,CLI 会自动进入自动模式: ```bat Confuser.CLI.exe DemoApp.exe Confuser.CLI.exe DemoLib.dll ``` 默认行为: - 自动识别程序集类型 - 自动输出到输入文件同目录下的 `Confused` - 默认使用 `aggressive` profile - 自动尝试加入本地托管依赖 ### 2. 显式使用自动模式 ```bat Confuser.CLI.exe --auto DemoApp.exe Confuser.CLI.exe --auto --profile=balanced DemoApp.exe Confuser.CLI.exe --auto -o protected-out DemoApp.exe ``` ### 3. 使用项目文件模式 如果你已经有 `*.crproj`: ```bat Confuser.CLI.exe DemoProject.crproj ``` 这仍然是完整支持的传统路径。 ### 4. 一次自动模式实际会发生什么 很多人看到 `Confuser.CLI.exe DemoApp.exe` 时,会以为 CLI 只是“自动帮你套一个固定模板”。 实际上当前自动模式大致会按下面的顺序工作: 1. 读取主程序集 2. 判断它属于 `Console`、`Library`、`WinForms`、`WPF` 还是 `Generic` 3. 统计主程序集的引用信息和方法数量 4. 决定是否自动扫描本地托管依赖 5. 按程序类型和 profile 生成对应的规则集 6. 决定是否启用 `compressor` 7. 对 `WinForms/WPF` 追加额外兼容规则 8. 如果是 `WinForms/WPF`,扫描主程序集中命名空间含 `.API` / `.Database` 的方法,并把它们加入 `vx.s8` 排除列表 9. 生成内存中的 `crproj` 10. 按生成后的项目执行实际保护 可以把自动模式理解成“先分析,再出模板,再执行”,而不是简单的“一键套壳”。 ### 5. 自动模式运行时你通常会看到什么 为了方便排错,理解 CLI 输出非常重要。一次正常的自动模式运行,通常会输出几类信息: - 输入文件与输出目录 - 自动识别到的程序集类型 - 启用的保护列表 - 跳过的保护或兼容性调整 - 依赖扫描结果 - 受保护模块数、方法数、部分保护的统计信息 你可以把这些输出理解为 3 个层次: - 第一层:CLI 决定“这次准备怎么保护” - 第二层:引擎开始“真正执行保护” - 第三层:引擎输出“哪些阶段成功、哪些地方跳过、最终输出到哪里” 如果你主要是排兼容问题,最值得看的不是“是否执行完成”,而是下面这些信息: - `Protections` - 说明本次到底开了哪些保护 - `Skipped protections` - 说明哪些保护因 profile 或兼容策略被关掉 - `Compatibility exclusions` - 说明自动模板主动为兼容性排除了哪些目标 - `Scanned vx.s8 exclusions` - 说明 `WinForms/WPF` 下额外扫出了多少方法级 `s8` 排除 - `Skipped packer` - 说明为什么这次没启用 `compressor` 判断方向时可以这样用: - 如果 `safe` 正常而 `balanced/aggressive` 异常,优先看 `vx.s8` - 如果只有 `aggressive` 异常,而 `balanced` 正常,优先看 `jt.s5/typescramble` - 如果 `WinForms/WPF` 下看到很多 `Scanned vx.s8 exclusions`,说明自动模式已经把一部分高风险方法主动避开了 - 如果你明明以为启用了某个保护,但输出里根本没有它,先看 profile 和程序集类型是否把它排掉了 ## CLI 参数 当前 `Confuser.CLI` 可见的主要参数如下: - `-n` / `--nopause` - 结束后不暂停 - `-o` / `--out=` - 指定输出目录 - `--probe=` - 增加探测目录 - `--plugin=` - 增加插件路径 - `--debug` - 生成调试符号 - `--auto` - 显式启用自动模式 - `--full` - 自动模式快捷开关 - 本质上等价于自动模式下固定为 `aggressive` - `--profile=safe|balanced|aggressive` - 指定自动模式强度 - `--save-project=` - 保存自动生成的 `crproj` - `--deps=true|false` - 自动模式下是否自动加入本地托管依赖 ### 参数补充说明 - 直接输入 `exe/dll` 且没有传入 `*.crproj` 时,CLI 会尝试进入隐式自动模式 - `--full` 本质上只是把自动模式 profile 固定为 `aggressive`,不是另一个独立模板 - `--save-project` 很适合排兼容问题,因为它能把自动生成结果固化成一个可手工修改的 `crproj` - `--deps=false` 适合那些依赖很多、但你不希望 CLI 自动把同目录 DLL 都拉进项目的场景 - `--probe` 适合依赖 DLL 不在主程序目录、但你又希望自动模式能找到这些 DLL 的场景 - `--plugin` 只负责追加插件路径,本身不会自动启用某个保护;是否生效还取决于项目/规则是否引用了对应保护 ### 哪些参数最值得先记住 如果你不想一开始记太多参数,最实用的其实只有下面几个: - `--profile` - 控制保护强度和兼容性风险 - `--save-project` - 控制后续能不能方便地手工排错 - `-o` - 控制输出目录,避免不同轮测试互相覆盖 - `--deps` - 控制是否把同目录依赖一起纳入 很多实际问题都不是“保护本身做不到”,而是: - 输出被覆盖了 - 你不知道这次到底用的什么 profile - 依赖 DLL 被自动带进来了 - 没保存 `crproj`,后续没法精细排 ### 常用示例 ```bat Confuser.CLI.exe DemoApp.exe Confuser.CLI.exe --profile=safe DemoApp.exe Confuser.CLI.exe --profile=balanced DemoApp.exe Confuser.CLI.exe --deps=false DemoApp.exe Confuser.CLI.exe --save-project=protected-out\auto.crproj DemoApp.exe Confuser.CLI.exe -o protected-out DemoApp.exe Confuser.CLI.exe --probe=plugins --plugin=MyPlugin.dll DemoApp.exe Confuser.CLI.exe DemoProject.crproj ``` ## 自动模式详解 自动模式是本仓库最重要的改动之一。它不是简单地“看到 `exe` 就全开保护”,而是会先分析主程序集,再按类型套用模板。 ### 自动识别的主程序集类型 - `Console` - `Library` - `WinForms` - `WPF` - `Generic` ### 自动模式默认做什么 - 识别主程序集类型 - 输出目录默认为输入目录下的 `Confused` - 自动扫描同目录和探测目录中的本地托管依赖 - 根据程序集类型生成保护模板 - 输出保护列表、跳过项、模板摘要、依赖摘要 ### 自动模式 profile 支持三档: - `safe` - 更保守 - 不开启 `vx.s8` - 不开启 `zk.anti_dbg/qm.s2/nf.s3/wr.s4/dp.s9` - `balanced` - 中间档 - 开启 `vx.s8` - 不开启 `jt.s5/typescramble` - `aggressive` - 更激进 - 开启 `vx.s8` - 对非 WinForms/WPF 目标还会额外开启 `jt.s5/typescramble` ### profile 对照表 | 维度 | `safe` | `balanced` | `aggressive` | | --- | --- | --- | --- | | 基础保护 | 开启 | 开启 | 开启 | | `zk.anti_dbg` | 关闭 | 开启 | 开启 | | `qm.s2` | 关闭 | 开启 | 开启 | | `nf.s3` | 关闭 | 开启 | 开启 | | `wr.s4` | 关闭 | 开启 | 开启 | | `dp.s9` | 关闭 | 开启 | 开启 | | `vx.s8` | 关闭 | 开启 | 开启 | | `jt.s5` | 关闭 | 关闭 | 仅非 WinForms/WPF 开启 | | `typescramble` | 关闭 | 关闭 | 仅非 WinForms/WPF 开启 | | `compressor` | 仅 `Console/Generic` | 仅 `Console/Generic` | 仅 `Console/Generic` | | 兼容性风险 | 最低 | 中等 | 最高 | | 推荐场景 | 先验证能否稳定运行 | 日常默认 | 对抗性更强、能接受额外验证成本 | ### 怎么选 profile 更稳 如果你不确定该选哪个,可以直接按软件类型判断: - 普通桌面软件,第一次加壳 - 先 `balanced` - 有本地授权、机器码、数据库、HTTP 服务 - 先 `safe` 或 `balanced` - 已经确认 `balanced` 正常,希望再抬强度 - 再测 `aggressive` - 控制台工具、后台任务、纯业务逻辑程序 - 可以更积极地直接试 `aggressive` - 对兼容性极度敏感的老软件 - 从 `safe` 起步最稳 一个很实用的经验是: - `safe` 是“先确认程序能不能跑” - `balanced` 是“日常最常用” - `aggressive` 是“要更强,但你愿意为兼容性付出测试成本” ### 自动模板的实际规则 基础启用: - `lh.shield` - `constants` - `ctrl flow` - `resources` - `ref proxy` - `rename` `balanced/aggressive` 额外启用: - `zk.anti_dbg` - `qm.s2` - `nf.s3` - `wr.s4` - `dp.s9` - `vx.s8` 只有 `aggressive` 且不是 `WinForms/WPF` 时,才额外启用: - `jt.s5` - `typescramble` 只有 `Console/Generic` 自动模板会启用 `compressor`。 以下类型默认不启用 `compressor`: - `Library` - `WinForms` - `WPF` WinForms/WPF 下: - `ref proxy` 会自动使用更保守的 `mild` - `rename` 会使用更保守的参数 - `s8` 会带兼容性排除规则,不是全量无差别开启 ### 按程序集类型理解自动模板 #### `Console` 特点: - 更适合吃到较完整的激进模板 - `aggressive` 下会额外启用 `jt.s5` 和 `typescramble` - 会启用 `compressor` 适合: - 命令行工具 - 后台任务 - 不依赖复杂 UI 生命周期的程序 不太适合直接无脑上最强的情况: - 程序大量反射调用自身类型 - 程序大量和第三方 native 组件交互 - 程序依赖非常脆弱的序列化或插件发现逻辑 #### `Generic` 特点: - 行为和 `Console` 很接近 - 也会启用 `compressor` - 更像“普通托管程序但识别不出明确 UI 类型”的兜底模板 适合: - 不明显属于 `Console/WinForms/WPF/Library` 的程序集 #### `Library` 特点: - 默认更保守 - 不启用 `compressor` - 倾向保持兼容性而不是追求打包效果 适合: - 被其它程序调用的 DLL - 对外公开接口较多的组件 使用 DLL 自动模式时尤其要注意: - 加壳后最终是被谁加载 - 加壳后的 DLL 是否仍要被反射发现 - 宿主程序是否能接受重命名、代理、控制流混淆等影响 对于被很多外部程序共同调用的公共库,更建议尽早导出 `crproj` 再做细调,而不是完全依赖默认自动模板。 #### `WinForms` 特点: - 保留 `vx.s8` - 但会自动排除 UI 敏感路径和属性访问器 - 不启用 `compressor` - `ref proxy` 会降为 `mild` - `aggressive` 下也不会启用 `jt.s5/typescramble` 适合: - 传统桌面管理软件 - 本地授权、本地数据库、内置 HTTP 服务较多的客户端 最常见的异常模式: - UI 能打开,但按钮后的业务逻辑异常 - API 服务显示未启动 - 授权状态显示错误 - 某些文本、状态栏、列表数据不对 遇到这类情况时,优先怀疑的通常不是 UI 框架本身,而是: - 属性访问器 - 授权/API/Database 链路 - 某段被 `s8` 虚拟化后的状态判断逻辑 #### `WPF` 特点: - 与 `WinForms` 的自动兼容策略基本一致 - 更强调 UI 生命周期兼容 - 对 `s8` 的排除更保守,而不是更激进 适合: - 传统 WPF 客户端 - 有绑定、命令、状态机、异步 UI 流程的桌面程序 WPF 尤其要关注: - 绑定链路 - 命令和状态机 - 异步回调 - `INotifyPropertyChanged` 相关状态读取 这也是为什么当前自动模式在 `WPF` 下同样会更谨慎地处理 `s8`。 ## `vx.s8` VM 保护说明 `vx.s8` 是本仓库的重点能力之一,但它的设计目标是: - 尽量提高覆盖率 - 尽量减少程序炸掉的概率 它不是“所有方法全部虚拟化”的保护。 ### `s8` 通常更适合保护什么 可以把它粗略理解成更偏向以下方法: - 普通业务逻辑方法 - 算法方法 - 校验方法 - 数据转换方法 - 普通静态方法和普通实例方法 ### `s8` 会主动避开的高风险方法 当前代码中,VM 兼容规则会主动移除或跳过以下目标: - 入口点 - `Main` / `WinMain` / `EntryPoint` - 带 `STAThread` 的方法 - `InitializeComponent` - `Dispose` - `WndProc` - `OnHandleCreated` - `OnHandleDestroyed` - `CreateHandle` - `DestroyHandle` - `OnLoad` - `CreateParams` - async/iterator 状态机 - 闭包、lambda、本地函数、编译器生成成员 - `WinForms/WPF` UI 类型上的高风险方法 - `WinForms/WPF` 下的属性访问器 `get_` / `set_` 这些规则背后的思路是: - 入口点和 `STAThread` 决定程序能不能正常起主线程,风险最高 - `InitializeComponent/Dispose/WndProc` 这类方法直接参与 UI 生命周期,最容易出现“程序能开但界面异常” - `MoveNext`、闭包、lambda、状态机如果被处理得太激进,最容易出现运行时行为偏差 - `get_/set_` 在 WinForms/WPF 里经常承担状态读取、数据绑定、UI 文本组装的职责,看起来简单,实际上非常敏感 - `Form/Control/Window/Application` 继承链上的方法,经常夹杂消息循环、句柄创建、线程上下文和设计器逻辑,属于兼容性雷区 ### `WinForms/WPF` 下的额外自动兼容规则 这是本仓库目前和普通 ConfuserEx 变体差异非常大的地方。 对于 `WinForms/WPF` 主程序集: - `s8` 仍然默认开启 - 但不会全量覆盖所有方法 - 自动模式会额外扫描主程序集中的高风险方法 当前自动扫描策略是: - 如果主程序集是 `WinForms/WPF` - 会扫描主程序集里命名空间含 `.API` 或 `.Database` 的方法 - 自动为这些方法生成 `vx.s8` 的方法级排除规则 这条规则的目的不是“削弱所有保护”,而是解决下面这种典型问题: - 程序能启动 - UI 不崩 - 但本地 HTTP 服务、授权校验、机器码读取、数据库配置读取、健康检查接口、加解密链路异常 换句话说,这套规则是为了避免: - `API 线程启动异常` - `授权校验误判` - `机器码或许可证读写链路异常` - `健康检查接口超时/403/状态显示错误` ### 这一套 `WinForms/WPF` 额外排除规则到底覆盖到什么程度 它目前更擅长覆盖这样的目标: - 主程序集自身就包含 API 层代码 - 主程序集自身就包含数据库配置或授权码处理代码 - 问题方法命名空间落在 `.API` 或 `.Database` - 问题是“运行后功能异常”,而不是“启动前直接崩溃” 它目前不保证覆盖这样的目标: - 授权逻辑在外部 DLL - 命名空间完全不带 `.API` / `.Database` - 问题来自第三方库、COM 组件、P/Invoke、驱动交互 - 问题属于更底层的线程竞争、反射、动态发射、运行时补丁 所以自动规则的定位是: - 优先解决高频兼容问题 - 减少手工排查成本 - 不是替代针对具体软件做方法级规则分析 ### 如果你的软件结构和当前扫描规则不一样怎么办 这时最稳的做法不是继续猜,而是转到“自动模板 + 手工微调”: - 先用 `--save-project` 保存生成结果 - 先验证是不是 `s8` 问题 - 再决定是按命名空间排、按类型排,还是按方法排 例如,如果你的软件把高风险逻辑放在这些命名空间: - `.Auth` - `.License` - `.Services` - `.Net` - `.Network` 那么当前自动规则可能不会自动命中,你就更适合自己在 `crproj` 上做定制。 ### 这意味着什么 - `s8` 不是全量关闭 - `s8` 也不是裸全开 - 当前策略是: - 尽量保留 `s8` - 只对 WinForms/WPF 下高风险、容易炸功能的方法做自动排除 ### 以后其它软件会不会自动排除类似问题 答案是:`会部分自动避开,但不是保证 100% 命中所有软件。` 现在能自动命中的前提通常是: - 目标是 `WinForms/WPF` - 关键问题方法在主程序集 - 相关逻辑在 `.API` 或 `.Database` 命名空间 如果目标程序的结构完全不同,例如命名空间叫: - `.Auth` - `.License` - `.Service` - `.Network` - `.Core` 或者关键逻辑放在外部依赖 DLL 里,那么当前自动规则不一定会自动避开。 ### 其它软件加壳时 `s8` 是不是全量开启 不是。 按当前自动逻辑: - `safe`:`s8` 不开启 - `balanced/aggressive`:`s8` 开启,但会带兼容性排除 - `WinForms/WPF`:排除更多,尤其是 UI 敏感方法、属性访问器,以及当前扫描到的 `API/Database` 方法 - `Console/Generic/Library`:也不是“所有方法全量进 `s8`”,仍然会跳过兼容性高风险目标 ## 手动项目模式与自动模式的关系 如果自动模式满足不了你的程序,可以这样做: 1. 先用自动模式跑一次 2. 用 `--save-project` 保存生成的项目 3. 在 `crproj` 里手工微调规则 示例: ```bat Confuser.CLI.exe --save-project=out\auto.crproj DemoApp.exe ``` 这通常是排兼容问题最稳的做法,因为你可以在自动模板基础上继续做: - 单保护排除 - 单类型排除 - 单方法排除 - 按命名空间排除 ### 一个更实用的工作流 如果你是第一次给某个软件加壳,推荐按下面顺序来,而不是一开始就手改很多规则: 1. 先直接跑自动模式默认值 2. 如果能正常运行,再决定是否继续上 `aggressive` 3. 如果出现“能启动但功能异常”,先切到 `safe` 4. 如果 `safe` 正常,而 `balanced/aggressive` 异常,优先怀疑 `vx.s8` 5. 保存 `crproj` 6. 从“整项保护排除”开始缩小范围 7. 再缩到类型级、命名空间级、最后到方法级 这样做的好处是: - 先拿到一个能跑的基线 - 再逐步找出真正有问题的保护 - 不会一上来就把所有高强度保护全关掉 ### 导出 `crproj` 后,建议怎么微调 如果你已经保存了自动生成的项目,建议按下面顺序调,而不是直接到处乱删保护: 1. 先只改一类保护 2. 每次只缩小一个维度 3. 先粗排,再细排 更具体一点: 1. 先验证是不是某个保护整项导致 2. 如果确认是,再缩到某个命名空间或某种方法模式 3. 再缩到具体类型 4. 最后才缩到具体方法 为什么这样做更稳: - 你能知道真正的根因属于哪一层 - 以后换一个版本时更容易复用规则 - 不会因为一次误判,把太多保护白白关掉 ### 什么叫“先粗排,再细排” 举个思路上的例子: - 第一步:先确认 `safe` 是否恢复正常 - 第二步:确认是不是 `vx.s8` - 第三步:确认是不是某个命名空间下的方法 - 第四步:确认是不是某个类型 - 第五步:确认是不是某个 getter、某个启动方法、某个校验方法 这种方式虽然看起来慢一点,但它能让你最终得到: - 更稳定的规则 - 更小的排除范围 - 更高的整体保护强度 ## 安全性说明 这是实际使用中经常会问到的问题。 ### 当前策略会不会“变得不安全” 会降低一部分方法的 VM 覆盖率,但不等于“完全不安全”。 原因是: - 被 `s8` 排除的方法仍然还会吃到其他保护 - 当前自动模板默认还保留了: - `rename` - `ctrl flow` - `constants` - `resources` - `ref proxy` - `zk.anti_dbg` - `qm.s2` - `nf.s3` - `wr.s4` - `dp.s9` 所以这次修复后的本质是: - 不是“把授权相关逻辑裸奔” - 而是“不给这一段逻辑上 `s8`,但其它保护仍然保留” ### 哪些东西更应该被理解成“安全体系”,而不是“某一个保护项” 很多人会自然地把“开了 `s8`”理解成“安全”,把“某段逻辑排除 `s8`”理解成“不安全”。 更准确的理解应该是: - 安全性来自多层叠加 - VM 只是其中一层 - 授权体系本身的设计,往往比单个保护项更重要 真正影响整体安全的,通常是下面这些东西的组合: - 授权是否只在本地校验 - 是否使用签名而不是仅仅可逆加密 - 是否有服务端参与最终裁决 - 关键校验是否分散而不是集中在一个函数 - 本地失败信息是否暴露过多细节 - 混淆和虚拟化是否只是“锦上添花”,而不是唯一防线 ### 更准确地理解“安全性下降了多少” 可以这样理解: - 如果一个方法被 `s8` 排除,它失去的是“VM 这一层” - 它不等于失去全部保护 - 它仍然可能被重命名、控制流混淆、常量加密、资源保护、代理保护、反调试等机制覆盖 所以真实变化更接近: - 从“多层保护”变成“少一层最重的保护” - 而不是从“受保护”变成“完全裸露” 但也要明确: - 如果你的授权体系完全在本地 - 并且攻击者愿意针对性逆向 - 那么只靠混淆和虚拟化,本来就不是绝对安全方案 ### 为什么不建议把授权/API/数据库链路强行全进 `s8` 因为本地授权、机器码、HTTP 服务、数据库配置这类链路,对运行时行为非常敏感。 如果强行全开 `s8`,常见后果反而是: - 授权码误判失效 - API 服务线程不工作 - 健康检查超时 - UI 状态显示错误 - 程序表面启动了,但关键功能坏了 从实战上看: - 一个“功能正常但局部少一点 VM”的程序 - 往往比“所有 VM 都开了但授权/API 全坏”的程序更可用 ### 需要更强授权安全时应该怎么做 如果你真正关心的是授权防破解,不建议只依赖本地混淆和虚拟化。 更合理的做法是组合: - 服务端签发授权 - 非对称签名校验 - 机器码绑定 - 到期时间绑定 - 版本绑定 - 失败原因模糊化 - 本地逻辑做多层校验,但最终裁决尽量下放服务端 混淆/虚拟化做的是“提高逆向成本”,不是替代授权体系本身。 ## 构建 ### 直接编译 CLI ```bat dotnet build .\Confuser.CLI\Confuser.CLI.csproj -c Debug dotnet build .\Confuser.CLI\Confuser.CLI.csproj -c Release ``` 编译输出通常在: - `Confuser.CLI\bin\Debug\net461\Confuser.CLI.exe` - `Confuser.CLI\bin\Release\net461\Confuser.CLI.exe` ### 构建整个解决方案 ```bat dotnet build .\Confuser2.sln -c Debug dotnet build .\Confuser2.sln -c Release ``` ## 安装与打包 仓库里保留了完整的 CLI 打包与安装链路: - `installer\Confuser.CLI.Setup` - 安装器项目 - `installer\build_installer.ps1` - 构建安装器 - `installer\install.ps1` - 安装到 `Program Files\ConfuserEx` - `installer\chocolatey-packages` - Chocolatey 包模板 - `installer\stage\payload` - 安装器载荷内容 如果你只是本地测试,通常不需要跑安装器,直接使用 `bin\Debug\net461\Confuser.CLI.exe` 即可。 ## 常见使用建议 ### 适合优先尝试自动模式的场景 - 普通 WinForms 管理软件 - 普通 WPF 桌面软件 - 传统 .NET Framework Console 程序 - 单可执行文件或依赖关系简单的程序集 ### 适合优先保存项目文件再调规则的场景 - 本地授权码校验很重 - 程序内置 HTTP 服务 - 依赖数据库配置、机器码、加解密、健康检查 - 业务逻辑分散在多个 DLL - 程序对线程、反射、动态调用非常敏感 ### 推荐排错路径 1. 先用自动模式跑 2. 如果异常,换 `safe` 看是否恢复 3. 如果 `safe` 正常、`balanced/aggressive` 异常,优先怀疑 `s8` 4. 用 `--save-project` 导出 `crproj` 5. 在项目文件里做保护项排除或方法级排除 ### 现象与优先怀疑对象 如果你是在排真实软件,下面这张“症状到方向”的映射会很实用: | 现象 | 优先怀疑 | | --- | --- | | 程序双击直接打不开 | 入口点、打包器、反篡改、运行时加载问题 | | 程序能开但窗口异常 | UI 生命周期、`InitializeComponent`、`WndProc`、重命名兼容 | | 程序能开但某个业务功能坏了 | `vx.s8`、控制流、代理、局部业务链路 | | 授权码读取失败 | `vx.s8`、本地加解密、机器码、配置读取 | | API 服务状态异常 | `vx.s8`、线程启动、状态 getter、授权前置检查 | | 只有 `aggressive` 异常 | `jt.s5`、`typescramble`、更激进的命名/代理组合 | | `safe` 也异常 | 基础兼容问题、依赖缺失、程序集本身结构特殊 | ## 常见问题 ### 1. 为什么同一个程序 `safe` 正常,但 `balanced/aggressive` 异常 最常见原因是: - `balanced/aggressive` 会开启 `vx.s8` - 非 UI 程序在 `aggressive` 下还可能额外开启 `jt.s5/typescramble` 因此这类现象通常说明: - 不是基础重命名或控制流出了问题 - 而是更强保护打到了程序的兼容性边界 继续往下判断时,可以再细分: - `balanced` 就坏 - 优先看 `vx.s8` - `balanced` 正常,但 `aggressive` 坏 - 优先看 `jt.s5/typescramble` ### 2. 为什么程序启动了,但某个功能坏了 这是桌面程序里最常见的现象之一。 典型表现: - 窗口能打开 - 按钮能点 - 但 API 状态不对 - 授权码读取失败 - 数据库配置读不到 - 某些页面或某些按钮逻辑不工作 这通常说明: - UI 框架本身没彻底炸 - 但某段业务链路被较强保护影响了运行时行为 这个时候最忌讳的做法是: - 直接把所有强保护全部关掉 更推荐的是: - 先确认是不是 `safe/balanced/aggressive` 的差异 - 再缩到具体保护 - 最后再缩到具体方法或命名空间 ### 3. 为什么 `WinForms/WPF` 不直接把 `s8` 全关掉 因为很多普通业务方法其实是适合吃 `s8` 的。 如果把 `s8` 在 `WinForms/WPF` 里整项关闭,会出现两个问题: - 保护强度下降过大 - 很多本来可以稳定虚拟化的方法也白白失去保护 所以当前策略不是“全关”,而是“自动绕开最容易炸的部分”。 ### 4. 为什么不把 `API/Database` 全部写成固定黑名单 因为不同软件结构差别很大: - 有的软件叫 `.API` - 有的软件叫 `.Auth` - 有的软件叫 `.Services` - 有的软件关键逻辑在外部 DLL 如果把规则写得过死: - 有些软件还是命不中 - 有些软件又会被过度排除 当前实现属于一个更实用的折中版本: - 先覆盖高频命名风格 - 后续再按真实样本继续扩展 ### 5. 我应该默认用哪个 profile 比较稳妥的建议: - 第一次上手新软件:先 `balanced` - 明显是高敏感桌面软件:先 `safe` 验证功能,再升到 `balanced` - 对抗性要求更高、且你愿意花时间验证:再考虑 `aggressive` ### 6. 我什么时候应该导出 `crproj` 建议在下面这些场景直接导出: - 这是你第一次保护该软件 - 软件有本地授权、机器码、数据库、HTTP 服务 - 软件依赖多个业务 DLL - 你预计后续要长期维护这个保护配置 ### 7. 为什么我觉得自动模式已经很强了,还要保留 `crproj` 因为自动模式解决的是“高频场景”和“第一轮可用性”,不是“替你完成所有定制”。 `crproj` 的价值在于: - 你可以把一次调试结果固化下来 - 你可以跨版本复用规则 - 你可以把兼容性策略做成团队内部标准模板 - 你不用每次都重新猜哪个保护引起了问题 对于长期维护的软件,这往往比“一次性自动跑成功”更重要。 ## 已知边界 - 当前仓库主维护目标是 CLI,不是桌面混淆 GUI - `vx.s8` 存在明确兼容性排除规则,属于“有选择地覆盖” - `wr.s4` 更偏向运行时内存层面的防护,不应理解为磁盘 PE 文件整体静态元数据加密 - 对 `.NET Core/.NET 5+` 没有在 README 中做正式支持承诺 - 自动模式下的 `s8` 兼容规则已经明显增强,但仍不保证覆盖所有业务风格和命名结构 ## 问题反馈 请到 [Gitee Issues][issues] 页面提交问题。 反馈时建议尽量带上: - 原始程序集类型 - 使用的命令行 - 是否 `safe/balanced/aggressive` - 是否 `WinForms/WPF` - 是启动即崩、功能异常、授权异常,还是 API 状态异常 - 如果可以,附上保存出来的 `crproj` ## 致谢 感谢 **[0x4d]** 的原始工作与知识积累。 [0x4d]: https://github.com/0x4d [issues]: https://gitee.com/h5hhh/confuser-ex_-modified/issues