原文鏈接:http://fighting300.com....
OLLVM簡介
OLLVM(Obfuscator-LLVM)是瑞士西北應(yīng)用科技大學(xué)安全實(shí)驗(yàn)室于2010年6月份發(fā)起的一個(gè)項(xiàng)目,該項(xiàng)目旨在提供一套開源的針對(duì)LLVM的代碼混淆工具庭敦,以增加對(duì)逆向工程的難度唧取。后期轉(zhuǎn)向商業(yè)項(xiàng)目strong.protect平酿。目前氧吐,OLLVM已經(jīng)支持LLVM-4.0版本雪情。
LLVM是一個(gè)優(yōu)秀的編譯器框架剧蚣,它也采用經(jīng)典的三段式設(shè)計(jì)趁窃。前端可以使用不同的編譯工具對(duì)代碼文件做詞法分析以形成抽象語法樹AST崇渗,然后將分析好的代碼轉(zhuǎn)換成LLVM的中間表示IR(intermediate representation)字逗;中間部分的優(yōu)化器只對(duì)中間表示IR操作,通過一系列的Pass對(duì)IR做優(yōu)化宅广;后端負(fù)責(zé)將優(yōu)化好的IR解釋成對(duì)應(yīng)平臺(tái)的機(jī)器碼葫掉。LLVM的優(yōu)點(diǎn)在于,中間表示IR代碼編寫良好跟狱,而且不同的前端語言最終都轉(zhuǎn)換成同一種的IR挖息。
LLVM IR 是LLVM的中間表示,優(yōu)化器就是對(duì)IR進(jìn)行操作的兽肤,具體的優(yōu)化操作由一些列的Pass來完成套腹,當(dāng)前端生成初級(jí)IR后,Pass會(huì)依次對(duì)IR進(jìn)行處理资铡,最終生成后端可用的IR电禀。下圖可以說明這個(gè)過程:
OLLVM的混淆操作就是在中間表示IR層,通過編寫Pass來混淆IR笤休,然后后端依據(jù)IR來生成的目標(biāo)代碼也就被混淆了尖飞。得益于LLVM的設(shè)計(jì),OLLVM適用LLVM支持的所有語言(C,C++,Objective-C,Ada,Fortran)和目標(biāo)平臺(tái)(x86,x86-64,PowerPC,PowerPC-64, ARM, Thumb, SPARC, Alpha, CellSPU, MIPS, MSP430, SystemZ, 和 XCore)
OLLVM iOS編譯環(huán)境搭建
以下店雅,介紹OLLVM iOS環(huán)境的插件創(chuàng)建過程政基。
首先下載源碼,編譯OLLVM混淆器闹啦,這里采用LLVM的版本是4.0沮明。下載編譯過程如下:
$ 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
下載的源碼里已經(jīng)包含了LLVM和Clang,編譯完成后窍奋,編譯好的二進(jìn)制程序都存在在build/bin目錄下荐健。
依據(jù)github上的wiki,bin目錄下編譯好的工具鏈可以直接用來編譯混淆linux下的程序琳袄,就像我們常用的gcc那樣江场。若想使用OLLVM來混淆iOS程序,還需將bin目錄下的工具鏈整合進(jìn)Xcode插件中窖逗,具體步驟如下址否。
配置Xcode--新建Obfuscator插件
$ cd /Applications/Xcode.app/Contents/PlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library/Xcode/Plug-ins/
$ sudo cp -r Clang\ LLVM\ 1.0.xcplugin/ Obfuscator.xcplugin
$ cd Obfuscator.xcplugin/Contents/
$ sudo plutil -convert xml1 Info.plist
$ sudo vim Info.plist
修改Info.plist中的對(duì)應(yīng)內(nèi)容:
<string>com.apple.compilers.clang</string> -> <string>com.apple.compilers.obfuscator</string>
<string>Clang LLVM 1.0 Compiler Xcode Plug-in</string> -> <string>Obfuscator Xcode Plug-in</string>
修改Obfuscator.xcspec文件
$ sudo plutil -convert binary1 Info.plist
$ cd Resources/
$ sudo mv Clang\ LLVM\ 1.0.xcspec Obfuscator.xcspec
$ sudo vim Obfuscator.xcspec
修改ExecPath的地址為當(dāng)前build/bin的地址(!重點(diǎn))
Identifier = "com.apple.compilers.llvm.clang.1_0"; -> Identifier = "com.apple.compilers.llvm.obfuscator.4_0";
Name = "Apple LLVM 8.0"; -> Name = "Obfuscator 4.0";
Description = "Apple LLVM 8.0 compiler"; -> Description = "Obfuscator 4.0";
Vendor = Apple; -> Vendor = HEIG-VD;
Version = "7.0"; -> Version = "4.0";
ExecPath = "clang"; -> ExecPath = "/path/to/obfuscator_bin/clang";
修改 Obfuscator 4.0 Strings
$ cd English.lproj/
$ sudo mv Apple\ LLVM\ 8.0.strings "Obfuscator 4.0.strings"
$ sudo plutil -convert xml1 Obfuscator\ 4.0.strings
$ sudo vim Obfuscator\ 4.0.strings
"Description" = "Apple LLVM 8.0 Compiler"; -> "Description" = "Obfuscator 4.0";
"Name" = "Apple LLVM 8.0"; -> "Name" = "Obfuscator 4.0";
"Vendor" = "Apple"; -> "Vendor" = "HEIG-VD";
"Version" = "8.0"; -> "Version" = "4.0";
sudo plutil -convert binary1 Obfuscator\ 4.0.strings
現(xiàn)在,你可以打開Xcode在項(xiàng)目配置里來選擇新的編譯器碎紊,并且可以在C Flags或C++ Flags下添加混淆標(biāo)簽佑附。
這樣配置完成后用含,就可以編譯項(xiàng)目生成混淆后的程序。
ollvm混淆使用
接下來使用以下demo介紹混淆功能的具體使用帮匾。
int main(){
int a = 1;
int b = 0;
int c = 0;
if(a > b){
a = 100;
b = 50;
c = a - b;
int d = a + b;
int e = a & b;
int f = a ^ b;
printf("c = %d\n",c);
printf("d = %d\n",d);
printf("e = %d\n",e);
printf("f = %d\n",f);
printf("a > b\n");
}else{
printf("a < b\n");
}
return 0;
}
OLLVM默認(rèn)支持-fla -sub -bcf 三個(gè)混淆參數(shù)啄骇,這三個(gè)參數(shù)可以單獨(dú)使用,也可以配合著使用瘟斜。-fla 參數(shù)表示使用控制流平展(Control Flow Flattening)模式缸夹, -sub 參數(shù)表示使用指令替換(Instructions Substitution)模式, -bcf 參數(shù)表示使用控制流偽造(Bogus Control Flow)模式螺句。
Instructions Substitution
指令替換模式主要是將正常的運(yùn)算操作(+虽惭,-,&蛇尚,|等)替換成功能相等但表述更復(fù)雜的形式芽唇。比如,對(duì)于表達(dá)式 a = b + c取劫,它的等價(jià)式可以有 a = – ( -b – c), a = b – (-c) 或 a = -(-b) + c 等匆笤,原表達(dá)式可以替換成任意相等式,或者通過隨機(jī)數(shù)在多個(gè)相等式中做選擇谱邪。SUB模式目前只支持整數(shù)運(yùn)算操作炮捧,支持 + , – , & , | 和 ^ 操作,還是比較局限的惦银。編譯時(shí)咆课,使用 -mllvm -sub 參數(shù)即可。
-mllvm -sub: 啟用instructions substitution
-mllvm -sub_loop=3: 對(duì)每個(gè)函數(shù)混淆3次扯俱,默認(rèn)1詞
Control Flow Flattening
控制流平展模式可以完全改變程序原本的控制流圖书蚪。如下示例代碼是簡單的if-else分支語句,正常編譯后其控制流圖在IDA中下圖所示迅栅,是正常的if-else分支殊校,使用 -mllvm -fla參數(shù)混淆后,在IDA中顯示的控制流圖如下:
經(jīng)FLA模式混淆后库继,程序的執(zhí)行流程已經(jīng)被打亂箩艺,出現(xiàn)許多代碼分支。通過仔細(xì)對(duì)比程序混淆前后宪萄,可以發(fā)現(xiàn)上圖著色區(qū)域是相對(duì)應(yīng)的,也就是說榨惰,F(xiàn)LA模式只去更改代碼分支拜英,而不會(huì)對(duì)單個(gè)代碼塊做處理。
-mllvm -fla: 啟用control flow flattening
-mllvm -split: 啟用block切分琅催,提升平展程度
-mllvm -split_num=3: 對(duì)每個(gè)block混淆3次居凶,默認(rèn)1詞
Bogus Control Flow
控制流偽造模式也是對(duì)程序的控制流做操作虫给,不同的是,BCF模式會(huì)在原代碼塊的前后隨機(jī)插入新的代碼塊侠碧,新插入的代碼塊不是確定的抹估,然后新代碼塊再通過條件判斷跳轉(zhuǎn)到原代碼塊中。更要命地是弄兜,原代碼塊可能會(huì)被克隆并插入隨機(jī)的垃圾指令药蜻。這么多不確定性,就導(dǎo)致對(duì)同一份代碼多次做BCF模式的混淆時(shí)替饿,得到的是不同的混淆效果语泽。可見视卢,BCF混淆模式還是很強(qiáng)大的踱卵,不同于FLA那種較確定的混淆模式。使用BCF模式編譯時(shí)配置參數(shù) -mllvm -bcf即可据过,此外惋砂,BCF模式還支持其它幾個(gè)參數(shù),下面參數(shù)與-mllvm -bcf參數(shù)配合使用绳锅。
-mllvm -bcf: 啟用 bogus control flow
-mllvm -bcf_loop=3: 對(duì)一個(gè)函數(shù)混淆3次班利,默認(rèn)1次
-mllvm -bcf_prob=40: 代碼塊被混淆的概率是40%,默認(rèn)30%
如上圖榨呆,下面兩個(gè)著色的代碼塊就是有上面兩個(gè)代碼塊克隆而來罗标,而且其中被插入了一些垃圾指令,類似于這樣:
當(dāng)然积蜻,上述介紹的三種混淆模式可以搭配使用闯割,同時(shí)使用三個(gè)參數(shù)混淆后,原本簡單的if-else分支代碼將會(huì)變得異常復(fù)雜竿拆,這無疑給逆向分析增加巨大的難度宙拉。
Functions annotations
有的時(shí)候,由于效率或其他原因的考慮丙笋,我們只想給指定的函數(shù)混淆或不混淆該函數(shù)谢澈,OLLVM也提供了對(duì)這一特性的支持,你只需要給對(duì)應(yīng)的函數(shù)添加attributes即可御板。比如锥忿,想對(duì)函數(shù)foo()使用fla混淆,只需要給函數(shù)foo()增加fla屬性即可怠肋。
int foo() __attribute((__annotate__(("fla"))));
int foo() {
return 2;
}
你可以給函數(shù)添加一個(gè)或多個(gè)注釋敬鬓。如果你不想混淆某個(gè)函數(shù),你可以使用否定標(biāo)簽。例如如果不想對(duì)func()函數(shù)使用bcf屬性钉答,那標(biāo)記為“nobcf”即可础芍。
錯(cuò)誤處理
1.編譯時(shí)報(bào)錯(cuò),提示信息如下:
clang-3.6: error: unknown argument: '-gmodules'
clang-3.6: error: unknown argument: '-fembed-bitcode-marker'
Command /Users/dream/ollvm/build/bin/clang failed with exit code 1
在Build Settings中搜索并修改:
-gmodules: Obfuscator 4.0 - Code Generation: Generate Debug Symbols: 原來yes数尿,改成no
-fembed-bitcode-marker: Build Option: Enable Bitcode: 原來yes仑性,改成no
你可以在該git地址下找到最新的插件和build編譯器文件,該編譯器所使用的Xcode版本是8.3.3右蹦。