ollvm在VS2017下編譯
- 2020 年 12 月 7 日
- 筆記
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進行註冊。
ollvm全稱obfuscator-llvm,即帶有函數混淆功能的llvm。
打開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!