ollvm是一个基于llvm的开源项目,利用llvm会生成IR中间代码并通过pass进行优化的特点,通过增加Pass来对代码进行优化.但这种优化是为了让代码更加复杂,达到混淆的目的.主要有以下3种混淆手段:
- 指令替换(Substitution)
- 虚假控制流(Bogus Control Flow)
- 控制流平坦化(Control Flow Flattening)
下面按照官方给的例子,来进行ollvm特性的学习.
https://github.com/obfuscator-llvm/obfuscator/wiki/Features
指令替换(sub)
原理:将一条运算指令,替换为多条等价运算指令.
测试代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
|
//luoTst.c
#include <stdio.h>
int main(int argc, char** argv) {
int n = argc + 2;
if(n >= 0){
printf("hello ollvm\r\n");
}
else{
printf("hello World\r\n");
}
return 0;
}
|
使用下述命令进行编译,会等价替换1次
1
|
clang -mllvm -sub luoTst.c -o luoTst_sub
|

使用下述命令进行编译,会等价替换3次
1
|
clang -mllvm -sub -mllvm -sub_loop=3 luoTst.c -o luoTst_sub3
|

虚假控制流(bcf)
原理:克隆一个真实块,并随机替换其中的一些指令,然后用一个永远为真的条件建立一个分支,克隆后的块是不会被执行的.
测试代码如下:
1
2
3
4
5
6
7
8
9
10
|
//luoTst.c
#include <stdlib.h>
int main(int argc, char** argv) {
int a = atoi(argv[1]);
if(a == 0)
return 1;
else
return 10;
return 0;
}
|
上述代码转成中间语言表示如下:

经过虚假控制流Pass处理后,流程可能如下:

这里我们使用如下命令使用进行编译,在IDA中看下代码.
1
|
clang -mllvm -bcf luoTst.c -o luoTst_bcf
|

控制流平坦化(fla)
原理:先实现一个永真循环,然后在这个循环中放入switch语句,将代码中除了开始块的所有BasicBlock放入这个switch语句的不同case中,通过修改switch的条件,来实现BasicBlock之间的跳转.
测试代码如下:
1
2
3
4
5
6
7
8
9
10
|
//luoTst.c
#include <stdlib.h>
int main(int argc, char** argv) {
int a = atoi(argv[1]);
if(a == 0)
return 1;
else
return 10;
return 0;
}
|
上述代码经过控制流平坦化Pass处理后,代码会转成如下所示:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
#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;
}
|
未经过处理前的流程如下:

经过处理后的流程如下:

接下来我们使用如下命令进行编译,在IDA中体会下:
1
|
clang -mllvm -fla luoTst.c -o luoTst_fla
|


上面的编译选项比较简单,生成的代码,从IDA反汇编结果来看好像还可以,下面使用如下命令进行编译,来体会下控制流平坦化的强大.
1
|
clang -mllvm -fla -mllvm -split -mllvm -split_num=10 luoTst.c -o luoTst_fla_split10
|

函数注解
可以使用注解的方式对指定函数进行指定的混淆方式.
测试代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
//luoTst.c
#include <stdlib.h>
#include <stdio.h>
int fun1(int a, int b) __attribute((__annotate__(("fla"))));
int fun2(int a, int b) __attribute((__annotate__(("nofla"))));
int main(int argc, char** argv) __attribute((__annotate__(("bcf"))));
int fun1(int a, int b){
if(a + b > 10){
return 10;
}else{
return 100;
}
}
int fun2(int a, int b){
if(a - b > 10){
return 5;
}else{
return 50;
}
}
int main(int argc, char** argv) {
if(argc > 2){
printf("hello world\n");
}else{
printf("hello ollvm\n");
}
printf("fun1:%d\n", fun1(argc, 6));
printf("fun2:%d\n", fun2(argc, 8));
return 0;
}
|
使用如下命令进行编译即可:
1
|
clang luoTst.c -o luoTst
|
参考链接
obfuscator