OLLVM学习以及平坦化源码分析
字数 2253 2025-09-01 11:25:53
OLLVM学习与平坦化源码分析教学文档
1. LLVM基础
1.1 LLVM架构概述
LLVM是一种模块化编译器框架,具有以下特点:
- 采用前后端分离设计
- 使用中间表示(IR)作为桥梁
- 支持多种编程语言和目标平台
与GCC相比的优势:
- 扩展性强:新语言只需添加前端解释器
- 平台无关性:后端可生成ELF、SO、EXE等多种格式
1.2 LLVM编译流程
- 前端:执行词法分析、语法分析、语义分析,生成中间代码(IR)
- 中间层优化:对IR进行各种优化和转换
- 后端:将优化后的IR转换为目标平台机器码
1.3 IR中间表示
IR有两种表现形式:
.ll文件:人类可读的文本格式.bc文件:机器处理的二进制格式
常见IR语法元素:
@:全局符号define:函数体定义declare:外部函数声明%1, %2:SSA寄存器i32:32位整数类型
2. 代码优化与混淆
2.1 常见代码优化技术
- 删除无用代码:移除不会被使用的计算结果
- 删除公共子表达式:复用重复计算结果
- 常量合并:编译时计算常量表达式
- 循环展开:减少循环控制开销
- 寄存器分配:优化变量存储位置
2.2 代码混淆原理
与优化相反,混淆通过增加冗余代码和复杂控制流来提高逆向难度。
3. LLVM Pass机制
3.1 Pass基本概念
Pass是在IR阶段对代码进行处理的通道,特点:
- 链式处理:前一个Pass的输出作为下一个Pass的输入
- 分为两类:
- Analysis Pass:提供信息为主
- Transform Pass:优化/转换代码为主
3.2 Pass类型
- ModulePass:处理整个模块(源文件),支持跨函数分析
- FunctionPass:针对单个函数运行,实现
runOnFunction方法 - BasicBlockPass:处理基本块(顺序执行的指令组)
3.3 类型查询与转换
LLVM提供的模板函数:
isa<T>(x):检查x是否为T类型,返回booldyn_cast<T>(x):动态转换为T类型指针(失败返回null)cast<T>(x):断言转换(失败则报错)
4. OLLVM平坦化源码分析
4.1 平坦化混淆原理
将程序的控制流转换为基于switch-case的状态机结构,使原始控制流难以识别。
4.2 关键实现步骤
-
初始化阶段:
- 生成随机密钥用于switch-case值
- 收集原始基本块到
orignBB列表 - 移除第一个基本块(通常为初始化块)
-
创建框架:
- 插入
loopEntry和loopEnd基本块 - 创建
switchVar变量并用密钥加密
- 插入
-
构建switch分发:
- 创建switch指令并设置默认处理块
- 删除原终结指令,改为跳转到
loopEntry
-
重写控制流:
- 为每个基本块分配case值
- 修改终结指令为更新
switchVar并跳转到loopEnd - 处理三种情况:
- 无后继(终止块):不操作
- 无条件跳转:写入对应case值
- 条件跳转:为每个分支写入不同case值
-
修复栈帧:
- 使用
fixStack修复因插入指针而打乱的栈布局
- 使用
4.3 混淆前后对比
原始控制流:
基本块A → 基本块B → 基本块C
平坦化后:
loopEntry → switch(switchVar) {
case 1: 基本块A; 更新switchVar; goto loopEnd;
case 2: 基本块B; 更新switchVar; goto loopEnd;
case 3: 基本块C; 更新switchVar; goto loopEnd;
}
loopEnd: goto loopEntry;
5. 反混淆技术
5.1 现有解决方案
- d810插件:Hex-Rays的逆向工程插件
- angr框架:符号执行分析
- unicorn引擎:模拟执行恢复控制流
5.2 反混淆思路
- 识别switch-case状态机结构
- 重建原始基本块间的跳转关系
- 消除中间状态变量和冗余跳转
5.3 增强混淆的思考
在基本块中间插入间接跳转(br寄存器)可以:
- 干扰angr/unicorn的CFG分析
- 增加动态跳转的复杂性
- 需要处理x64/ARM架构差异
6. 实践指南
6.1 编译OLLVM
- 获取源码:
https://github.com/buffcow/ollvm-project/tree/14.x - 编译选项:
DCMAKE_BUILD_TYPE=Debug(便于调试) - 注意:Release版本无法命中断点
6.2 生成测试IR
clang -emit-llvm -S test.cpp -o output.ll
6.3 自定义Pass开发
- 继承适当的Pass基类(FunctionPass等)
- 实现核心处理逻辑
- 注册Pass到LLVM框架
- 编译为动态库(.so)使用
7. 进阶研究方向
- 混合混淆:结合平坦化与其他混淆技术
- 架构适配:优化ARM平台的混淆效果
- 抗反混淆:设计对抗符号执行的技术
- 性能平衡:在安全性和性能间取得平衡
8. 参考资料
- LLVM官方文档:https://llvm.org/docs/WritingAnLLVMNewPMPass.html
- OLLVM源码:https://github.com/buffcow/ollvm-project
- 反混淆工具:
- https://github.com/mFallW1nd/deflat
- https://eshard.com/posts/D810-a-journey-into-control-flow-unflattening
- 相关研究:
- https://blog.quarkslab.com/deobfuscation-recovering-an-ollvm-protected-program.html
- https://hex-rays.com/blog/hex-rays-microcode-api-vs-obfuscating-compiler