[机翻] [ABD] 04_混淆工具使用指南
04 混淆工具使用指南
⚠️ API 版本说明:本文档中的 Miasm API 代码示例已于 2026-07 更新至 Miasm 0.1.5+ 版本。课程原始材料使用的是 0.1.3 版本(2020年),部分 API 已发生 breaking change。更新处以
【更新】标注,旧版用法以【旧版 v0.1.3】标注。
本章介绍商业混淆工具与学术混淆工具,重点讲解 O-LLVM 与 Tigress 的原理、选项与使用方法,并列出课程的测试用 C 源码与 Makefile 构建规则,供 Hands-On 实践参考。
4.1 商业混淆工具
以下是一些常见的商业混淆工具,它们被广泛应用于软件保护(同时也可能被恶意软件滥用):
| 工具 | 说明 |
|---|---|
| Themida | 由 Oreans Technologies 开发,提供多层保护机制,包括反调试、反内存转储、代码虚拟化与代码变形。是市场上知名的加壳保护工具之一。 |
| Code Virtualizer | 同样来自 Oreans,专注于代码虚拟化(Virtualization Obfuscation),将 x86/x64 指令转换为自定义虚拟机字节码。 |
| VMProtect | 提供代码虚拟化、加壳与授权管理功能。广泛用于软件保护,也常见于恶意软件样本中。 |
| Enigma | Enigma Protector,提供加壳、虚拟化、反调试与授权管理。 |
| Epona | 商业软件保护工具,提供代码混淆与反逆向功能。 |
注意:这些商业工具在恶意软件分析中经常出现——许多恶意软件样本使用这些工具加壳以逃避检测。因此,逆向分析者需要熟悉这些工具的特征与脱壳方法。
4.2 学术混淆工具
学术混淆工具通常开源或可免费获取,便于教学与研究。本课程重点介绍两个工具:O-LLVM 与 Tigress。
4.2.1 O-LLVM (Obfuscator-LLVM)
【更新】O-LLVM 原始项目已停止维护:
github.com/obfuscator-llvm/obfuscator仓库自 2017 年起不再更新,最后支持的 LLVM 版本为 4.0。以下是目前活跃的替代 fork:
- Hikari-LLVM15 (https://github.com/HikariObfuscator/Hikari) — 支持 LLVM 15+,在 O-LLVM 基础上新增了字符串加密、间接跳转、反 IDA 等混淆 pass
- goron (https://github.com/amimo/goron) — 支持 LLVM 13+,保持与 O-LLVM 原有选项(-sub/-fla/-bcf)的兼容性
- Pluto-Obfuscator (https://github.com/bluesadi/Pluto-Obfuscator) — 支持 LLVM 12+,增强了控制流混淆和虚假控制流
- Arkari — 基于 Hikari 的商业版本,提供更多高级混淆特性
这些 fork 支持更新的 LLVM 版本,部分还新增了更多混淆选项。下文 O-LLVM 的选项说明(-sub/-fla/-bcf)对 goron 仍然适用;Hikari 和 Pluto 有额外的混淆选项。
原理
O-LLVM 是基于 LLVM 的开源混淆器。其核心原理是:
- 将混淆实现为编译器工具链中的一个 optimization pass(优化通道)。
- 混淆作用于 LLVM IR(中间表示) 层面。
- 由于混淆在 IR 层进行,可以支持 LLVM 支持的所有目标架构。
源代码 (.c) ──► LLVM Frontend (clang) ──► LLVM IR
│
▼
┌──────────────────┐
│ Obfuscation Pass │ ← O-LLVM 的混淆在此插入
│ -sub / -fla / │
│ -bcf │
└────────┬─────────┘
│
▼
混淆后的 LLVM IR
│
▼
LLVM Backend ──► 机器代码
选项
O-LLVM 提供三个混淆选项:
| 选项 | 名称 | 对应技术 | 说明 |
|---|---|---|---|
-sub |
Instruction Substitution | 指令替换 | 用等效但复杂的指令序列替换原始指令。 |
-fla |
Control Flow Flattening | 控制流平坦化 | 将基本块展平为 switch-case 结构。 |
-bcf |
Bogus Control Flow | 不透明谓词 | 插入不透明谓词与虚假控制流。 |
-bcf 还可配合 -bcf_prob 参数控制插入概率(0-100)。
参考文献
- Junod et al. Obfuscator-LLVM – Software Protection for the Masses. SPRO'15 (Workshop on Software Protection, 2015).
o-llvm.sh 脚本内容
以下是对单个 C 文件应用三种混淆变换的核心命令:
# 指令替换
${OLLVM} –m32 –mllvm –sub ${FILE} –o "${FILE_NO_EXT##*/}-sub.bin"
# 控制流平坦化
${OLLVM} –m32 –mllvm –fla ${FILE} –o "${FILE_NO_EXT##*/}-fla.bin"
# 虚假控制流(不透明谓词),bcf_prob=100 表示 100% 插入概率
${OLLVM} –m32 –mllvm –bcf –mllvm –bcf_prob=100 ${FILE} –o "${FILE_NO_EXT##*/}-bcf.bin"
参数说明:
${OLLVM}:O-LLVM 的 clang 可执行文件路径。–m32:编译为 32 位。–mllvm –sub/–mllvm –fla/–mllvm –bcf:启用对应的混淆变换。${FILE}:输入的 C 源文件。${FILE_NO_EXT##*/}:去除路径与扩展名后的文件名,用于命名输出文件。
完整 o-llvm.sh 脚本逻辑
完整的 o-llvm.sh 脚本逻辑:遍历 src 目录下的所有 .c 文件,对每个文件应用三种混淆变换。
#!/bin/bash
#
# o-llvm.sh - 对 src 目录下所有 .c 文件应用 O-LLVM 三种混淆变换
#
# O-LLVM 的 clang 路径(需根据实际环境配置)
OLLVM=/path/to/ollvm/build/bin/clang
# 源代码目录
SRC_DIR=src
# 输出目录
OUT_DIR=out
# 创建输出目录
mkdir -p ${OUT_DIR}
# 遍历 src 目录下的所有 .c 文件
for FILE in ${SRC_DIR}/*.c; do
# 提取文件名(不含路径与扩展名)
FILE_NO_EXT="${FILE%.c}"
echo "========================================"
echo "Processing: ${FILE}"
echo "========================================"
# 1. 指令替换 (-sub)
${OLLVM} –m32 –mllvm –sub ${FILE} –o "${OUT_DIR}/${FILE_NO_EXT##*/}-sub.bin"
# 2. 控制流平坦化 (-fla)
${OLLVM} –m32 –mllvm –fla ${FILE} –o "${OUT_DIR}/${FILE_NO_EXT##*/}-fla.bin"
# 3. 虚假控制流 / 不透明谓词 (-bcf),插入概率 100%
${OLLVM} –m32 –mllvm –bcf –mllvm –bcf_prob=100 ${FILE} –o "${OUT_DIR}/${FILE_NO_EXT##*/}-bcf.bin"
echo "Done: ${FILE}"
echo ""
done
echo "All files processed. Output in ${OUT_DIR}/"
4.2.2 Tigress
简介
- Tigress 由 University of Arizona 维护,由 Christian Collberg 领导开发。
- 与 O-LLVM 不同,Tigress 混淆的是 C 源代码(而非 IR)。
- Christian Collberg 是软件混淆领域的先驱学者之一,也是混淆分类法的重要贡献者。
选项
Tigress 的主要选项:
| 选项 | 说明 |
|---|---|
Transform |
指定要应用的变换名称。 |
AddOpaqueCount |
指定插入的不透明谓词数量。 |
AddOpaqueKinds |
指定不透明谓词的种类。 |
Functions |
指定要混淆的函数(可指定多个)。 |
Environment |
指定运行环境(如操作系统)。 |
out / o |
指定输出文件名。 |
6 种变换
Tigress 提供 6 种变换:
| 序号 | 变换名称 | 说明 |
|---|---|---|
| 1 | EncodeLiterals |
编码文字常量(Encode Literals)。 |
| 2 | EncodeArithmetic |
编码算术运算(Encode Arithmetic / MBA)。 |
| 3 | Flatten |
控制流平坦化(Control Flow Flattening)。 |
| 4 | InitOpaque + AddOpaque |
初始化并添加不透明谓词(Opaque Predicate)。 |
| 5 | InitEntropy + InitOpaque + AddOpaque |
复合变换:先初始化熵源,再添加不透明谓词。 |
| 6 | Virtualize |
虚拟化混淆(Virtualization Obfuscation)。 |
Transform 和 Functions 可堆叠:可以在一条命令中指定多个 Transform,并对多个函数应用变换。Tigress 会按照指定顺序依次应用变换。
运行示例
以下是对每个变换的完整命令行示例。假设源文件为 test-add.c,混淆的函数为 add:
# 1. EncodeLiterals - 编码文字常量
tigress \
--Transform=EncodeLiterals \
--Functions=add \
--out=test-add-encode_literals.c \
test-add.c
# 2. EncodeArithmetic - 编码算术
tigress \
--Transform=EncodeArithmetic \
--Functions=add \
--out=test-add-encode_arithmetic.c \
test-add.c
# 3. Flatten - 控制流平坦化
tigress \
--Transform=Flatten \
--Functions=add \
--out=test-add-flatten.c \
test-add.c
# 4. InitOpaque + AddOpaque - 不透明谓词
tigress \
--Transform=InitOpaque \
--Functions=add \
--Transform=AddOpaque \
--AddOpaqueCount=5 \
--AddOpaqueKinds=call,bug,true \
--Functions=add \
--out=test-add-addopaque.c \
test-add.c
# 5. InitEntropy + InitOpaque + AddOpaque - 复合变换
tigress \
--Transform=InitEntropy \
--Functions=add \
--Transform=InitOpaque \
--Functions=add \
--Transform=AddOpaque \
--AddOpaqueCount=5 \
--AddOpaqueKinds=call,bug,true \
--Functions=add \
--out=test-add-entropy_opaque.c \
test-add.c
# 6. Virtualize - 虚拟化混淆
tigress \
--Transform=Virtualize \
--Functions=add \
--out=test-add-virtualize.c \
test-add.c
tigress.sh 脚本
tigress.sh 脚本通过 Docker 运行 Tigress(因为 Tigress 的本地安装较为复杂)。脚本使用 sed 替换占位符 __TMPDIR__:
#!/bin/bash
#
# tigress.sh - 通过 Docker 运行 Tigress 混淆器
#
# 使用 sed 替换模板中的 __TMPDIR__ 占位符为实际临时目录路径
#
# Docker 镜像名
TIGRESS_IMAGE=tigress/tigress:latest
# 临时工作目录
TMPDIR=$(mktemp -d)
# 对模板进行 sed 替换,将 __TMPDIR__ 替换为实际路径
sed "s|__TMPDIR__|${TMPDIR}|g" tigress_template.sh > ${TMPDIR}/tigress_run.sh
# 通过 Docker 运行 Tigress
# 将临时目录挂载到容器中
docker run --rm \
-v ${TMPDIR}:/work \
${TIGRESS_IMAGE} \
/bin/bash /work/tigress_run.sh
# 清理临时目录
rm -rf ${TMPDIR}
参考链接
- Tigress 官方主页:http://tigress.cs.arizona.edu/index.html
4.3 测试用 C 源码
课程提供了 4 个测试用 C 源码文件,用于验证不同混淆技术的效果。
4.3.1 test-add.c
三个常量加法运算,用于测试指令替换、编码算术等。
#include <stdio.h>
int add(int n) {
return 12 + 56 + 127 + n;
}
int main() {
int n;
scanf("%d", &n);
printf("%d\n", add(n));
return 0;
}
- 函数
add计算12 + 56 + 127 + n。 - 包含多个常量加法,适合测试
-sub(指令替换)、EncodeArithmetic。 - 常量
12, 56, 127可被EncodeLiterals处理。
4.3.2 test-hello.c
字符串打印,用于测试编码文字(Encode Literals)。
#include <stdio.h>
int main() {
printf("hello world\n");
return 0;
}
- 仅打印字符串
"hello world\n"。 - 适合测试
EncodeLiterals(将字符串逐字符编码)。 - 无算术运算,因此
-sub和EncodeArithmetic不适用(*2)。
4.3.3 test-mod2.c
取模分支,用于测试控制流相关的混淆。
#include <stdio.h>
int mod2(int n) {
if (n % 2 == 0) {
return 0;
} else {
return 1;
}
}
int main() {
int n;
scanf("%d", &n);
printf("%d\n", mod2(n));
return 0;
}
- 函数
mod2判断n的奇偶性,返回 0(偶数)或 1(奇数)。 - 包含条件分支,适合测试
-bcf(不透明谓词)、-fla(控制流平坦化)、AddOpaque、Virtualize。 - 基本块数量足够,适用于大多数混淆技术。
4.3.4 test-mod2-add.c
使用魔数(magic numbers)的复合运算,综合测试多种混淆。
#include <stdio.h>
int mod2_add(int n) {
int magic1 = 0xdeadbeef;
int magic2 = 0x8badf00d;
int result = (magic1 ^ magic2) + n;
if (result % 2 == 0) {
return 0;
} else {
return 1;
}
}
int main() {
int n;
scanf("%d", &n);
printf("%d\n", mod2_add(n));
return 0);
}
- 函数
mod2_add使用两个魔数0xdeadbeef和0x8badf00d。 - 包含异或运算、加法运算与条件分支。
- 综合了常量、算术与控制流,适合测试多种混淆技术的叠加效果。
注:
0xdeadbeef和0x8badf00d是经典的"调试魔数"(magic debug numbers),在恶意软件分析中也常作为特征值出现。
4.4 Makefile
课程为各 Hands-On 实验提供了 Makefile,用于自动化构建混淆后的二进制文件。
4.4.1 hands-on1/Makefile
Hands-On 1 使用 O-LLVM 进行混淆。Makefile 使用 O-LLVM 的 clang,以 -m32 -O0 编译:
# hands-on1/Makefile
# 使用 O-LLVM 的 clang 进行混淆编译
# O-LLVM 的 clang 路径
CC = /path/to/ollvm/build/bin/clang
# 编译选项:32 位、不优化(-O0 保留混淆效果,防止编译器优化掉混淆代码)
CFLAGS = -m32 -O0
# 源文件
SRCS = $(wildcard src/*.c)
# 目标文件(将 .c 替换为 .bin)
BINS = $(patsubst src/%.c,out/%.bin,$(SRCS))
# 默认目标
all: $(BINS)
# 编译规则
out/%.bin: src/%.c
@mkdir -p out
$(CC) $(CFLAGS) $< -o $@
# 清理
clean:
rm -rf out
.PHONY: all clean
关键点:
-m32:编译为 32 位二进制(便于分析)。-O0:关闭优化。这是关键——如果开启优化,编译器可能会将混淆插入的"无用代码"优化掉,使混淆失效。因此使用-O0保留混淆效果。- 每个源文件编译为对应的
.bin输出。
4.4.2 hands-on2 ~ hands-on6/Makefile
Hands-On 2 到 6 各有不同的实验目标,Makefile 根据实验内容定制构建规则:
# hands-on2/Makefile(示例结构)
# 每个 hands-on 的 Makefile 根据实验内容定制
CC = gcc
CFLAGS = -m32 -O0
# 实验特定的源文件与目标
SRCS = test-add.c test-hello.c test-mod2.c
BINS = $(SRCS:.c=.bin)
all: $(BINS)
%.bin: %.c
$(CC) $(CFLAGS) $< -o $@
clean:
rm -f *.bin
.PHONY: all clean
各 Hands-On 实验概览:
| Hands-On | 实验内容 | 使用工具 |
|---|---|---|
| hands-on1 | O-LLVM 混淆实验 | O-LLVM (-sub, -fla, -bcf) |
| hands-on2 | Tigress 混淆实验 | Tigress (6 种变换) |
| hands-on3 | 数据流分析反混淆 | 自定义 Python 脚本 |
| hands-on4 | 符号执行反混淆 | angr / miasm |
| hands-on5 | 等价性检查 | SMT solver (Z3) |
| hands-on6 | 综合 Hands-On | 综合 |
注:以上 Makefile 为教学示例,实际使用时需根据环境调整工具路径与编译选项。
4.5 工具对比总结
O-LLVM vs Tigress
| 特性 | O-LLVM | Tigress |
|---|---|---|
| 混淆层次 | LLVM IR(中间表示) | C 源代码 |
| 维护方 | 开源社区 | University of Arizona (Christian Collberg) |
| 混淆选项 | 3 种(-sub, -fla, -bcf) | 6 种(含复合变换) |
| 虚拟化混淆 | 不支持 | 支持(Virtualize) |
| 编码文字 | 不支持 | 支持(EncodeLiterals) |
| MBA | 不支持 | 支持(EncodeArithmetic) |
| 输出 | 二进制(机器代码) | C 源代码(需再编译) |
| 安装难度 | 需编译 LLVM | 提供 Docker 镜像 |
选择建议
- 需要 控制流平坦化 或 指令替换:两者皆可,O-LLVM 更简单。
- 需要 虚拟化混淆:使用 Tigress(
Virtualize)。 - 需要 MBA:使用 Tigress(
EncodeArithmetic)。 - 需要 隐藏字符串:使用 Tigress(
EncodeLiterals)。 - 需要混淆后直接得到二进制:使用 O-LLVM(Tigress 输出 C 源码需二次编译)。
4.6 本章小结
- 商业混淆工具(Themida、VMProtect 等)提供强大但闭源的保护,也常被恶意软件使用。
- O-LLVM 是基于 LLVM IR 的开源混淆器,提供
-sub、-fla、-bcf三种变换,通过o-llvm.sh脚本批量处理。 - Tigress 是基于 C 源代码的混淆器,提供 6 种变换,通过 Docker 运行,支持变换堆叠。
- 课程提供了 4 个测试用 C 源码,覆盖常量加法、字符串打印、取模分支与魔数复合运算等场景。
- Makefile 使用
-O0编译以保留混淆效果,避免编译器优化消除混淆代码。 - 至此,课程的混淆技术部分讲解完毕,后续将进入反混淆技术(Dataflow Analysis、Symbolic Execution、Equivalence Checking)部分。

浙公网安备 33010602011771号