OLLVM 快速學(xué)習(xí)

近來(lái),ollvm在國(guó)內(nèi)移動(dòng)安全,尤其是安全加固上的使用越來(lái)越廣泛,ollvm的混淆和反混淆也被視為比較高等的知識(shí)之一,讓很多人感到無(wú)從下手,望塵莫及。如果你在google上搜索ollvm,你會(huì)發(fā)現(xiàn)第一頁(yè)都是中文的搜索結(jié)果。其實(shí),llvm和ollvm在國(guó)外是比較傳統(tǒng)的東西,說(shuō)到底也只是C++代碼,難度大概等同于ART系統(tǒng)源碼的程度。

本篇文章目地是為了從另一個(gè)從未出現(xiàn)的角度來(lái)讓一個(gè)完全不懂llvm的新手快速上手ollvm,大神請(qǐng)直接跳過(guò)。

注意:本文因角度不同,若引起誤會(huì),純屬個(gè)人理解不同,本人不會(huì)作出任何解釋?zhuān)?qǐng)諒解。

  1. 快速理解llvm、clang和ollvm的概念

我們不使用網(wǎng)上那些冗雜的闡述,一句話(huà)概括,llvm是一個(gè)完整的編譯器架構(gòu),作用可以理解為制作一個(gè)編譯器,llvm先將源碼生成為與目標(biāo)機(jī)器無(wú)關(guān)的LLVMIR代碼,然后把LLVMIR代碼先優(yōu)化,再向目標(biāo)機(jī)器的匯編語(yǔ)言而努力。經(jīng)典編譯器都可以分為前端、中層優(yōu)化和后端:

[圖片上傳失敗...(image-41e3a2-1523154756216)]

我們從上圖也理解了clang,是前端的一個(gè)套件,但在實(shí)際使用時(shí),你會(huì)感覺(jué)到,我們只可以感受到clang,也只是在使用clang,因?yàn)榫幾g的時(shí)候,是調(diào)用clang或clang++來(lái)編譯源碼。Ollvm呢?是基于LLVM的代碼分支的代碼混淆,對(duì)誰(shuí)混淆?什么時(shí)候混淆?在中間表示IR層,通過(guò)編寫(xiě)pass(英文翻譯:經(jīng)過(guò),自己理解,也不需要知道其正規(guī)的概念)來(lái)混淆IR,這樣目標(biāo)機(jī)器的匯編語(yǔ)言也就被混淆了:

[圖片上傳失敗...(image-e4c6f6-1523154756216)]

當(dāng)然,這里需要知道的是,即使不用ollvm,LLVM本身也是有很多pass的,我們這樣簡(jiǎn)單的理解,LLVMIR本身是一種與目標(biāo)機(jī)器無(wú)關(guān)的虛擬化代碼,而在轉(zhuǎn)化為真實(shí)匯編代碼時(shí),肯定要?jiǎng)h除一些虛擬的東西,自然也需要pass。這樣,我們就用不到200字的闡述完成了網(wǎng)上很多長(zhǎng)篇大論才能達(dá)到的理解。

2、llvm與ollvm在移動(dòng)加固的發(fā)展

在開(kāi)始制作安卓vmp時(shí),llvm其實(shí)是被我們暫時(shí)放棄的一個(gè)方案。因?yàn)閺膕mali上想可以使用llvm,還必須先克服smali到底怎么成為C/C++,當(dāng)時(shí)他被提及,很大原因是安卓系統(tǒng)后端使用了llvm,但其實(shí)ART下和llvm關(guān)系已經(jīng)不大了。當(dāng)時(shí)都急于上架vmp,因此大部分都是采用折衷策略,如自定義dex結(jié)構(gòu)、置換指令等。隨著發(fā)展,smali2c漸漸成熟,可以smali2c了,自然ollvm是必然的一個(gè)選擇。但一個(gè)新的問(wèn)題出現(xiàn)了,就像很多加固網(wǎng)站,需要提供源碼,或編譯過(guò)程中的中間文件,說(shuō)到底還是源碼加固。

所以想做二進(jìn)制加固的ollvm分支,需要注意一下。想做到二進(jìn)制加固,沒(méi)有一個(gè)自己的反匯編解析引擎是不可能的,目前用capstone比較多。但要真正做自己的二進(jìn)制VMP加固,首先你得有一個(gè)反匯編引擎能把指令抽出來(lái),同時(shí)轉(zhuǎn)為了自己的虛擬指令,如果接上了llvm,最完美的方案就是把LLVMIR給虛擬為自己的虛擬指令,這個(gè)難度相當(dāng)于把.netframwork的IL指令給虛擬了??梢韵忍颖芰诉@兩個(gè)問(wèn)題,ARM指令得到后,利用簡(jiǎn)單的函數(shù)式指令解析來(lái)完成這個(gè)虛擬過(guò)程。我們認(rèn)為,如果只有LLVMIR,如ollvm,是沒(méi)有虛擬的,只是混淆。

3、利用beyondcompare+****sourceinsight4****的ollvm快速上手

Ollvm如果你去網(wǎng)上搜索資料學(xué)習(xí),大概是這么幾種文章:“LLVM編譯器架構(gòu)王者-編寫(xiě)簡(jiǎn)單的C虛擬編譯器”、“ollvm+ndk編譯環(huán)境的搭建”、“從0開(kāi)始學(xué)習(xí)LLVM”、“LLVM PASS的完整編寫(xiě)”,當(dāng)然這些文章都很不錯(cuò)。但對(duì)于一個(gè)新手來(lái)說(shuō),看了和沒(méi)看其實(shí)區(qū)別不大。因?yàn)槲覀円獙W(xué)習(xí)ollvm,必須先抓住關(guān)鍵,到底一個(gè)llvm是如何變?yōu)閛llvm,這是最簡(jiǎn)單,最直觀(guān)的學(xué)習(xí)方式。

我們?nèi)ハ螺d一份llvm4.0源碼(官網(wǎng)http://releases.llvm.org/4.0.1/llvm-4.0.1.src.tar.xz)和ollvm源碼(https://github.com/obfuscator-llvm/obfuscator/tree/llvm-4.0),之所以使用4.01,因?yàn)?.0.0是2017.03的,而4.01相對(duì)時(shí)期接近一點(diǎn)。然后拉入beyondcompare,這里把會(huì)話(huà)設(shè)置取消勾選“比較時(shí)間戳”,以及把比較設(shè)置為“僅文件”,時(shí)間戳因?yàn)楸容^時(shí)間不是我們的重點(diǎn),而之所以不采用原先的文件結(jié)構(gòu)比較,是因?yàn)閮烧叨加幸恍┛瘴募A,沒(méi)有比較的意義。如圖:

[圖片上傳失敗...(image-6a7250-1523154756216)]

[圖片上傳失敗...(image-49190c-1523154756216)]

看來(lái)主要的差別就在這些文件夾里了。先看最外層的CMakeLists.txt(整個(gè)工程使用cmake編譯)等3個(gè)文件:基本都是加入了產(chǎn)品的一些信息和協(xié)議:

[圖片上傳失敗...(image-827a5d-1523154756216)]

主要是其他四個(gè)文件夾:

utils文件夾:主要是Revision的細(xì)微差別

[圖片上傳失敗...(image-294408-1523154756216)]

[圖片上傳失敗...(image-21cb4-1523154756216)]

tools文件夾:ollvm中有clang文件夾,也可以看出clang是作為工具在llvm中存在,而llvm中并沒(méi)有此文件夾,在llvm官網(wǎng)中clang是作為單獨(dú)源碼而存在

[圖片上傳失敗...(image-eea73f-1523154756216)]

include文件夾(整個(gè)文件夾內(nèi)都是.h文件夾):

[圖片上傳失敗...(image-ac8105-1523154756216)]

Ollvm多了llvm\Transforms\obfuscation文件夾,可以看出ollvm添加了一些功能頭文件,一共6個(gè)文件。其中有5個(gè)我們可以理解為具體參數(shù)功能,fla 參數(shù)表示使用控制流平展(Control Flow Flattening)模式,sub參數(shù)表示使用指令替換(Instructions Substitution)模式,bcf參數(shù)表示使用控制流偽造(Bogus Control Flow)模式,aesSeed參數(shù)表示aes加密隨機(jī)種子,split參數(shù)表示分離代碼塊,我們常用的是sub\bcf\fla?;煜齾?shù)代碼我們?cè)诮酉聛?lái)分析,先看Utils.h文件

Utils.h(功能箱):

[圖片上傳失敗...(image-1eda5-1523154756216)]

其實(shí)這里也可以看出來(lái),ollvm基于了llvm,使用了llvm的頭文件,這些頭文件也在該include文件夾。

lib文件夾(\lib\Transforms)

[圖片上傳失敗...(image-c92291-1523154756214)]

這里稍微麻煩點(diǎn),我們還是從最外層的兩個(gè)文件分析,主要添加了obfuscation目錄的編譯和構(gòu)建:

CMakeLists.txt:

[圖片上傳失敗...(image-20127c-1523154756214)]

LLVMBuild.txt:

[圖片上傳失敗...(image-eb9af6-1523154756214)]

再來(lái)看IPO文件夾的兩個(gè)文件:

LLVMBuild.txt:

[圖片上傳失敗...(image-4a9d24-1523154756214)]

PassManagerBuilder.cpp(從文件名可以看出,pass管理生成,ollvm就是寫(xiě)pass),我們分三部分解析:

導(dǎo)入ollvm特有的頭文件

[圖片上傳失敗...(image-abaca3-1523154756214)]

添加混淆參數(shù)flag:

[圖片上傳失敗...(image-bee5cd-1523154756214)]

首先進(jìn)行全局aes(aesSeed)隨機(jī)種子密碼初始化,接著把ollvm混淆功能函數(shù)(split\fla\bcf\sub)添加進(jìn)去,而添加的這些函數(shù),都可以在上面include文件夾的頭文件找到,

BogusControlFlow.h、Flattening.h、Substitution.h、CryptoUtils.h等。

[圖片上傳失敗...(image-ae17ef-1523154756214)]

以BogusControlFlow為例來(lái)看:

[圖片上傳失敗...(image-d35bc-1523154756214)]

再以CryptoUtils為例來(lái)看:

[圖片上傳失敗...(image-3aeec-1523154756214)]

[圖片上傳失敗...(image-1d2cb-1523154756214)]

最后以Split為例來(lái)看:

Split.h(分離基礎(chǔ)塊,這里可能對(duì)于BasicBlock基礎(chǔ)塊不太明白,就簡(jiǎn)單理解為代碼塊,也可以推測(cè)LLVM基于的是模塊):

[圖片上傳失敗...(image-dcfb2e-1523154756214)]

如果存在一些疑惑,請(qǐng)仔細(xì)對(duì)比一看,是不是全部對(duì)上了?

最后一個(gè)文件夾,obfuscation文件夾,里面就是具體的CPP代碼了,是不是要加點(diǎn),然后,,,

[圖片上傳失敗...(image-5e22cf-1523154756212)]

當(dāng)然我們現(xiàn)在還是沒(méi)有接觸到具體的代碼,但對(duì)于以上的邏輯分析清楚特別重要,為以后我們自己的pass添加鋪路。下面以BogusControlFlow.cpp為例,來(lái)看看pass的編寫(xiě)。


我們使用sourceinsight4可以非常清晰的看到該代碼的邏輯組成

先回到BogusControlFlow.h,看到了pass.h

[圖片上傳失敗...(image-9f3d22-1523154756212)]

接著來(lái)到BogusControlFlow.cpp的llvm pass代碼處,而createBogus函數(shù),我們?cè)谇懊娴腜assManagerBuilder.cpp是見(jiàn)到過(guò)的。

[圖片上傳失敗...(image-9a5f35-1523154756212)]

往下跟,BogusControlFlow是一個(gè)結(jié)構(gòu)體,跟到runOnFunction,

[圖片上傳失敗...(image-bcce3a-1523154756212)]

runOnFunction調(diào)用了bogus函數(shù)

[圖片上傳失敗...(image-cf0657-1523154756212)]

bogus調(diào)用了addBogusFlow函數(shù)

[圖片上傳失敗...(image-276de0-1523154756212)]

addBogusFlow函數(shù)意為添加假流程,看來(lái)這里就是比較核心的函數(shù)實(shí)現(xiàn)了

[圖片上傳失敗...(image-8ad2d0-1523154756212)]

其實(shí)英文寫(xiě)的都是非常清楚的,現(xiàn)在翻譯挺智能的,意思為:

[圖片上傳失敗...(image-2e2231-1523154756212)]

這里意思大概應(yīng)該結(jié)合著前面學(xué)習(xí)都理解了,除了phi節(jié)點(diǎn),對(duì)數(shù)據(jù)結(jié)構(gòu)有點(diǎn)了解的朋友都知道節(jié)點(diǎn),節(jié)點(diǎn)就有前驅(qū)和后續(xù)節(jié)點(diǎn),直接看代碼理解,

[圖片上傳失敗...(image-e9f940-1523154756212)]

但在真實(shí)代碼中,phi并不存在,因此我們要繼續(xù)消除phi,這也是轉(zhuǎn)為真實(shí)指令的重要一步,對(duì)于以上代碼,我們可以如下消除:

[圖片上傳失敗...(image-562514-1523154756212)]

bb就是我們剛剛見(jiàn)到的BasicBlock,這樣我們就消除了phi節(jié)點(diǎn),同時(shí)更進(jìn)一步理解了addBogusFlow函數(shù)的意思,LLVM中使用reg2mem pass來(lái)對(duì)phi進(jìn)行消除。至此,一切又回到了我們最初對(duì)LLVM的介紹。

以上看雪鏈接:https://bbs.pediy.com/thread-225756.htm

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀(guān)點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容