0x1,首先介紹一下編譯環境配置
1、UE4.25
2.vs2017(15.9),注:2019編譯總是出現錯誤
3、cmake3.18.5,cmake的作用是為ollvm原始碼編譯成適合於在vs2017上能夠進行編譯的專案解決檔案。
4、andriod studio,最新版就行,為apk打包提供環境。
5、IDA,檢查函式混淆的結果。
6、NDK r21b,andriod沒有整合ndk,需要手動安裝並且在ue4中指定路徑。
7、需要注意的是llvmbuild需要Python 2.x,如果你只有或CMake優先選擇了Python 3.x,則會導致以下錯誤:
ModuleNotFoundError: No module named 'llvmbuild'
0x2,ollvm簡介
在介紹ollvm之前,需要先了解一下llvm
LLVM(low level virtual machine)從本質上來說,是一個開源編譯器框架,能夠提供程式語言的編譯期優化、連結優化、線上編譯優化、程式碼生成。LLVM有兩個特點:
(1)LLVM有一個特定指令格式的IR語言,我們可以通過書寫Pass來對其IR進行優化。
(2)可以作為多種語言的後端,提供與程式語言無關的優化和針對多種CPU的程式碼生成功能。
LLVM主要由Clang前端、IR優化器(Pass)和LLVM後端構成。其功能分別是:
clang前端:將平臺相關的原始碼生成與平臺無關的IR(llvm Bitcode)。
IR優化器:主要對IR進行優化。
llvm後端:將優化後的IR轉換為與平臺相關的彙編程式碼或者機器碼。
Clang前端以.c檔案為輸入,經語法詞法分析後解析為抽象語法數,最後通過LLVM內聯API變為LLVM IR。其功能為:詞法分析器:把輸入的程式程式碼切成token;語法分析器:接收token流解析為AST。
gcc和clang的區別
GCC特性:除支援C/C++/ Objective-C/Objective-C++語言外,還是支援Java/Ada/Fortran/Go等;當前的Clang的C++支援落後於GCC;支援更多平臺;更流行,廣泛使用,支援完備。
Clang特性:是一個C、C++、Objective-C和Objective-C++程式語言的編譯器前端。它採用了底層虛擬機器(LLVM)作為其後端。它的目標是提供一個GNU編譯器套裝(GCC)的替代品。編譯速度快;記憶體佔用小;相容GCC;設計清晰簡單、容易理解,易於擴充套件增強;基於庫的模組化設計,易於IDE整合;出錯提示更友好。
IR優化器:
LLVM IR包含三種格式:一種是在記憶體中的編譯中間語言;一種是硬碟上儲存的二進位制中間語言(以.bc結尾),最後一種是可讀的中間格式(以.ll結尾)。這三種中間格式是完全相等的。LLVM IR是LLVM優化和進行程式碼生成的關鍵。根據可讀的IR,我們可以知道再最終生成目的碼之前,我們已經生成了什麼樣的程式碼。我們通過Pass來對IR進行相應的優化。
文字格式如下:
define i32 @add1(i32 %a, i32 %b) { entry: %tmp1 = add i32 %a, %b ret i32 %tmp1 } define i32 @add2(i32 %a, i32 %b) { entry: %tmp1 = icmp eq i32 %a, 0 br i1 %tmp1, label %done, label %recurse recurse: %tmp2 = sub i32 %a, 1 %tmp3 = add i32 %b, 1 %tmp4 = call i32 @add2(i32 %tmp2, i32 %tmp3) ret i32 %tmp4 done: ret i32 %b
llvm後端
Llvm clang編譯器主要是將各平臺原始碼編譯成與平臺無關的IR指令集,這將支撐對IR的優化及轉換操作,而llvm後端的主要工作是優化IR指令,並將這些與平臺無關的IR指令轉換成目標裝置相關的指令。
由上圖所示,LLVM IR進入後端要經過pass優化,指令選擇,指令排程,暫存器分配,程式碼佈局優化以及彙編發行等過程。上述各過程都是pass優化的過程,普通(白色)pass可由使用者自定義,內建(灰色)pass由一系列小的pass構成,換句話說我們可以對每一個階段都可以進行不同程度的優化。同時無須為每個目標平臺編寫重複的程式碼。
LLVM的pass均用C ++類編寫,使用者編寫的Pass都繼承於內建的父Pass
類,然後重新父類的某個方法(即虛擬函式)。大多數pass都寫在一個 .cpp
檔案中,並且它們的類的子Pass
類是在匿名名稱空間中定義的(這使其對定義檔案完全私有)。並且在外部定義pass ID(用於識別pass),以及對Pass進行註冊。
開啟include資料夾
其實從資料夾名稱就能判斷include資料夾是標頭檔案所在的地方,include資料夾之下包含兩個資料夾:llvm和llvm-c。
llvm資料夾下有如下目錄:llvm\Transforms\Obfuscation
,可以看到此資料夾下有一些標頭檔案:
此處是存放OLLVM專案中自己寫的pass的標頭檔案的地方,由此可知,如果我們需要些自己的pass的話,那麼對應的pass類的標頭檔案也需要在include\llvm\Transforms
新建一個資料夾專門用來存放標頭檔案。標頭檔案的具體內容暫且不管,接下來再去看看實現檔案在哪裡。
開啟與include
資料夾平行的lib
資料夾並進入lib\Transforms\Obfuscation
目錄:
開啟
Obfuscation
目錄,可以看到與之前的標頭檔案一一對應的實現檔案:至此,與我們編寫自己的pass一樣,在
include\llvm\Transforms\Obfuscation
定義標頭檔案,在lib\Transforms\Obfuscation
寫實現檔案。這樣,我們就明白了該如何開始寫自己的專案。不過要注意的是,不管是LLVM還是OLLVM,它們都是通過編寫makefile來實現專案的執行的,所以我們得熟練掌握makefile的編寫與依賴,才能玩轉自己的專案。下面介紹編譯過程
OK!