OLLVM代碼混淆移植與使用

簡(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。

image.png

下載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è)文件如下:

image.png
image.png
image.png
image.png
image.png
image.png
image.png
image.png

編譯

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-BuildingNO

image.png
image.png

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

image.png
image.png
image.png

按這些配置好后就算是可以用了。

最后

簡(jiǎn)單展示一下混淆后的成果

源碼


image.png

反編譯未混淆代碼


image.png

反編譯混淆后代碼


image.png

擴(kuò)展:字符串混淆

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

未命名.png

用法

-mllvm -sobf:編譯時(shí)候添加選項(xiàng)開啟字符串加密
-mllvm -seed=0xdeadbeaf:指定隨機(jī)數(shù)生成器種子

效果

看個(gè)添加了-mllvm -sub -mllvm -sobf -mllvm -fla -mllvm -bcf這么一串的效果。

源碼

image.png

反編譯未混淆代碼


image.png

反編譯混淆后代碼

image.png
最后編輯于
?著作權(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)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • 前言 相信大部分的第一感覺就是覺得jni居然也可以混淆???!是的,在沒有接觸這塊的時(shí)候我和大家是一樣的懵逼,居然還...
    海闊sun天空閱讀 20,097評(píng)論 35 20
  • Ollvm,是C/C++的跨平臺(tái)混淆方式,它提供了指令平坦化的能力,可以吧邏輯變得相當(dāng)復(fù)雜從而阻止逆向工程。網(wǎng)上有...
    超哥__閱讀 2,445評(píng)論 7 2
  • 原文鏈接:http://fighting300.com.... OLLVM簡(jiǎn)介 OLLVM(Obfuscator-...
    fighting300閱讀 21,259評(píng)論 65 35
  • 說明 這只是筆記。。。。。。。。 從0開始搭建測(cè)試環(huán)境 下載android ndk ,然后配置ndk環(huán)境變量,使n...
    吉兇以情遷閱讀 5,491評(píng)論 0 3
  • 一輩子,為了啥? 有人說,是為了錢! 累死累活,就想多賺點(diǎn);口挪肚攢,就想多存?zhèn)z。最后烙下個(gè)病身子,金山銀山也換不...
    余小包閱讀 270評(píng)論 0 1

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