OLLVM是一款是由瑞士西北科技大学开发的一套开源的针对LLVM的代码混淆工具,旨在加强逆向的难度,整个项目包含数个独立功能的LLVM Pass,每个Pass会对应实现一种特定的混淆方式,通过这些Pass可以改变源程序的CFG和源程序的结构:
LLVM与OLLVM最大的区别在于混淆Pass的不同,混淆Pass作用于LLVM的IR中间语言,通过Pass混淆IR,最后后端依据IR生成的目标语言也会得到相应的混淆。得益于LLVM的三段式结构,即前端对代码进行语法分析词法分析形成AST并转换为中间IR语言,一系列优化Pass对IR中间语言进行优化操作,或混淆,或分析,或改变IR的操作码等等。最终在后端解释为相应平台的机器码。
OLLVM的三大功能
- Instructions Substitution(指令替换):随机选择一种功能上等效但更复杂的指令序列替换标准二元运算符,编译选项:-mllvm -sub
- 实现,以
a = b + c
为例: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
- 实现,以
- Bogus Control Flow(混淆控制流):在当前基本块之前添加基本块来修改函数调用图,编译选项:-mllvm -bcf
-
实现:以下述代码为例:
#include <stdlib.h> int main(int argc, char** argv) { int a = atoi(argv[1]); if(a == 0) return 1; else return 10; return 0; }
对应的LLVM IR:
经过混淆控制流后:
-
- Control Flow Flattening(控制流平展):将控制流展平,比如
if...else
变为switch..case..
-
实现,依旧是以下述代码为例:
#include <stdlib.h> int main(int argc, char** argv) { int a = atoi(argv[1]); if(a == 0) return 1; else return 10; return 0; }
对应的控制流图为:
控制流平展会将代码变为类似于下面这种:#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; }
对应的控制流图为:
-