原理
OLLVM提供三种混淆机制:
- 控制流平坦化(control flow flattening)
- 虚假控制流程(instruction substitution)
- 指令替换(bogus control flow)
1 控制流平坦化
基本思想是让所有的基本块都有共同的前驱块,而该前驱块进行基本块的分发,分发用switch语句,依赖于switch变量进行分发。先为每个基本块进行值编号,每个基本块就是一个case块,如果基本块有后继块,就替换每个基本块的后继块,新的后继块更新switch变量为后继块的值,然后跳转到switch开始分发处,初始switch变量为入口entry块的值。例如下图是正常的执行流程
经过控制流平坦化后的执行流程就如下图
对应ida的cfg会显示为这种形式
反编译代码会显示为众多while循环
#include <stdlib.h>
int main(int argc, char** argv) {
int a = atoi(argv[1]);
int b = 0;
while(1) {
switch(b) {
case 0:
if(a == 0)
b = 1;
else
b = 2;
break;
case 1:
return 1;
case 2:
return 10;
default:
break;
}
}
return 0;
}
llvm-obfuscator
使用控制流平坦化将代码逻辑顺序切断,仅通过对于单一代码段的唯一前趋和唯一后继形成逻辑顺序,提高逆向分析成本
2 虚假控制流程
通过在当前代码块之前添加一个判断代码块来改变cfg,通过永真或永假判断后使得直接跳转到原代码块,并将整个代码内容被随机生成的垃圾指令填满,增加逆向成本
图中常量恒为零,恒为假
指令替换
使用复杂的指令代替简单的二元运算(如加减法,或,异或)这种混淆比较简单,可以通过简单的优化消除混淆的影响,而且目前仅支持整数上的运算
e.g.
加法
· a = b - (-c)
%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = sub i32 0, %1
%3 = sub nsw i32 %0, %2
· a = -(-b + (-c))
%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = sub i32 0, %0
%3 = sub i32 0, %1
%4 = add i32 %2, %3
%5 = sub nsw i32 0, %4
· r = rand (); a = b + r; a = a + c; a = a - r
%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = add i32 %0, 1107414009
%3 = add i32 %2, %1
%4 = sub nsw i32 %3, 1107414009
· r = rand (); a = b - r; a = a + b; a = a + r
%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = sub i32 %0, 1108523271
%3 = add i32 %2, %1
%4 = add nsw i32 %3, 1108523271
Subtraction
· a = b + (-c)
%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = sub i32 0, %1
%3 = add nsw i32 %0, %2
· r = rand (); a = b + r; a = a - c; a = a - r
%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = add i32 %0, 1571022666
%3 = sub i32 %2, %1
%4 = sub nsw i32 %3, 1571022666
· r = rand (); a = b - r; a = a - c; a = a + r
%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = sub i32 %0, 1057193181
%3 = sub i32 %2, %1
%4 = add nsw i32 %3, 1057193181
逻辑与
· a = b & c => a = (b ^ ~c) & b
%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = xor i32 %1, -1
%3 = xor i32 %0, %2
%4 = and i32 %3, %0
逻辑或
· a = b | c => a = (b & c) | (b ^ c)
%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = and i32 %0, %1
%3 = xor i32 %0, %1
%4 = or i32 %2, %3
异或
· a = a ^ b => a = (~a & b) | (a & ~b)
%0 = load i32* %a, align 4
%1 = load i32* %b, align 4
%2 = xor i32 %0, -1
%3 = and i32 %1, %2
%4 = xor i32 %1, -1
%5 = and i32 %0, %4
%6 = or i32 %3, %5
应用
正向
github项目
官方Wiki安装使用介绍很全面
$ git clone -b llvm-4.0 https://github.com/obfuscator-llvm/obfuscator.git
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release ../obfuscator/
$ make -j7
-fla 控制流平坦化(control flow flattening pass)
-sub 指令替换(instruction substitution)
-bcf 虚假控制流程(bogus control flow)
// 通过参数调用参数实现添加混淆
e.g.$ path_to_the/build/bin/clang test.c -o test -mllvm -sub
// 可以重复调用参数添加多种混淆
e.g.$ path_to_the/build/bin/clang test -o test -mllvm -sub -mllvm -fla
逆向
项目依赖angr环境,安装时需要创建虚拟环境,原因是angr库可能对其依赖有所影响,可能对其他项目造成影响。
若发生module 'keystone' has no attribute 'KS_ARCH_X86'
报错
使用命令sudo apt-get uninstall keystone
解决
z3库发生类似错误也可这样解决,原因可能是本机安装的keystone与angr依赖有冲突
使用方法
**Bogus_control_flow**
(angr-dev) <path>/deflat/bogus_control_flow$ python3 debogus.py -f samples/bin
**Flat_control_flow**
(angr-dev) <path>/deflat/flat_control_flow$ python3 deflat.py -f samples/bin
生成文件保存为file_recoverd
项目脚本使用前,需将脚本文件中的sys扩展路径写为am_graph.py文件(在项目根目录)的路径