技术文档
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 保护后无法启动
排查顺序:
- 关闭反调试、虚拟机检测、内存校验,只保留压缩。
- 关闭压缩,只保留函数保护,确认是否是压缩层问题。
- 检查是否与其他加壳工具、签名校验、完整性校验冲突。
- 检查 TLS 回调、延迟导入、manifest、DLL 搜索路径。
- 用原始产物对比依赖和运行库版本。
9.2 函数列表为空或不完整
- 确认
.pdb与二进制完全匹配。 - 确认没有先被其他混淆器或裁剪工具处理。
- 尝试改用导出符号定位。
- 确认保护工具能识别当前编译器生成的调试信息格式。
9.3 保护后 DLL 加载失败
- 检查导出表是否被破坏,序号导出是否仍可解析。
- 检查
DllMain是否被虚拟化或混淆。 - 检查依赖 DLL 的加载顺序与搜索路径。
- 检查宿主程序是否有模块签名或哈希校验。
9.4 杀毒软件误报
- 确认发布包已使用正式证书签名。
- 提交误报样本给杀毒厂商,说明产品用途和签名信息。
- 避免使用与恶意软件特征相似的高熵压缩配置。
- 保留旧版本安装包,便于用户回滚。
9.5 虚拟化后性能下降明显
- 检查是否误选了热循环或高频调用函数。
- 减少虚拟化函数数量,改用混淆。
- 对性能敏感模块单独构建,不启用虚拟化。
10. 相关文档
这份文档有帮助吗?欢迎反馈文档问题或补充场景。提交文档反馈