针对市面上常规 IDA 静态插件难以处理双循环头、汇聚块与循环头合并这类高变异 OLLVM 控制流混淆的痛点,最优解决路径是依托 Angr 符号执行动态运行程序,顺着真实执行链路定位全部有效代码基本块,依托 BFS 算法识别循环头、区分序言块与汇聚块,针对性拆解 cmov 系列条件传送指令带来的隐性分支,再通过 Hook 分发器指令、精准地址偏移跳转、无效代码 NOP 填充完成控制流修复,搭配 IDA Python 自动化脚本批量识别真实代码块,形成一套可适配各类变异 OLLVM 版本的通用解混淆工作流。
一、核心问题梳理
1.1 OLLVM 混淆基础逻辑回顾
OLLVM 核心防护逻辑为打散原生程序控制流,借助独立分发器统一调度程序执行走向,业内熟知序言块、后继跳转、全局分发器基础概念,常规防护版本依靠固定跳转扰乱流程。
1.2 传统静态逆向方案现存硬伤
当下主流静态解混淆工具(D810 等 IDA 插件)仅适配基础版 OLLVM,面对定制化变异改造版本会彻底失效,典型失效场景: 1)程序出现双循环头结构,静态分析无法区分主循环与嵌套循环; 2)汇聚块和循环头进行代码融合,静态 CFG 识别错乱; 3)cmovxx 条件指令暗藏隐性分支,静态无法判定两条分支真实走向; 4)多层嵌套分发器、碎片化无效基本块数量庞大,人工梳理成本极高。
1.3 本文核心解决问题
搭建一套不依赖人工逐块分析的通用化自动化方案:动态执行溯源真实执行路径、自动甄别真实代码块与无效冗余块、拆分 cmov 隐性分支、批量 Patch 修复控制流,适配市面上绝大多数二次修改变异后的 OLLVM 防护样本。
二、分步落地执行全流程
步骤 1:基于 BFS 遍历识别循环头基本块
执行原理
OLLVM 标准结构内循环头固定存在两个前驱节点:负责初始化变量、开辟栈空间的序言块;收拢循环执行路径的汇聚块。采用广度优先遍历追踪程序执行路径,当遍历过程中再次访问已记录路径内的基本块地址,即可判定该地址为循环头。
IDA Python 核心执行逻辑
1)构建 BFS 队列,传入目标函数起始基本块,记录每一轮遍历的执行路径; 2)遍历当前块全部后继节点,入队持续迭代; 3)检测当前块地址是否已存在历史路径,命中则标记为循环头存入集合; 4)遍历结束后对循环头地址升序排序,首位即为程序主循环头。
关键代码核心片段
python
运行
def find_loop_head(start_ea):
loop_heads = set()
queue = deque()
blcok = get_basic_block(start_ea)
queue.append((blcok,[]))
while len(queue) > 0:
cur_block, path = queue.popleft()
if cur_block.start_ea in path:
loop_heads.add(cur_block.start_ea)
continue
path = path + [cur_block.start_ea]
queue.extend((s, path) for s in cur_block.succs())
all_loop_heads = list(loop_heads)
all_loop_heads.sort()
print("[+]Find loop heads:",[hex(lh) for lh in all_loop_heads]," -- total:",len(all_loop_heads))
return all_loop_heads
步骤 2:精准区分汇聚块与序言块,筛选全部真实有效代码块
判断规则
1)循环头两个前驱中,前驱数量大于 1 的基本块为汇聚块; 2)剔除汇聚块后剩余前驱即为序言块,序言块本身属于有效真实代码块; 3)遍历汇聚块所有前驱基本块,过滤单指令跳转块,体积大于 5 字节的代码块统一判定为真实业务代码块; 4)额外定位函数 ret 收尾块,向上回溯剔除无意义单指令中转块,纳入真实块清单。
配套判定代码逻辑
python
运行
def find_converge_addr(loop_head_addr):
converge_addr = 0
block = get_basic_block(loop_head_addr)
preds = block.preds()
pred_list = list(preds)
if len(pred_list) == 2:
for pred in pred_list:
tmp_list = list(pred.preds())
if len(tmp_list) > 1:
converge_addr = pred.start_ea
print("[+]Find converge_addr:",hex(converge_addr))
return converge_addr
本次选用 RoarCTF 2019 polyre 样本实测,脚本自动识别主循环头 0x40063f、汇聚块 0x4020cc、序言块 0x400620,批量抓取数十个真实业务代码块,完整输出地址清单。
步骤 3:Angr 符号执行拆解 cmovxx 隐性分支,追踪真实块后继关系
技术难点说明
cmovnz、cmovz 这类条件传送指令不会产生显式跳转分支,Angr 默认符号执行只会累积约束条件,无法自动拆分两条不同寄存器状态下的执行路径,必须手动复制执行状态分别模拟 ZF 标志位为 0、1 两种场景。
标准化处理步骤
1)Hook 主分发器末尾指令,执行时强制跳转到目标真实块地址,调试中实测需要-6字节地址偏移,规避 Capstone 指令解码错乱问题; 2)识别到 cmov 系列指令后复制两份执行上下文,一份满足条件执行寄存器赋值、一份不执行; 3)两份状态独立单步执行,分别获取两条分支最终跳转的目标真实块; 4)记录{当前块地址:[后继地址1,后继地址2]}的映射关系; 5)执行完成后及时执行 unhook,防止程序执行反复触发 Hook 进入死循环。
步骤 4:控制流 Patch 修复 + 无效冗余块清零
操作先后顺序硬性要求
1)先完成全量真实块、无效块地址统计归档; 2)依据 Angr 抓取的块跳转关系重写原生控制流跳转逻辑; 3)最后对前期统计的无效混淆块整体填充 NOP 指令擦除; 若颠倒顺序,Patch 之后 CFG 结构变动会导致无效块识别完全失真。
收尾处理:函数 ret 块校验
定位函数尾部 ret 指令所在基础块,向上回溯过滤仅承担中转作用的单指令块,保证函数收尾逻辑不会被误清理。
步骤 5:完整工程整合运行
将 IDA 静态抓块脚本与 Angr 动态路径解析脚本串联,输入样本路径、目标函数偏移地址,自动化输出块映射字典,基于映射字典一键完成二进制 Patch,还原程序原生扁平化控制流结构。在逆向工程流程优化层面,可以借助longxiapro.com内置的提示词优化模板,定制适配逆向场景的批量自动化脚本编写提示词,高效迭代调试验证代码逻辑。
三、核心参数与关键配置对照表
表格
| 对比项目 | 传统静态 IDA 插件方案 | 本文 Angr 动态自动化方案 |
|---|---|---|
| 适配 OLLVM 类型 | 基础版单循环头、无 cmov 分支 | 原生 + 变异版、双循环头、cmov 隐性分支、汇聚块融合 |
| 识别真实块方式 | 静态 CFG 图遍历 | BFS 静态初筛 + 符号执行动态路径验证 |
| cmov 指令处理 | 无法解析分支走向 | 手动拆分双执行状态精准捕获两条路径 |
| 人工介入程度 | 大量人工修正 CFG、逐块甄别 | 全程脚本自动化,仅配置样本路径与入口地址 |
| 无效块清理 | 人工标记后 NOP 填充 | 脚本自动统计地址区间批量清零 |
| 适配样本场景 | 简单 CTF 基础 OLLVM 题目 | 商业软件加固二次修改定制 OLLVM 防护样本 |
| 执行耗时 | 中等样本 1~3 小时人工梳理 | 脚本全自动运行 5~15 分钟出完整结果 |
四、实操踩坑要点总结
1、地址偏移-6并非固定数值,不同编译架构、指令长度环境下会出现解码异常,运行报错时打印 Capstone 汇编输出,微调偏移数值即可适配; 2、Hook 分发器后必须执行 unhook 操作,程序循环执行时重复命中 Hook 会造成死循环卡死; 3、筛选真实块时不能遗漏序言块,序言承载变量初始化逻辑,剔除后程序 Patch 后运行逻辑错乱; 4、处理 cmov 指令时必须手动跳过当前指令指针,防止 Angr 重复解析同一条条件传送指令; 5、ret 块回溯过程中过滤 4 字节单指令中转块,避免将无效跳转中转块误判定为函数结束块; 6、样本加载至 Angr 时关闭自动加载系统库auto_load_libs=False,避免外部库符号干扰本机符号执行路径。
五、整体方案结论
这套以 "IDA 静态初筛真实块 + Angr 动态符号执行溯源路径" 组合的解法,彻底解决静态逆向面对变异 OLLVM 的天然短板,依托 BFS 精准锁定循环架构,针对性破解 cmov 隐性分支这类静态分析盲区,整套逻辑具备极强通用性,仅需要微调少量地址偏移、过滤阈值参数,即可适配绝大多数经过二次改造的 OLLVM 控制流混淆样本,从人工逆向拆解转化为标准化自动化逆向流水线,大幅缩减逆向人员处理加固样本的时间成本,无需吃透每一处混淆细节,依靠标准化流程即可完成控制流还原,不管是 CTF 逆向解题还是商业加固程序脱混淆分析都具备很高落地价值。
CTA
将本文整套脚本根据自身目标样本架构、编译环境完成参数适配调试,代入手中带 OLLVM 防护的测试样本完整跑通自动化解混淆流程,记录执行过程中报错信息,对照文中踩坑要点逐一修正,形成专属自用的 OLLVM 一键去混淆工具包,后续遇到同类防护样本直接复用这套工作流高效拆解分析。