簡(jiǎn)介
OLLVM(Obfuscator-LLVM)是瑞士西北應(yīng)用科技大學(xué)安全實(shí)驗(yàn)室于2010年6月份發(fā)起的一個(gè)項(xiàng)目,該項(xiàng)目旨在提供一套開源的針對(duì)LLVM的代碼混淆工具,以增加對(duì)逆向工程的難度。github上地址是https://github.com/obfuscator-llvm/obfuscator,只不過僅更新到llvm的4.0,2017年開始就沒在更新。
移植
OLLVM如果自己想拿最新版的LLVM和Clang進(jìn)行移植功能其實(shí)也并不是很難,整理一下其實(shí)改動(dòng)很小,接下來將會(huì)講一下移植的方法。
個(gè)人整理
先放一下個(gè)人移植好的版本地址https://github.com/heroims/obfuscator.git,個(gè)人fork原版后又加入了llvm5.0,6.0,7.0以及swift-llvm5.0的版本,應(yīng)該能滿足大部分需求了,如果有新版本下面的講解,各位也可以自己動(dòng)手去下載自己需要的llvm和clang進(jìn)行移植。git上的提交每次都很獨(dú)立如下圖,方便各位cherry-pick。

下載LLVM
llvm地址:https://github.com/llvm-mirror
swift-llvm地址:https://github.com/apple
大家可以從上面的地址下載最新的自己需要的llvm和clang
#下載llvm源碼
wget https://codeload.github.com/llvm-mirror/llvm/zip/release_70
unzip llvm-release_70.zip
mv llvm-release_70 llvm
#下載clang源碼
wget https://codeload.github.com/llvm-mirror/clang/zip/release_70
unzip clang-release_70.zip
mv clang-release_70 llvm/tools/clang
添加混淆代碼
如果用git的話只需要執(zhí)行git cherry-pick xxxx把xxxx換成對(duì)應(yīng)的我的版本上的提交哈希填上即可。極度推薦用git搞定。
如果手動(dòng)一點(diǎn)點(diǎn)加的話,第一步就是把我改過的OLLVM文件夾里/include/llvm/Transforms/Obfuscation和/lib/Transforms/Obfuscation移動(dòng)到剛才下載好的llvm源碼文件夾相同的位置。
git clone https://github.com/heroims/obfuscator.git
cd obfuscator
git checkout llvm-7.0
cp include/llvm/Transforms/Obfuscation llvm/include/llvm/Transforms/Obfuscation
cp lib/Transforms/Obfuscation llvm/lib/Transforms/Obfuscation
然后手動(dòng)修改8個(gè)文件如下:








編譯
mkdir build
cd build
#如果不想跑測(cè)試用例加上-DLLVM_INCLUDE_TESTS=OFF
cmake -DCMAKE_BUILD_TYPE=Release -DLLVM_CREATE_XCODE_TOOLCHAIN=ON ../obfuscator/
make -j7
使用
這里原版提供了3種混淆方式分別是控制流扁平化,指令替換,虛假控制流程,用起來都是加cflags的方式。下面簡(jiǎn)單說下這幾種模式。
控制流扁平化
這個(gè)模式主要是把一些if-else語句,嵌套成do-while語句
-mllvm -fla:激活控制流扁平化
-mllvm -split:激活基本塊分割。在一起使用時(shí)改善展平。
-mllvm -split_num=3:如果激活了傳遞,則在每個(gè)基本塊上應(yīng)用3次。默認(rèn)值:1
指令替換
這個(gè)模式主要用功能上等效但更復(fù)雜的指令序列替換標(biāo)準(zhǔn)二元運(yùn)算符(+ , – , & , | 和 ^)
-mllvm -sub:激活指令替換
-mllvm -sub_loop=3:如果激活了傳遞,則在函數(shù)上應(yīng)用3次。默認(rèn)值:1
虛假控制流程
這個(gè)模式主要嵌套幾層判斷邏輯,一個(gè)簡(jiǎn)單的運(yùn)算都會(huì)在外面包幾層if-else,所以這個(gè)模式加上編譯速度會(huì)慢很多因?yàn)橐鰩讓蛹俚倪壿嫲嬲杏玫拇a。
另外說一下這個(gè)模式編譯的時(shí)候要浪費(fèi)相當(dāng)長(zhǎng)時(shí)間包哪幾層不是鬧得!
-mllvm -bcf:激活虛假控制流程
-mllvm -bcf_loop=3:如果激活了傳遞,則在函數(shù)上應(yīng)用3次。默認(rèn)值:1
-mllvm -bcf_prob=40:如果激活了傳遞,基本塊將以40%的概率進(jìn)行模糊處理。默認(rèn)值:30
上面說完模式下面講一下幾種使用方式
直接用二進(jìn)制文件
直接使用編譯的二進(jìn)制文件build/bin/clang test.c -o test -mllvm -sub -mllvm -fla -mllvm -bcf
NDK集成
這里分為工具鏈的制作和項(xiàng)目里的配置。
制作Toolchains
這里以修改最新的ndk r18為例,老的ndk版本比這更容易都在ndk-bundle/toolchains里放著需要修改的文件。
#復(fù)制ndk的toolschain里的llvm
cp -r Android/sdk/ndk/xx.x.xxxxxx/toolchains/llvm Android/sdk/ndk/xx.x.xxxxxx/toolchains/ollvm
#刪除prebuilt文件夾下的文件夾的bin和lib64,prebuilt文件夾下根據(jù)系統(tǒng)不同命名也不同
rm -rf Android/sdk/ndk/xx.x.xxxxxx/toolchains/ollvm/prebuilt/darwin-x86_64/bin
rm -rf Android/sdk/ndk/xx.x.xxxxxx/toolchains/ollvm/prebuilt/darwin-x86_64/lib64
#把我們之前編譯好的ollvm下的bin和lib移到我們剛才刪除bin和lib64的目錄下
mv build/bin Android/sdk/ndk/xx.x.xxxxxx/toolchains/ollvm/prebuilt/darwin-x86_64/bin
mv build/lib Android/sdk/ndk/xx.x.xxxxxx/toolchains/ollvm/prebuilt/darwin-x86_64/lib64
#復(fù)制Android/sdk/ndk/xx.x.xxxxxx?/?build?/?core?/?toolchains的文件夾,這里根據(jù)自己對(duì)CPU架構(gòu)的需求自己復(fù)制然后修改
cp -r Android/sdk/ndk/xx.x.xxxxxx?/?build?/?core?/?toolchains/aarch64-linux-android-clang? Android/sdk/ndk/xx.x.xxxxxx/?build?/?core?/?toolchains/aarch64-linux-android-clang-ollvm
cp -r Android/sdk/ndk/xx.x.xxxxxx/?build?/?core?/?toolchains/arm-linux-androideabi-clang? Android/sdk/ndk/xx.x.xxxxxx/build?/?core?/?toolchains/arm-linux-androideabi-clang-ollvm
cp -r Android/sdk/ndk/xx.x.xxxxxx/?build?/?core?/?toolchains/x86_64-clang Android/sdk/ndk/xx.x.xxxxxx/build?/?core?/?toolchains/x86_64-clang-ollvm
cp -r Android/sdk/ndk/xx.x.xxxxxx/?build?/?core?/?toolchains/x86-clang-clang? Android/sdk/ndk/xx.x.xxxxxx/build?/?core?/?toolchains/x86-clang-ollvm
最后把xxxxxxxxx-ollvm里的setup.mk文件進(jìn)行修改
TOOLCHAIN_NAME := ollvm
TOOLCHAIN_ROOT := $(call get-toolchain-root,$(TOOLCHAIN_NAME))
TOOLCHAIN_PREFIX := $(TOOLCHAIN_ROOT)/bin
config.mk里是CPU架構(gòu),剛才是復(fù)制出來的所以不用修改,但如果要添加其他的自定義架構(gòu)需要嚴(yán)格按照格式規(guī)范命名最初的文件夾,如mips的需要添加文件夾mipsel-linux-android-clang-ollvm,setup.mk和剛才的修改一樣即可。
修改Android/sdk/ndk/xx.x.xxxxxx/?build?/?core?/?toolchains/setup-toolchain.mk里
ifneq ($(words $(TARGET_TOOLCHAIN_LIST)),1)
$(call __ndk_error,Expected two items in TARGET_TOOLCHAIN_LIST, \
found "$(TARGET_TOOLCHAIN_LIST)")
endif
改為
ifneq ($(words $(TARGET_TOOLCHAIN_LIST)),2)
$(call __ndk_error,Expected two items in TARGET_TOOLCHAIN_LIST, \
found "$(TARGET_TOOLCHAIN_LIST)")
endif
項(xiàng)目中配置
到了項(xiàng)目里還需要修改兩個(gè)文件:
在Android.mk 中添加混淆編譯參數(shù)
LOCAL_CFLAGS += -mllvm -sub -mllvm -bcf -mllvm -fla
Application.mk中配置NDK_TOOLCHAIN_VERSION
#根據(jù)需要添加
APP_ABI := x86 armeabi-v7a x86_64 arm64-v8a mips armeabi mips64
#使用剛才我們做好的編譯鏈
NDK_TOOLCHAIN_VERSION := ollvm
Visual Studio集成
編譯ollvm的時(shí)候,使用cmake-gui選擇Visual Studio2015或者命令行選擇cmake -G "Visual Studio 14 2015" -DCMAKE_BUILD_TYPE=Release ../obfuscator/
然后cmake會(huì)產(chǎn)生一個(gè)visual studio工程,用vs編譯即可!
至于將Visual Studio的默認(rèn)編譯器換成clang編譯,參考https://www.ishani.org/projects/ClangVSX/
Visual Studio2015起官方開始支持Clang,具體做法:
文件->新建->項(xiàng)目->已安裝->Visual C++->跨平臺(tái)->安裝Clang with Microsoft CodeGen
Clang是一個(gè)完全不同的命令行工具鏈,這時(shí)候可以在工程配置中,平臺(tái)工具集選項(xiàng)里找到Clang,然后使用ollvm的clang替換該clang即可。
XCode集成
XCode里集成需要看版本,XCode10之前和之后是一個(gè)分水嶺,XCode9之前和之后有一個(gè)小配置不同。
XCode10以前
$ 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
修改:
<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>
執(zhí)行:
$ sudo plutil -convert binary1 Info.plist
$ cd Resources/
$ sudo mv Clang\ LLVM\ 1.0.xcspec Obfuscator.xcspec
$ sudo vim Obfuscator.xcspec
修改:
<key>Description</key>
<string>Apple LLVM 8.0 compiler</string> -> <string>Obfuscator 4.0 compiler</string>
<key>ExecPath</key>
<string>clang</string> -> <string>/path/to/obfuscator_bin/clang</string>
<key>Identifier</key>
<string>com.apple.compilers.llvm.clang.1_0</string> -> <string>com.apple.compilers.llvm.obfuscator.4_0</string>
<key>Name</key>
<string>Apple LLVM 8.0</string> -> <string>Obfuscator 4.0</string>
<key>Vendor</key>
<string>Apple</string> -> <string>HEIG-VD</string>
<key>Version</key>
<string>7.0</string> -> <string>4.0</string>
執(zhí)行:
$ cd English.lproj/
$ sudo mv Apple\ LLVM\ 5.1.strings "Obfuscator 3.4.strings"
$ sudo plutil -convert xml1 Obfuscator\ 3.4.strings
$ sudo vim Obfuscator\ 3.4.strings
修改:
<key>Description</key>
<string>Apple LLVM 8.0 compiler</string> -> <string>Obfuscator 4.0 compiler</string>
<key>Name</key>
<string>Apple LLVM 8.0</string> -> <string>Obfuscator 4.0</string>
<key>Vendor</key>
<string>Apple</string> -> <string>HEIG-VD</string>
<key>Version</key>
<string>7.0</string> -> <string>4.0</string>
執(zhí)行:
$ sudo plutil -convert binary1 Obfuscator\ 3.4.strings
XCode9之后要設(shè)置Enable Index-While-Building成NO


XCode10之后
xcode10之后無法使用添加ideplugin的方法,但添加編譯鏈跑的依然可行,另外網(wǎng)上一些人說不能開bitcode,不能提交AppStore,用原版llvm改的ollvm的確有可能出現(xiàn)上述情況,所以我用蘋果的swift-llvm改了一版暫時(shí)沒去試著提交,或許可以,有興趣的也可以自己下載使用試試obfuscator這版,特別備注由于修改沒有針對(duì)swift部分所以用swift寫的代碼沒混淆,回頭有空的話再弄。
創(chuàng)建XCode的toolchain然后把生成的文件夾放到/Library/Developer/下
cd build
sudo make install-xcode-toolchain
mv /usr/local/Toolchains /Library/Developer/
Toolchains下的.xctoolchain文件就是一個(gè)文件夾,進(jìn)去修改info.plist
<key>CFBundleIdentifier</key>
<string>org.llvm.7.0.0svn</string> -> <string>org.ollvm-swift.5.0</string>
修改完在XCode的Toolchains下就會(huì)顯示相應(yīng)的名稱
然后如圖打開XCode選擇Toolchaiins



按這些配置好后就算是可以用了。
最后
簡(jiǎn)單展示一下混淆后的成果
源碼

反編譯未混淆代碼

反編譯混淆后代碼

擴(kuò)展:字符串混淆
原版是沒有這功能的本來,Armariris 提供了這個(gè)功能,我這也移植過來了,畢竟不難。
首先把StringObfuscation的.h,.cpp文件放到對(duì)應(yīng)的Obfuscation文件夾下,然后分別修改下面的文件。

用法
-mllvm -sobf:編譯時(shí)候添加選項(xiàng)開啟字符串加密
-mllvm -seed=0xdeadbeaf:指定隨機(jī)數(shù)生成器種子
效果
看個(gè)添加了-mllvm -sub -mllvm -sobf -mllvm -fla -mllvm -bcf這么一串的效果。
源碼

反編譯未混淆代碼

反編譯混淆后代碼
