(十四)Android NDK混淆


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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM