移动端安全 OLLVM
字数 2359 2025-08-22 12:23:30

OLLVM移植与使用详解

1. OLLVM简介

OLLVM(Obfuscator-LLVM)是一个基于LLVM框架的代码混淆工具,主要用于增强代码的安全性,防止逆向工程分析。它提供了三种主要的混淆功能:

  1. 指令替换(Instruction Substitution)
  2. 虚假控制流(Bogus Control Flow)
  3. 控制流平坦化(Control Flow Flattening)

2. OLLVM移植到LLVM-14.0.6

2.1 移植步骤

  1. 获取OLLVM项目

    git clone https://github.com/buffcow/ollvm-project
    
  2. 添加头文件

    • llvm/include/llvm/Transforms文件夹下创建Obfuscation目录
    • 按照[commit](llvm support obfuscator)中的内容逐个添加头文件
  3. 添加源文件

    • llvm/lib/Transforms文件夹下创建Obfuscation目录
    • 按照[commit](llvm support obfuscator)中的内容逐个添加源文件
  4. 修改支持文件及配置

    • 按照[commit](llvm support obfuscator)对LLVM项目中相关文件进行补充或修改

2.2 编译OLLVM

mkdir build
sudo cmake -S llvm -B build -G Ninja -DLLVM_ENABLE_PROJECTS="clang" -DCMAKE_BUILD_TYPE=Release -DLLVM_INCLUDE_TESTS=OFF -DLLVM_ENABLE_NEW_PASS_MANAGER=OFF
sudo cmake --build build -j4

编译完成后,可在build/bin文件夹中查看生成的工具。

3. OLLVM混淆功能详解

3.1 指令替换(Instruction Substitution)

功能:随机选择一种功能上等效但更复杂的指令序列替换标准二元运算符。

编译选项

  • -mllvm -sub:激活指令替换操作
  • -mllvm -sub_loop=3:在函数上应用3次,默认值为1

替换规则示例

  1. 算术运算:

    • a = b + c 替换为:
      a = b - (-c)
      // 或
      a = -(-b + (-c))
      // 或
      r = rand(); a = b + r; a = a + c; a = a - r
      // 或
      r = rand(); a = b - r; a = a + b; a = a + r
      
    • a = b - c 替换为:
      a = -(-b + c)
      // 或
      r = rand(); a = b + r; a = a - c; a = a - r
      // 或
      r = rand(); a = b - r; a = a - c; a = a + r
      
  2. 逻辑运算:

    • a = b & c 替换为 a = (b ^ ~c) & b
    • a = b | c 替换为 a = (b & c) | (b ^ c)
    • a = a ^ b 替换为 a = (~a & b) | (a & ~b)

源码分析

  • Substitution类继承自LLVM中的FunctionPass
  • 覆盖runOnFunction实现混淆逻辑
  • toObfuscate函数根据传入的flag和其他参数决定是否混淆函数
  • substitute方法执行实际的混淆逻辑

3.2 虚假控制流(Bogus Control Flow)

功能:在程序的控制流图(CFG)中引入虚假的分支和基本块。

编译选项

  • -mllvm -bcf:激活虚假控制流
  • -mllvm -bcf_loop=3:对基本块混淆操作连续进行3次
  • -mllvm -bcf_prob=40:操作发生的概率为40%

示例

#include <stdlib.h>
int main(int argc, char **argv) {
    int a = atoi(argv[1]);
    if (a == 0) return 1;
    else return 10;
    return 0;
}

源码分析

  • BogusControlFlow类继承自FunctionPass
  • bogus函数:
    • 将函数的所有basicblock存放到list容器
    • 使用while循环调用addBogusFlow函数对选中的basicblock增加虚假控制流
  • addBogusFlow函数:
    • 使用getFirstNonPHIOrDbgOrLifetime找到第一个有效指令地址
    • 使用splitBasicBlock将一个basicblock一分为二
    • 使用createAlteredBasicBlock拷贝生成"altered basicblock"
    • 设置跳转条件,创建分支跳转指令
  • doF函数:
    • 遍历Module内的所有指令
    • 将所有的FCMP_TRUE分支指令替换为永真式

3.3 控制流平坦化(Control Flow Flattening)

功能:把程序原有逻辑转化成多个case-swich的扁平状结构。

编译选项

  • -mllvm -fla:激活控制流平坦化功能
  • -mllvm -split:激活基本块分裂
  • -mllvm -split_num=3:使每个基本块上分裂3次

实现原理

  1. 创建循环入口基本块(loopEntry)和循环出口基本块(loopEnd)
  2. 创建switch-default基本块(swDefault)
  3. 创建switch指令,根据条件决定跳转方向
  4. 将函数原有基本块添加到switch-case语句中
  5. 修改基本块之间的跳转关系

4. OLLVM移植到NDK

4.1 移植步骤

  1. 覆盖NDK目录

    • 将LLVM中的binlibinclude目录覆盖NDK的toolchains/llvm/prebuilt/linux-86_64/目录下对应目录
  2. 覆盖clang目录

    • toolchains/llvm/prebuilt/linux-86_64/lib64目录下的clang文件夹覆盖到toolchains/llvm/prebuilt/linux-86_64/lib目录下

4.2 CMake配置

cpp目录下的CMakeLists.txt中添加混淆配置:

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -mllvm -bcf -mllvm -bcf_loop=3 -mllvm -fla -mllvm -split -mllvm -split_num=3")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mllvm -bcf -mllvm -bcf_loop=3 -mllvm -fla -mllvm -split -mllvm -split_num=3")

5. LLVM Pass操作对象结构

OLLVM混淆操作主要针对以下LLVM IR结构:

  1. Module:对应C/C++文件
  2. Function:对应C/C++代码中的函数
  3. BasicBlock:每个函数被划分为若干基本块,一个block只有一个入口和一个出口
  4. Instruction:具体的指令

6. 总结

OLLVM提供了强大的代码混淆能力,通过指令替换、虚假控制流和控制流平坦化等技术,可以有效增加逆向工程的难度。移植到特定版本的LLVM和NDK需要仔细处理文件结构和编译配置。在实际应用中,可以根据安全需求选择适当的混淆选项和参数组合。

OLLVM移植与使用详解 1. OLLVM简介 OLLVM(Obfuscator-LLVM)是一个基于LLVM框架的代码混淆工具,主要用于增强代码的安全性,防止逆向工程分析。它提供了三种主要的混淆功能: 指令替换(Instruction Substitution) 虚假控制流(Bogus Control Flow) 控制流平坦化(Control Flow Flattening) 2. OLLVM移植到LLVM-14.0.6 2.1 移植步骤 获取OLLVM项目 : 添加头文件 : 在 llvm/include/llvm/Transforms 文件夹下创建 Obfuscation 目录 按照[ commit ](llvm support obfuscator)中的内容逐个添加头文件 添加源文件 : 在 llvm/lib/Transforms 文件夹下创建 Obfuscation 目录 按照[ commit ](llvm support obfuscator)中的内容逐个添加源文件 修改支持文件及配置 : 按照[ commit ](llvm support obfuscator)对LLVM项目中相关文件进行补充或修改 2.2 编译OLLVM 编译完成后,可在 build/bin 文件夹中查看生成的工具。 3. OLLVM混淆功能详解 3.1 指令替换(Instruction Substitution) 功能 :随机选择一种功能上等效但更复杂的指令序列替换标准二元运算符。 编译选项 : -mllvm -sub :激活指令替换操作 -mllvm -sub_loop=3 :在函数上应用3次,默认值为1 替换规则示例 : 算术运算: a = b + c 替换为: a = b - c 替换为: 逻辑运算: a = b & c 替换为 a = (b ^ ~c) & b a = b | c 替换为 a = (b & c) | (b ^ c) a = a ^ b 替换为 a = (~a & b) | (a & ~b) 源码分析 : Substitution 类继承自LLVM中的 FunctionPass 类 覆盖 runOnFunction 实现混淆逻辑 toObfuscate 函数根据传入的flag和其他参数决定是否混淆函数 substitute 方法执行实际的混淆逻辑 3.2 虚假控制流(Bogus Control Flow) 功能 :在程序的控制流图(CFG)中引入虚假的分支和基本块。 编译选项 : -mllvm -bcf :激活虚假控制流 -mllvm -bcf_loop=3 :对基本块混淆操作连续进行3次 -mllvm -bcf_prob=40 :操作发生的概率为40% 示例 : 源码分析 : BogusControlFlow 类继承自 FunctionPass bogus 函数: 将函数的所有basicblock存放到list容器 使用while循环调用 addBogusFlow 函数对选中的basicblock增加虚假控制流 addBogusFlow 函数: 使用 getFirstNonPHIOrDbgOrLifetime 找到第一个有效指令地址 使用 splitBasicBlock 将一个basicblock一分为二 使用 createAlteredBasicBlock 拷贝生成"altered basicblock" 设置跳转条件,创建分支跳转指令 doF 函数: 遍历Module内的所有指令 将所有的FCMP_ TRUE分支指令替换为永真式 3.3 控制流平坦化(Control Flow Flattening) 功能 :把程序原有逻辑转化成多个case-swich的扁平状结构。 编译选项 : -mllvm -fla :激活控制流平坦化功能 -mllvm -split :激活基本块分裂 -mllvm -split_num=3 :使每个基本块上分裂3次 实现原理 : 创建循环入口基本块(loopEntry)和循环出口基本块(loopEnd) 创建switch-default基本块(swDefault) 创建switch指令,根据条件决定跳转方向 将函数原有基本块添加到switch-case语句中 修改基本块之间的跳转关系 4. OLLVM移植到NDK 4.1 移植步骤 覆盖NDK目录 : 将LLVM中的 bin 、 lib 、 include 目录覆盖NDK的 toolchains/llvm/prebuilt/linux-86_64/ 目录下对应目录 覆盖clang目录 : 将 toolchains/llvm/prebuilt/linux-86_64/lib64 目录下的 clang 文件夹覆盖到 toolchains/llvm/prebuilt/linux-86_64/lib 目录下 4.2 CMake配置 在 cpp 目录下的 CMakeLists.txt 中添加混淆配置: 5. LLVM Pass操作对象结构 OLLVM混淆操作主要针对以下LLVM IR结构: Module :对应C/C++文件 Function :对应C/C++代码中的函数 BasicBlock :每个函数被划分为若干基本块,一个block只有一个入口和一个出口 Instruction :具体的指令 6. 总结 OLLVM提供了强大的代码混淆能力,通过指令替换、虚假控制流和控制流平坦化等技术,可以有效增加逆向工程的难度。移植到特定版本的LLVM和NDK需要仔细处理文件结构和编译配置。在实际应用中,可以根据安全需求选择适当的混淆选项和参数组合。