OLLVM特性、使用原理
一、OLLVM特性
目前ollvm支持的特性有以下幾種:
- 指令替換 -mllvm -sub
- 虛假控制流 -mllvm -bcf
- 打平控制流 -mllvm -fla
- 函數(Funtions)注解
二、指令替換
所謂指令替換僅僅是對標準二進制運算(比如加、減、位運算)使用更復雜的指令序列進行功能等價替換,當存在多種等價指令序列時,隨機選擇一種。
這種混淆并不直截了當而且并沒有增加更多的安全性,因為通過重新優化可以很容易地把替換的等價指令序列變回去。然而,提供一個偽隨機數,就可以使指令替換給二進制文件帶來多樣性。
目前,只有在整數上的操作可用,因為在浮點數上的運算替換會帶來四舍五入的錯誤以及不必要的數值不準確。
可用選項有
- -mllvm -sub:激活指令替換趟(pass)
- -mllvm -sub_loop=3:如果激活了指令替換,使用這個選項在一個函數中應用3次指令替換。默認應用1次。
如何實現?
- 加法
(1)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
(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
(3)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
(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 = sub i32 %0, 1108523271
%3 = add i32 %2, %1
%4 = add nsw i32 %3, 1108523271
2. 減法
(1)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
(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
(3)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
3. 按位與
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
4. 按位或
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
5. 按位異或
a = b ^ c => a = (~b & c) | (b & ~c)
%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
三、虛假控制流
這種方式通過在當前基本塊之前添加一個基本塊,來修改函數調用流程圖。新添加的基本塊包含一個不透明的謂語,然后再跳轉到原來的基本塊。
原始的基本塊會被克隆,并充滿了隨機的垃圾指令。
可用選項有:
(1)-mllvm -bcf:激活虛假控制流趟(pass)
(2)-mllvm -bcf_loop=3:如果虛假控制流被激活,在一個函數中應用三次。默認應用一次。
(3)-mllvm -bcf_prob=40:如果虛假控制流趟被激活,一個基本塊將會以40%的概率被混淆。默認30%。
一個例子:
下面的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;
}
會被翻譯成這樣的中間代碼:

虛假控制流的趟結束之后,我們或許會得到下面的控制流圖:

四、控制流打平
控制流打平的目的是將程序的控制流圖完全地扁平化。
可用選項:
(1)-mllvm -fla:激活控制流打平
(2)-mllvm -split:激活基本塊劃分。一起使用時能提高打平能力。
(3)-mllvm -split_num=3:如果激活控制流打平,對每一個基本塊應用三次控制流打平。默認使用1次。
考慮下面的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;
}
經過控制流打平后,這段代碼代碼變成了這樣:
#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;
}
所有的基本塊都被分開且放到了無限循環中,程序流變成了由switch和變量b控制。在打平控制流之前的控制流是這樣的:

打平之后的控制流是這樣的:

五、函數注解
使用注解可以定制哪個函數參與混淆。


浙公網安備 33010602011771號