.NET 程序保护实战系列01-流水线架构与保护引擎总览

01 · 流水线架构与保护引擎总览

目录

  1. [为什么要保护 .NET 程序?](#为什么要保护 .NET 程序?)
  2. 保护引擎的核心设计理念
  3. 三阶段流水线架构
  4. 保护步骤注册与执行顺序
  5. ProtectOptions:一个配置控制所有层
  6. ProtectionContext:步骤间的共享数据总线
  7. ProtectionSession:多模块协同保护
  8. AssemblyProtectorService:顶层编排器
  9. [从命令行到 GUI:三种使用入口](#从命令行到 GUI:三种使用入口)
  10. 结语

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 驱动。完整源码和工具请访问项目主页。

相关推荐
落寞的电源3 小时前
Delegate = Object + MethodInfo
开发语言·数据库·c#
Ricky_Theseus5 小时前
Trie 字典树:前缀匹配利器
开发语言·c#
北域码匠19 小时前
嵌入式限幅滤波:工业信号降噪利器
c#·传感器采集·数据预处理·嵌入式算法·限幅滤波·数字滤波·数据降噪
csdn_aspnet1 天前
C# 提取、截取或匹配字符串内包含指定字符的一些方法分享
c#·字符串·正则·分割·提取·匹配
枳实-叶1 天前
【Linux驱动开发】第23天:spi_driver 的 probe / remove 函数实现规范
linux·驱动开发·c#
长明1 天前
C#项目组织与概念梳理
后端·c#
迷路爸爸1801 天前
Python collections 入门+实战
windows·python·c#·collections·dict
csdn_aspnet1 天前
C# 截取或匹配字符串内包含指定字符的一些方法
c#·字符串·分割·string·匹配·截取
Rotion_深1 天前
C# 值类型与引用类型 详解
开发语言·jvm·c#