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

.NET 程序保护实战系列

本系列文章基于 TWSoft.AssemblyProtector 保护引擎,系统讲解 .NET 程序集的防护技术,从流水线架构到每一层保护的实现原理。


文章列表

# 标题 核心内容
01 流水线架构与保护引擎总览 三阶段流水线、ProtectOptions、多模块编排
02 字符串加密:让反编译器的搜索功能失效 Ldstr HOOK、XOR 块加密、xorshift32、不可见 Unicode
03 符号混淆:名称就是第一道防线 VTable 感知重命名、跨模块同步、6 种命名模式
04 控制流混淆:打乱逻辑让分析者绕路 基本块拆分、JumpMangler、不透明谓词
05 代码虚拟化:把 IL 变成只有你能懂的字节码 自定义 VM、栈式解释器、Token 名称反射
06 方法体加密:密钥在手才能执行的代码 DynamicMethod 解密、ILGenerator 重建 IL
07 JIT Hook 保护:在编译时刻解密 clrjit.dll Hook、Trampoline、哨兵 IL
08 防篡改校验:任何修改都会触发自毁 FNV-1a 方法体哈希、Environment.FailFast
09 反调试与反转储:让调试器无处下手 IsDebuggerPresent、PE 头归零、元数据销毁
10 资源加密:把 DLL 藏进保险箱 SPN 三阶段加密、xorshift128、AssemblyResolve
11 类型注入:无 DLL 依赖的运行时交付 InjectHelper 深度克隆、框架外观程序集重定向
12 授权保护集成:从保护到变现的闭环 验证器编译、入口点注入、多点验证、HMAC 签名

适用读者

  • .NET 开发者,了解 IL 基本指令
  • 安全研究员,对逆向工程有兴趣
  • 商业软件开发者,需要保护知识产权

技术栈

  • dnlib — .NET 程序集读写库
  • CIL — 通用中间语言指令
  • C# Expression Trees / ILGenerator — 运行时代码生成

本系列文章由 TWSoft.AssemblyProtector 保护引擎驱动。工具在全部完成后部分开源,欢迎在 GitHub 关注。文章内容仅供技术学习,请勿用于非法用途。

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

目录

  1. 为什么要保护 .NET 程序?
  2. 保护引擎的核心设计理念
  3. 三阶段流水线架构
  4. 保护步骤注册与执行顺序
  5. ProtectOptions:一个配置控制所有层
  6. ProtectionContext:步骤间的共享数据总线
  7. ProtectionSession:多模块协同保护
  8. AssemblyProtectorService:顶层编排器
  9. 从命令行到 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 接口,包含三个可选方法:

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) { }
}

三阶段执行流程

// 阶段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 个保护步骤:

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) 决定是否启用:

// 字符串加密:由 EncryptStrings 开关控制
public bool IsEnabled(ProtectOptions options) => options.EncryptStrings;

// 混淆:由 Obfuscate 开关控制
public bool IsEnabled(ProtectOptions options) => options.Obfuscate;

5. ProtectOptions:一个配置控制所有层

ProtectOptions 是所有保护步骤的控制中心:

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:步骤间的共享数据总线

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:多模块协同保护

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:顶层编排器

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 原生体验

命令行示例:

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

posted @ 2026-07-06 11:57  翼帆  阅读(82)  评论(0)    收藏  举报