1、ollvm下載編譯
我的是macbook環境。
參考obfuscator官網:https://github.com/obfuscator-llvm/obfuscator/wiki
執行下面的命令下載並編譯:
$ git clone -b llvm-4.0 https://github.com/obfuscator-llvm/obfuscator.git
$ mkdir build
$ cd build
$ cmake -DCMAKE_BUILD_TYPE=Release ../obfuscator/
$ make -j7
cmake找不到的話,上cmake.org官網下載,並設置環境變量。
編譯成功后,生成的文件主要在build/bin 和 build/lib 這2個文件夾。
2、整合到NDK
網上別人有介紹在NDK目錄手動創建llvm之類的新文件夾,拷貝build/bin 和 build/lib2個文件夾,有編譯問題,懶得去折騰。
我的做法是:
找到Android SDK目錄中的 ../ndk-bundle/toolchains/llvm 文件夾,先備份下llvm文件夾,然后將obfuscator編譯好的build/bin 和 build/lib2個文件夾直接拷貝到../llvm/prebuilt/darwin-x86_64/文件夾下,直接覆蓋替換。
使用最新的Android Studio編輯器,編譯so庫已經集成cmake,不需要去修改config.mk 與 setup.mk也是正常的。
我沒按這個步驟,編譯通過后直接拷貝bin目錄下clang、clang++、clang-format、clang-4.0拷貝到 android-ndk-r16b/toolchains/llvm/prebuilt/linux-x86_64/bin(覆蓋前請自行備份)
3、使用OLLVM
先嘗試在自己so庫工程的CMakeList.txt中加入:
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -mllvm -fla")SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -mllvm -fla")
Release編譯修改成下面的配置:
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mllvm -fla")SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mllvm -fla")
再使用IDA工具查看so文件,發現函數內的代碼有產生混淆修改。
這里介紹下OLLVM的混淆參數,上面的官網github的wiki有說明這些參數:
1、-fla :for the control flow flattening pass
2、-sub :for the instruction substitution pass
3、-bcf : for the bogus control flow pass
-fla:
表示使用控制流平展模式,最直觀的感受就是簡單的if-else語句,被嵌套成了while-switch語句,出現了很多干擾無用的分支,增加閱讀難度。
-mllvm -fla: activates control flow flattening
-mllvm -split: activates basic block splitting. Improve the flattening when applied together.
-mllvm -split_num=3: if the pass is activated, applies it 3 times on each basic block. Default: 1
-sub:
表示使用指令替換模式,主要是將正常的運算操作(+,-,&,|等)替換成功能相等但表述更復雜的形式。
比如,對於表達式 a = b + c,它的等價式可以有 a = – ( -b – c), a = b – (-c) 或 a = -(-b) + c 等,原表達式可以替換成任意相等式,或者通過隨機數在多個相等式中做選擇。
SUB模式目前只支持整數運算操作,支持 + , – , & , | 和 ^ 操作,還是比較局限的。編譯時,使用 -mllvm -sub 參數即可。下面參數可與-mllvm -sub參數配合使用。
-mllvm -sub: activate instructions substitution
-mllvm -sub_loop=3: if the pass is activated, applies it 3 times on a function. Default: 1
-bcf:
表示使用控制流偽造模式,也是對程序的控制流做操作。BCF模式會在原代碼塊的前后隨機插入新的代碼塊,新插入的代碼塊不是確定的,然后新代碼塊再通過條件判斷跳轉到原代碼塊中。
更要命地是,原代碼塊可能會被克隆並插入隨機的垃圾指令。這么多不確定性,就導致對同一份代碼多次做BCF模式的混淆時,得到的是不同的混淆效果。可見,BCF混淆模式還是很強大的,不同於FLA那種較確定的混淆模式。使用BCF模式編譯時配置參數 -mllvm -bcf即可,此外,BCF模式還支持其它幾個參數,下面參數與-mllvm -bcf參數配合使用。
-mllvm -perBCF=20: 對所有函數都混淆的概率是20%,默認100%
-mllvm -bcf: activates the bogus control flow pass
-mllvm -bcf_loop=3: 對函數做3次混淆,默認1次
-mllvm -bcf_prob=40: 代碼塊被混淆的概率是40%,默認30%
備注:
參數前都需要有-mllvm,比如,CMakeList.txt中添加:
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} -mllvm -fla -mllvm -bcf -mllvm -sub ")
有的時候,由於效率或其他原因的考慮,我們只想給指定的函數混淆,OLLVM也提供了對這一特性的支持。比如,想對函數func()使用bcf混淆,只需要給函數func()增加bcf屬性即可。
int func() __attribute__ ((__annotate__ (("bcf"))))
fla,sub和bcf三個屬性可以搭配使用。如果不想對func()函數使用bcf屬性,那標記為“nobcf”即可。
4、混淆代碼中的字符串常量
上海交大密碼與計算機安全實驗室GoSSIP小組開源了他們設計的基於LLVM 4.0的孤挺花混淆框架,實現了一個用於字符串加密的pass。
字符串加密的pass位於如下目錄:
Armariris/include/llvm/Transforms/Obfuscation/StringObfuscation.h
Armariris/lib/Transforms/Obfuscation/StringObfuscation.cpp
提取出該文件,放到OLLVM相同目錄下,並將頭文件也復制到對應目錄下.
在Obfuscation下的cmakelists.txt將StringObfuscation.cpp添加到編譯庫中,
add_llvm_library(LLVMObfuscation
CryptoUtils.cpp
Substitution.cpp
StringObfuscation.cpp
BogusControlFlow.cpp
Utils.cpp
SplitBasicBlocks.cpp
Flattening.cpp
)
最后只需要在Transforms/IPO下的PassManagerBuilder.cpp將字符串加密的編譯選項添加進去即可
1. 在PassManagerBuilder.cpp中添加引用:
#include "llvm/Transforms/Obfuscation/StringObfuscation.h"
2. 在PassManagerBuilder.cpp中的合適的地方插入以下加粗的兩條函數聲明,即編譯時的編譯參數-mllvm -sobf:
static cl::optEnableMLSM("mlsm", cl::init(true), cl::Hidden, cl::desc("Enable motion of merged load and store"));
static cl::opt Seed("seed", cl::init(""),cl::desc("seed for the random"));
static cl::opt StringObf("sobf", cl::init(false),cl::desc("Enable the string obfuscation"));
3. 在PassManagerBuilder::PassManagerBuilder()構造函數中添加隨機數因子的初始化:
加粗的那一行代碼就是了。
void PassManagerBuilder::populateModulePassManager(
legacy::PassManagerBase &MPM) {
...
MPM.add(createForceFunctionAttrsLegacyPass());
MPM.add(createStringObfuscation(StringObf));
MPM.add(createSplitBasicBlock(Split));
...
}
參數用法:
編譯時候添加選項開啟字符串加密: -mllvm -sobf
開啟控制流扁平化: -mllvm -fla
開啟指令替換: -mllvm -sub
指定隨機數生成器種子: -mllvm -seed=0xdeadbeaf
最后命令調用:
#SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -mllvm -sobf")
#SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -mllvm -sobf")
IDA查看so庫,可以看到常量字符串被混淆成亂碼了。
5、OLLVM 5.0版本的參考:
https://github.com/qtfreet00/llvm-obfuscator
