读完本文,你将获得:
能在 IDA 里一眼认出 Control Flow Flattening、Bogus Control Flow 和 Instruction Substitution 三种 OLLVM 混淆的视觉特征 理解 OLLVM 如何嵌入 LLVM 编译管线,以及每个 pass 在 IR 层面做了什么 掌握从 Frida 动态 trace 到 angr 符号执行再到 CFG 手动恢复的完整去混淆工作流 经历一个真实案例中"IDA 看到 400 个基本块、真正执行的只有 27 个"的完整分析过程 理解为什么 OLLVM 在 AI 时代正在从"有效保护"滑向"增加成本但不改变结局" 〇、摘要 🧑🔬 笔者最近在分析一个国内头部电商 App 的签名 SO 时,IDA 打开目标函数,CFG 窗口画出来的图像一块被碾平的披萨饼——400 多个基本块,全部通过一个巨型 switch 相互连接,没有任何可读的逻辑结构。这是典型的 OLLVM Control Flow Flattening,笔者在过去两年的 Android 逆向中至少遇到过十几次,但每次都在不同环节卡住。
这篇文章不是 OLLVM 的百科全书。笔者的目标是把自己在实战中积累的工程经验整理成一条可复现的路线:从识别混淆类型,到选择去混淆策略,到工具链搭建,到最终恢复出可读的控制流。过程中踩过的坑和失败的尝试一样会记录下来。
核心贡献:
三大 pass 的 IDA 视觉指纹库 🧑🔬:总结了 CFF、BCF、Instruction Substitution 在 IDA CFG/伪代码中的 12 个可识别特征,附实际截图级描述 从 Frida trace 到 CFG 恢复的完整工作流 🔬:以某电商 App 的 libsign.so 为案例,记录了从 0 到可读伪代码的全过程 基于 angr 的半自动 CFF 去平坦化 🤖🧑🔬:实现了一个 600 行的 Python 脚本,在 5 个不同目标上成功恢复了 CFF,失败了 2 个(原因分析见 §6.5) opaque predicate 的 7 种识别模式 🧑🔬:从 BCF 的死代码中提取了 7 类 opaque predicate 模板,其中 2 类是 MBA 变种 去混淆工具链横向对比 🔬:对比了 D-810、GAMBA、Triton、angr、手动五种方案在 4 个目标上的表现 OLLVM 在 AI 时代的失效曲线分析 🧑🔬:基于本文实验数据,评估了 LLM 辅助去混淆对各保护层的实际影响 防御方改进提案 🧑🔬:从保护方视角提出了 6 条 P0-P3 级改进建议 Research Evidence Environment Item Detail Device Pixel 7 Pro (cheetah), rooted via Magisk 27.0 OS Android 14 (UP1A.231005.007) Target SO libsign.so v8.2.3, arm64-v8a, 4.7 MB SO SHA256 7f3a2b1c4d5e******9a8b7c6d5e4f3a (partial) IDA 9.0 SP1 + Hex-Rays ARM64 Frida 16.5.9, frida-server 16.5.9 angr 9.2.107 Unicorn 2.1.1 Ghidra 11.2 (辅助交叉验证) Python 3.11.8, z3-solver 4.13.0 分析周期 2026-05-18 ~ 2026-06-03 (约 3 周) Hypothesis ID 假设内容 章节 结果 H1 目标函数使用标准 OLLVM CFF,state variable 为单一 32-bit 整数 §6.1 ✓ 确认 — switch 变量为 w8,取值 47 种 H2 通过 Frida trace 收集的 state 序列可以直接恢复原始 CFG §6.2 ✗ 部分失败 — 覆盖率仅 68%,路径依赖输入 H3 angr 符号执行可以枚举所有 state 转移,补全动态 trace 的缺口 §6.3 ✓ 确认 — 47 个 state 全部覆盖,但耗时 23 分钟 H4 BCF 插入的 opaque predicate 全部基于 (x * (x - 1)) % 2 == 0 模板 §4.2 ✗ 证伪 — 发现 7 种模板,含 2 种 MBA 变种 H5 D-810 可以一键去除所有 BCF dead code §7.1 ✗ 部分失败 — 标准模板 95% 去除,MBA 变种 0% H6 Instruction Substitution 不影响仿真正确性,可以忽略 §4.3 ✓ 确认 — Unicorn trace 语义等价 H7 字符串加密使用固定 XOR key,可全局批量解密 §5.1 ✗ 证伪 — 每个函数使用不同 key,需逐函数处理 Experiments ID 实验 验证假设 结果 关键证据 E01 IDA CFG 统计分析 H1 ✓ PASS 47 个 case,1 个 switch 变量 w8 E02 Frida state trace (100 次调用) H2 ✗ PARTIAL 32/47 states 覆盖,15 个未触发 E03 angr symbolic exploration H3 ✓ PASS 47/47 全覆盖,23 min,peak 4.2 GB E04 BCF opaque predicate 分类 H4 ✗ FAIL 7 种模板,非单一类型 E05 D-810 自动去 BCF H5 ✗ PARTIAL 标准模板去除 95%,MBA 残留 E06 Unicorn 全路径仿真 H6 ✓ PASS 输出与真机一致 E07 字符串解密 key 分析 H7 ✗ FAIL 12 个函数,12 个不同 key E08 CFF 去平坦化脚本 (5 目标) — ✓ 5/7 5 成功 2 失败 (§6.5) E09 恢复后 CFG vs 真机 trace 验证 — ✓ PASS 27 个真实基本块,执行顺序一致 一、路线总览 这一节给出完整的分析路线图。笔者的经验是:面对 OLLVM 保护的二进制,最大的陷阱不是技术难度,而是在错误的层次上花时间。先花 30 分钟做识别和分类,能省下 3 天的无效逆向。
...