aronpaaul/CompotProtector
GitHub: aronpaaul/CompotProtector
基于Rust的Windows x64 PE文件保护器,提供代码加密、虚拟化等安全特性。
Stars: 1 | Forks: 0
# CompotProtector -> CompotProtector




使用 Rust 编写的自定义 Windows x64 PE 保护器,由一个小型可脚本化命令行界面驱动。它接受一个输入 `.exe` 文件,应用一系列混淆、虚拟化和反分析转换,并写入一个加固的二进制文件,该文件仍然可以本地运行。它针对 MinGW 和 MSVC 生成的二进制文件。
## 内容
- [概述](#overview)
- [功能映射](#feature-map)
- [保护内部机制](#protection-internals) - 虚拟化、变异、混淆
- [运行时保护](#runtime-protections) - 字符串、加密、种子、完整性
- [保护管道](#protection-pipeline)
- [优势和局限性](#strengths-and-limitations)
- [路线图和待办事项](#roadmap-and-todo)
- [构建和使用](#build-and-usage)
- [免责声明](#disclaimer)
## 概述
保护器在 PE 文件上运行一系列独立的遍历。每次遍历都是可组合的,并且可以从命令行切换。输出二进制文件携带一个小型位置无关的加载器占位符,作为 TLS 回调注入,在原始入口点运行之前在内存中反转转换。没有任何内容写回磁盘:受保护的文件在其整个生命周期内都保持加密状态。
## 功能映射
| 区域 | 执行的操作 |
|------|--------------|
| 字符串 | 整个字符串加密、运行时解密、定期重新加密(反导出) |
| 导入 | 哈希解析、IAT 摧毁、数据目录中毒、名称混淆 |
| 代码 | 整个 `.text` 加密、磁盘上为零、在运行时恢复并重新保护 |
| 虚拟化 | 标记区域的有限自定义虚拟机(适用于 MinGW 和 MSVC) |
| 加载器 | TLS 回调注入,在入口点之前解密占位符 |
| 密码 | SipHash-2-4 密钥流,单向 PRF,64 位机器绑定种子 |
| 反调试 | ntdll 内联钩检测(击败默认 ScyllaHide 配置文件) |
| 反附加 | 监视器线程在调试器附加时破坏行为 |
| 反模拟 | 通过 CPUID 和 ntdll 标头将种子绑定到真实机器 |
| 反篡改 | 专用线程每 100 毫秒重新散列占位符和代码块 |
| 多态性 | 每次构建的种子、垃圾、密钥和 VM 寄存器布局 - 没有两个构建匹配 |
## 保护内部机制
三个转换在指令级别操作。下面的代码片段以 x86-64 流加 VM 字节码编写,以显示分析师在每次遍历前后看到的内容。
### 虚拟化
标记的函数被提升到用于小型有限解释器的字节码。本地的 `add` / `xor` / `lea` 已消失;只剩下对 VM 的调度,字节码本身在磁盘上使用每次构建的寄存器排列加密。要读取逻辑,分析师必须首先反转解释器,然后解码字节码。

之前:一个干净的四个指令函数,任何人都可以阅读。
之后:一个 `call vm_loader` 调用加上加密的字节码流。算术仅作为 VM 操作存在,永远不会接触本地指令流。
### 变异
这里的变异是多态性:相同的逻辑代码在每次构建中发出不同的字节。加载器引导程序携带垃圾锚点,这些锚点从新的时钟种子修补,密钥更改,VM 重新排列寄存器映射。结果是,签名、哈希和二进制比较不会从一个构建传递到下一个构建。

注意:这是构建时多态性,而不是每次运行时任意函数的自修改变异。真正的编译代码指令级变异是不稳定的(它将每个相对跳转、RIP 相对引用和展开记录移动),因此项目加密代码而不是变异它控制的部件。请参阅 TODO。
### 混淆
曾经用来泄露密钥派生过程的可识别常量被移动到调度器后面并屏蔽。像黄金比例常数这样的字面量不再出现在反汇编中;操作数从加密的字节码中拉出,仅在运行时取消屏蔽。

之前:KDF 从上到下读取,并使用单个 `grep` 查找算法的常量名称。之后:常量永远不会是字面量,操作符位于调度循环后面,并且模式匹配识别失败。
## 运行时保护
### 字符串保护
字符串永远不会出现在文件中。它们仅在运行时解密,并且后台线程会定期重新加密它们,因此在进程空闲时的内存转储显示密文而不是文本。

### 密钥流加密
原始 Murmur3 `fmix32` 密钥流是可逆的:已知的明文让分析师恢复种子并解锁一切。它被替换为 SipHash-2-4,这是一个经过验证的单向密钥 PRF,因此已知的明文不会泄露有关密钥的任何信息。

### 反模拟种子
解密种子曾经是一个存储在文件中的常量,离线模拟器(如 Unicorn)可以逐字逐句地回放它。现在种子与真实 ntdll 标头的哈希和 `CPUID` 的结果进行 XOR 混合,因此它永远不会完整存储,并且仅在目标机器上解析。

### 运行时完整性
专用线程每 100 毫秒重新散列加载器占位符、加密的代码块和在内存中解密的代码。任何修补,包括磁盘或内存中的修补,包括翻转已解密代码中的分支,都会被检测到,并且进程会以错误对话框退出。

## 保护管道
```
input.exe
|
strip symbols / debug
virtualize marked regions (bounded custom vm, per-build register layout)
encrypt every string (siphash-2-4, machine-bound seed)
hide imports (hash resolve + iat destroy + dir poison)
encrypt .text (zeroed on disk, restored and re-protected at runtime)
install tls callback (decrypts the stub before the entry point)
anti-debug / anti-attach / anti-emulation / integrity
randomize section names, poison data directories
|
output.exe -> runs natively, decrypts itself in memory only
```
## 优势和局限性
### 优势
- 分层和可组合:每次遍历都是独立的,可切换。
- 适用于 MinGW 和 MSVC 二进制文件,通过单个可脚本化 CLI。
- 单向密码加上机器绑定种子击败了简单的离线静态恢复和已演示的 Unicorn 重放攻击。
- 反导出:字符串和代码在进程空闲时重新加密。
- ntdll 内联钩反调试捕获默认 ScyllaHide 设置。
- 有限制的 VM 和整个 `.text` 磁盘上为零的视图使反汇编器中的第一次查看显示无用的内容。
- 每次构建的多态性破坏了签名和比较。
- 快速:保护只需一秒钟,运行时开销适中。
### 局限性
- 解包悖论:自解包的二进制文件最终可以被一个有决心的分析师解包,因为解密器和所有密钥材料都包含在其中。每一层都提高了成本,但没有一层使其成为不可能。
- CPUID 节点锁定绑定到 CPU 模型,因此输出在不同 CPU 系列之间不可移植。
- 加载器引导程序必须是明文(它引导解密),因此最外层总是可读的。
- 种子是 64 位,而不是 128 位;在目标机器上,暴力破解在理论上可能(尽管成本高昂)。
- 反调试和反篡改是用户模式,因此它们是可修补的,经过调整的 ScyllaHide 配置文件仍然可以绕过一些检查。
- 没有真正的控制流混淆(没有 CFG 扁平化或 MBA)。
- 文件大小增加,因为加密的代码块重复 `.text`。
## 路线图和待办事项
### 尚未实现
- 128 位字面量种子(当前种子是 64 位;需要双密钥密码路径)。
- 真正的指令级代码变异(目前只有构建时多态性)。
- 延迟导入隐藏。
- 控制流混淆:CFG 扁平化、不透明谓词、MBA 表达式。
- VM 内存和调用操作码(解释器仅是整数-ALU 并有限制)。
- 超出 CPU 模型的外部或在线密钥/硬件绑定密钥。
### 已实现但较弱
- 加载器混淆较轻;引导程序和密码仍然是可读的。
- 反调试是用户模式,可修补;钩检测仅捕获钩子。
- 完整性检查器位于同一受保护占位符中,因此可以在它运行之前将其修补出来(运行时线程缩小但不会关闭)。
- 种子熵主要来自时钟,这限制了真正的不可预测性。
- 即使有合理的部分名称,输出结构仍然看起来是打包的(没有导入,高熵)。
- 短 `"> "` 字符串低于扫描阈值,保持明文。
- 篡改响应使用阻塞消息框,因此对话框有一些窗口创建延迟。
### 做得很好,但永远可以改进
- SipHash-2-4 单向密钥流密码。
- 运行时重新加密的整个字符串加密(反导出)。
- 运行时整个 `.text` 加密,磁盘上为零的视图。
- CPUID 和 ntdll 反模拟种子绑定。
- 导入隐藏、IAT 摧毁和数据目录中毒。
- ntdll 内联钩反调试。
- MinGW 和 MSVC 之间的有限制 VM。
- 每 100 毫秒的运行时完整性线程。
- 每次构建的多态性。
## 构建和使用
需要 Rust 工具链以及 MinGW / clang 设置来重新组装位置无关的加载器占位符。
```
cargo build --release
```
保护器二进制文件在 `target/release/` 下生成。
CLI 模式在传递参数时自动激活:
```
comprotector -i input.exe -o output.exe
comprotector -i input.exe -o output.exe --lazy # on-demand page decrypt
comprotector -i input.exe -o output.exe --min-len 3 # string scan threshold
comprotector -i input.exe -o output.exe --no-anti-debug # disable anti-debug
comprotector -i input.exe -o output.exe --no-virtualize # disable the vm pass
```
不带参数运行,或使用 `--help` 打印完整选项列表。
## 免责声明
仅限学习和研究之用。请勿将其用于混淆恶意软件或绕过您不拥有的保护。
标签:DOM解析, GitHub Advanced Security, MinGW, MSVC, PE文件处理, Rust语言, TLS回调, Windows PE保护, XML 请求, 代码加密, 代码混淆, 代码虚拟化, 内存保护, 加密技术, 反仿真, 反取证, 反篡改, 反调试, 可视化界面, 字符串加密, 安全加固, 安全开发, 安全测试, 安全评估, 安全防护, 导入加密, 攻击性安全, 文件保护, 软件保护, 通知系统