技术文档

Windows PE 加固推荐方案

Windows PE32 / PE64 的保护选项组合、PDB 符号准备、签名顺序、DLL 导出与兼容性验证。

最后更新于 2025-06-06预计阅读 7 分钟

1. 适用范围

项目范围
格式PE32 / PE64
架构x86 / x64 / ARM / ARM64
产物.exe、.dll、部分 .sys 之外的用户态模块
工具链MSVC / MinGW / Clang / Rust / Go 等生成的 PE

不适用于:

  • 纯托管 .NET 程序集:.NET 加固推荐方案
  • C++/CLI 混合模式程序集:需要同时验证托管与原生部分
  • 内核驱动、受 Windows 签名强制约束的系统组件:当前不建议修改

2. 可选能力

能力作用代价建议默认
压缩保护压缩代码与数据,减小体积启动时解压整个文件,冷启动变慢;EXE / DLL 越大越慢开
导入表保护隐藏或加密 IAT,增加重建导入表的难度与部分加壳、注入工具冲突视场景
反调试检测调试器并终止或降级运行与合法调试、EDR 冲突发布版开
虚拟机检测检测 VMware / VirtualBox 等环境影响虚拟机用户视场景
内存校验检测运行时代码或关键内存被修改少量运行时开销视场景
函数混淆打乱控制流单函数小幅开销核心函数开
函数虚拟化转换为自定义虚拟指令被虚拟化的函数慢数倍到数十倍少量核心函数

性能提醒

  • 压缩保护会在进程启动时解压整个 EXE / DLL,文件越大启动越慢;DLL 被宿主加载时也会拖慢宿主启动。
  • 如果启用文件 / 完整性校验,启动阶段还要遍历、校验产物,同样越大越慢。
  • 函数虚拟化只影响被选中的函数,但会让其运行速度慢数倍到数十倍;高频调用、热循环、DllMain、TLS 回调不要虚拟化。
  • 先用未保护产物测冷启动基线,再开启保护;大体积客户端、启动即加载大量 DLL 的产品要重点测。

已经使用其他加壳、保护或混淆工具的程序,不要再次启用压缩层。多层压缩与虚拟化叠加会导致启动崩溃或随机异常。

3. 三档推荐方案

3.1 基础档:兼容性优先

选项设置
压缩保护开
导入表保护关
反调试关
虚拟机检测关
内存校验关
函数保护5–10 个核心函数混淆

3.2 标准档:商业发布

选项设置
压缩保护开
导入表保护开(验证插件与注入场景)
反调试开
虚拟机检测关(除非明确禁止虚拟机)
内存校验开
函数保护授权、支付、协议签名函数虚拟化;业务逻辑混淆

3.3 强化档:高价值目标

选项设置
压缩保护开
导入表保护开
反调试开
虚拟机检测按业务决定
内存校验开
函数保护10–30 个核心函数虚拟化,其余敏感函数混淆

4. 函数选择与 PDB

4.1 准备 PDB

  • 使用 Release 配置构建,保留与二进制完全匹配的 .pdb。
  • 把 .pdb 放在与输入文件同目录、同名位置。
  • 没有 PDB 时,函数列表只能依赖导出符号或地址,函数级保护的可用性会下降。
  • 发布包不要附带 PDB;PDB 只用于保护阶段和崩溃符号化,按版本单独归档。

4.2 优先保护

  • 授权激活、许可证校验、试用期判断
  • 支付、订单、发票相关逻辑
  • 协议签名、加密解密、密钥派生
  • 反作弊、风控判定、设备指纹
  • 核心算法与业务规则

4.3 谨慎保护

  • DllMain 及加载器锁内执行的代码:可能导致死锁或加载失败
  • TLS 回调、延迟加载导入、清单初始化相关函数
  • SEH / C++ 异常密集的函数:虚拟化可能影响栈展开
  • 高频热循环、实时音视频处理:虚拟化开销明显
  • 与 COM、.NET Interop、外部插件交互的边界函数

4.4 不建议保护

  • CRT / STL 模板实例、__security_check_cookie 等编译器生成代码
  • 只做参数转发的 thunk
  • 第三方静态库中未验证的代码
  • 已经由其他工具虚拟化或加密的代码

4.5 数量建议

  • 首次:5–10 个函数,全部混淆。
  • 第二次:授权与支付函数改为虚拟化。
  • 后续:每次增加 5–10 个函数,跑完整回归后再扩大。

5. 构建、签名与更新

推荐顺序:

编译 → 保护 → 签名 → 安装包 → 分发

关键点:

  • 先保护再签名,否则 Authenticode 签名会因字节变化失效。
  • 使用时间戳服务器签名,避免证书过期后安装包失效。
  • 如果产品有自动更新,更新包的哈希必须在保护之后计算。
  • 同时发布 x86 / x64 / ARM64 时,为每个架构分别构建、保护和签名,不要用 x64 结果代替 ARM64 验证。
  • 保留原始未保护二进制和 PDB,便于回滚与崩溃分析。

6. DLL、COM 与导出

  • 保护 DLL 前确认导出表、序号导出和转发导出仍可用。
  • 如果 DLL 通过 GetProcAddress 动态加载,验证加载路径、导出名称与调用约定。
  • 对 COM 组件,验证 CLSID 注册、Proxy/Stub、regsvr32 与跨进程调用。
  • 对插件体系,验证宿主程序的加载顺序、白名单与签名校验。
  • 对 Shell 扩展、输入法、浏览器插件等宿主进程内模块,重点验证宿主兼容性与崩溃隔离。

7. 兼容性注意

  • 启用 CFG、CET、ASLR、DEP 等缓解措施的程序,先在测试环境验证。
  • 使用 TLS 回调、延迟加载导入、manifest 的程序,重点验证启动阶段。
  • 反调试与部分 EDR、游戏反作弊、远程桌面、录屏环境可能冲突。
  • 使用 SetWindowsHookEx、APC、远程线程注入的插件,可能被反注入策略拦截。
  • Windows 7 / 8.1 仍在使用时,需要单独验证;部分新编译器产物可能已不支持旧系统。
  • ARM64 产物必须在 ARM64 设备或对应虚拟化环境验证。

8. 验证清单

  • 原始 EXE / DLL 在目标系统可正常运行
  • 保护后冷启动、热启动正常
  • 所有导出函数、COM 接口、插件加载正常
  • DllMain、TLS 回调、延迟导入路径正常
  • 授权、支付、自动更新链路正常
  • 异常与崩溃路径能正常提示
  • x86 / x64 / ARM64 目标均覆盖
  • Windows 10 / 11(及需要支持的旧版本)覆盖
  • 主流杀毒软件与 EDR 不误报
  • 最大体积 EXE / DLL 的冷启动已单独测试
  • 被虚拟化函数的调用延迟 / P95 已对比基线
  • 已保留原始产物与 PDB

9. 常见问题

9.1 保护后无法启动

排查顺序:

  1. 关闭反调试、虚拟机检测、内存校验,只保留压缩。
  2. 关闭压缩,只保留函数保护,确认是否是压缩层问题。
  3. 检查是否与其他加壳工具、签名校验、完整性校验冲突。
  4. 检查 TLS 回调、延迟导入、manifest、DLL 搜索路径。
  5. 用原始产物对比依赖和运行库版本。

9.2 函数列表为空或不完整

  • 确认 .pdb 与二进制完全匹配。
  • 确认没有先被其他混淆器或裁剪工具处理。
  • 尝试改用导出符号定位。
  • 确认保护工具能识别当前编译器生成的调试信息格式。

9.3 保护后 DLL 加载失败

  • 检查导出表是否被破坏,序号导出是否仍可解析。
  • 检查 DllMain 是否被虚拟化或混淆。
  • 检查依赖 DLL 的加载顺序与搜索路径。
  • 检查宿主程序是否有模块签名或哈希校验。

9.4 杀毒软件误报

  • 确认发布包已使用正式证书签名。
  • 提交误报样本给杀毒厂商,说明产品用途和签名信息。
  • 避免使用与恶意软件特征相似的高熵压缩配置。
  • 保留旧版本安装包,便于用户回滚。

9.5 虚拟化后性能下降明显

  • 检查是否误选了热循环或高频调用函数。
  • 减少虚拟化函数数量,改用混淆。
  • 对性能敏感模块单独构建,不启用虚拟化。

10. 相关文档

这份文档有帮助吗?欢迎反馈文档问题或补充场景。提交文档反馈