01 · 流水线架构与保护引擎总览
目录
- [为什么要保护 .NET 程序?](#为什么要保护 .NET 程序?)
- 保护引擎的核心设计理念
- 三阶段流水线架构
- 保护步骤注册与执行顺序
- ProtectOptions:一个配置控制所有层
- ProtectionContext:步骤间的共享数据总线
- ProtectionSession:多模块协同保护
- AssemblyProtectorService:顶层编排器
- [从命令行到 GUI:三种使用入口](#从命令行到 GUI:三种使用入口)
- 结语
1. 为什么要保护 .NET 程序?
.NET 程序编译为 IL(中间语言),附带完整的元数据------类名、方法签名、字段类型一览无余。使用 dnSpy、ILSpy 等工具可以几乎完整还原源代码。对于商业软件,这意味着核心算法暴露、授权验证逻辑可被绕过、通信协议和 API 密钥泄露。
我们的保护引擎提供了 全链条防护------从字符串加密到方法体加密、从反调试到代码虚拟化,层层设防。
2. 保护引擎的核心设计理念
2.1 无独立 DLL 依赖
所有运行时助手类型在保护时通过 InjectHelper 深度克隆到目标程序集中。用户分发的受保护程序是完全自包含的,没有任何额外的 .dll 文件。
2.2 共享上下文
多个保护步骤共享 ProtectionContext,其中包含模块引用、随机数生成器、运行时类型服务、注入的用户类型等。这确保了步骤之间可以无缝协作。
2.3 基于 dnlib
使用 dnlib 库读写 .NET 程序集。dnlib 是 Mono.Cecil 的替代品,在 ConfuserEx 等知名保护工具中广泛使用。
3. 三阶段流水线架构
每个保护步骤实现 IProtectionStep 接口,包含三个可选方法:
csharp
public interface IProtectionStep
{
string Name { get; } // 步骤名称
int Order { get; } // 执行顺序(数值越小越先执行)
bool IsEnabled(ProtectOptions options); // 是否启用
void Inject(ProtectionContext context) { } // 阶段1:注入运行时类型
void Execute(ProtectionContext context); // 阶段2:执行 IL 修改
void ConfigureWriter(ProtectionContext context, // 阶段3:配置写入器
ModuleWriterOptions options) { }
}
三阶段执行流程
csharp
// 阶段1:Inject(注入运行时)--- 所有启用步骤先集体执行
foreach (var ctx in contexts)
{
foreach (var step in steps.Where(s => s.IsEnabled(ctx.Options)))
step.Inject(ctx);
}
// 阶段2:Execute(IL 修改)--- 按 Order 从小到大顺序执行
foreach (var step in steps.Where(s => s.IsEnabled(ctx.Options))
.OrderBy(s => s.Order))
{
if (step.Order >= 90) break; // StrongName 跳过 Execute
foreach (var ctx in contexts)
step.Execute(ctx);
}
// 阶段3:ConfigureWriter(写入器配置)
foreach (var ctx in contexts)
{
foreach (var step in steps.Where(s => s.IsEnabled(ctx.Options)))
step.ConfigureWriter(ctx, writerOptions);
}
为什么要分三个阶段? 因为 Order 靠前的步骤注入的运行时类型,可以被 Order 靠后的步骤保护。例如授权验证器(Order=5 注入)在后续的字符串加密(Order=10)和防篡改(Order=60)中会被自动保护。
4. 保护步骤注册与执行顺序
ProtectionPipeline 构造函数中注册了全部 10 个保护步骤:
csharp
public ProtectionPipeline()
{
_steps = new List<IProtectionStep>
{
new LicenseInjectionStep(), // Order=5: 授权注入(最先执行)
new StringEncryptionStep(), // Order=10: 字符串加密
new ObfuscationStep(), // Order=20: 符号混淆
new LogicObfuscationStep(), // Order=30: 控制流混淆
new VirtualizationStep(), // Order=35: 代码虚拟化
new MethodEncryptionStep(), // Order=50: 方法体加密
new JitHookStep(), // Order=55: JIT Hook
new AntiTamperStep(), // Order=60: 防篡改校验
new AdditionalProtectionsStep(), // Order=40: 附加保护(反调试/反转储/资源加密/元数据混淆)
new StrongNameStep(), // Order=90 写入阶段: 强名称签名
};
}
每个步骤通过 IsEnabled(opts) 决定是否启用:
csharp
// 字符串加密:由 EncryptStrings 开关控制
public bool IsEnabled(ProtectOptions options) => options.EncryptStrings;
// 混淆:由 Obfuscate 开关控制
public bool IsEnabled(ProtectOptions options) => options.Obfuscate;
5. ProtectOptions:一个配置控制所有层
ProtectOptions 是所有保护步骤的控制中心:
csharp
public class ProtectOptions
{
// === 字符串加密 ===
public bool EncryptStrings { get; set; } // 总开关
public string StringMode { get; set; } = "DelegateProxy"; // 编码模式
// === 混淆 ===
public bool Obfuscate { get; set; }
public string RenameMode { get; set; } = "Unicode";
public bool RenameNamespaces { get; set; }
public bool RenameTypes { get; set; }
public bool RenameMethods { get; set; }
public bool RenameProperties { get; set; }
public bool RenameFields { get; set; }
public bool RenameParameters { get; set; }
public bool RenamePublic { get; set; }
public bool RenamePrivate { get; set; }
public bool FlattenNamespaces { get; set; }
// === 控制流 ===
public bool ObfuscateLogic { get; set; }
// === 方法保护(三选一,互斥) ===
public bool EncryptMethods { get; set; } // DynamicMethod 解密
public bool VirtualizeMethods { get; set; } // 虚拟化
public bool JitHook { get; set; } // JIT Hook
// === 授权 ===
public bool LicenseProtection { get; set; }
public LicenseOptions License { get; set; }
// === 其他 ===
public bool AntiTamper { get; set; }
public bool Additional { get; set; } // 总开关
public bool AntiDebug { get; set; }
public bool AntiDump { get; set; }
public bool EncryptResources { get; set; }
public bool MetadataConfusion { get; set; }
public string? SnkPath { get; set; } // 强签名密钥路径
}
6. ProtectionContext:步骤间的共享数据总线
csharp
public class ProtectionContext
{
public required ModuleDefMD Module { get; init; } // dnlib 模块引用
public required ProtectOptions Options { get; init; } // 保护选项
public required string SourcePath { get; init; } // 源文件路径
public required string OutputPath { get; init; } // 输出路径
public string TargetFramework { get; init; } // "net48", "net8.0" 等
public bool IsNetCore { get; init; } // .NET Core 标志
public bool IsExecutable { get; init; } // EXE vs DLL
public required RuntimeService Runtime { get; init; } // 运行时类型加载
public RandomService Random { get; set; } = new(); // 共享随机数
public ProtectionSession? Session { get; set; } // 多模块会话
// 用户注入的类型(如授权验证器),会被后续步骤自动保护
public HashSet<TypeDef> UserTypes { get; } = new();
// 执行日志
public List<string> Logs { get; } = new();
}
7. ProtectionSession:多模块协同保护
csharp
public class ProtectionSession
{
public IList<ProtectionContext> Contexts { get; } // 所有模块上下文
public NameService? NameService { get; } // 跨模块共享名称服务
public RandomService Random { get; } // 跨模块共享随机数
// 在所有模块 Execute 之后统一重命名
public void RunRename()
{
// AnalyzeAll: 收集所有模块可重命名成员 + 构建 VTable
// RenameAll: 统一分配新名称 + 更新所有引用
NameService?.AnalyzeAll();
NameService?.RenameAll();
}
}
8. AssemblyProtectorService:顶层编排器
csharp
public class AssemblyProtectorService
{
private IList<ProtectResult> ProtectMultipleCore(
List<string> inputs, string outputDir, ProtectOptions options)
{
// 1. 加载所有模块 → 创建 ProtectionContext
var contexts = new List<ProtectionContext>();
foreach (var input in inputs)
{
var module = ModuleDefMD.Load(input);
var ctx = new ProtectionContext { Module = module, Options = options, ... };
contexts.Add(ctx);
}
// 2. 创建会话(共享 NameService + RandomService)
var session = new ProtectionSession(contexts, options);
var pipeline = new ProtectionPipeline();
// 3. 阶段1:注入运行时
foreach (var ctx in contexts)
pipeline.Inject(ctx);
// 4. 阶段2:执行 IL 修改(按 Order 排序)
foreach (var ctx in contexts)
pipeline.Execute(ctx);
// 5. 跨模块重命名
session.RunRename();
// 6. 阶段3:写入器配置 + 保存
foreach (var ctx in contexts)
{
var writeOptions = new ModuleWriterOptions(ctx.Module);
pipeline.ConfigureWriter(ctx, writeOptions);
ctx.Module.Write(ctx.OutputPath, writeOptions);
}
}
}
9. 从命令行到 GUI:三种使用入口
| 入口 | 类型 | 技术 | 适用场景 |
|---|---|---|---|
TWProtector.CLI |
命令行 | .NET 10 Console | CI/CD 自动化 |
TWProtector (GUI) |
桌面 | Avalonia 12 | 跨平台可视化 |
TWProtector (WPF) |
桌面 | WPF | Windows 原生体验 |
命令行示例:
bash
TWProtector.CLI --input MyApp.exe --output ./protected \
--preset all --encrypt-strings --obfuscate \
--license --online --api-url http://server:5159 \
--software-key YOUR_KEY
10. 结语
本文概述了保护引擎的流水线架构。后续文章将逐层深入每一类保护的具体实现。下一篇将详细讲解字符串加密------这是最基础但最有效的第一道防线。
本文由 TWSoft.AssemblyProtector 驱动。完整源码和工具请访问项目主页。