一、前言
最近一直在學習Android加固方面的知識,看了不少論文、科技部落格以及一些github上的原始程式碼,下麵總結一下混淆方面的科技,也算是給想學習加固的同學做一些科普,在文中將到的論文、資料以及源碼,我都會給出相應的連結,供大家進一步去深入學習。後面我會弄成一個系列的文章,如有一些混淆科技沒講到,還希望大家指點,當做是交流學習。
二、Android混淆科技介紹
2.1控制流平坦化
2.1.1概念和思路
控制流平坦化,就是在不改變原始程式碼的功能前提下,將C或C++程式碼中的if、while、for、do等控制語句轉換成switch分支語句。這樣做的好處是可以模糊switch中case程式碼塊之間的關係,從而新增分析難度。
這種技術的思想是,首先將要實現平坦化的方法分成多個基本塊(就是case程式碼塊)和一個入口塊,為每個基本快編號,並讓這些基本塊都有共同的前驅模塊和後繼模塊。前驅模塊主要是進行基本塊的分發,分發通過改變switch變數來實現。後繼模塊也可用於更新switch變數的值,並跳轉到switch開始處。詳細的概念可以參考文獻[1]。
其模型如下圖:
下麵用程式碼來說明,左邊方法是沒有採用控制流平坦化之前的效果,右邊是採用了控制流平坦化的效果。
2.1.2開源項目
現時用的最多的是OLLVM(Obfuscator-LLVM)的開源混淆方案,很多國內加固廠商都可以看到使用它的身影。它提供了3中保護管道:控制流平坦化、虛假控制流和指令替換。其項目地址如下:
https://github.com/Fuzion24/AndroidObfuscation-NDK
https://github.com/obfuscator-llvm/obfuscator
2.1.3對抗
現時,對於ollvm的反混淆思路,多採用基於符號執行的方法來消除控制流平坦化,這裡不做詳細分析,詳細的分析思路,可以參考quarkslab寫的文章[3]。
2.2花指令
2.2.1概念和思路
花指令也叫垃圾指令,是指在原始程式中插入一組無用的位元組,但又不會改變程式的原始邏輯,程式仍然可以正常運行,然而反彙編工具在反彙編這些位元組時會出錯,由此造成反彙編工具失效,提高破解難度。
花指令的主要思想是,當花指令跟正常指令的開始幾個位元組被反彙編工具識別成一條指令的時候,才可以使得反彙編工具報錯。囙此插入的花指令都是一些隨機的但是不完整的指令。但是這些花指令必須要滿足兩個條件:
在程式運行時,花指令是位於一個永遠也不會被執行的路徑中。
這些花指令也是合法指令的一部分,只不過它們是不完整指令而已。
也就是說,我們只需要在每個要保護的程式碼塊之前插入無條件分支語句和花指令,如下圖所示。無條件分枝是保證程式在運行的時候不會運行到花指令的位置。而反彙編工具在再反彙編時由於會執行到花指令,所以就會報錯。
那麼現時的反彙編工具所使用的反彙編算灋,主要分為兩類:線性掃描算灋和遞迴掃描算灋。
線性掃描:依次按順序逐個地將每一條指令反匯編成彙編指令
例如下麵的指令:
如果是反彙編工具使用線性掃描算灋,就會把花指令錯誤識別,導致反彙編出錯。如下:
Dalvik Bytecode Obfuscation on Android[5]這篇文章就利用線性掃描的特點,插入fill-array-data-payload花指令,導致反編譯工具失效。
遞迴掃描:按順序逐個反彙編指令,如果某個地方出現了分支,就會把這個分支地址記錄下來,然後對這些反彙編過程中碰到的分支進行反彙編。
可見,遞迴掃描的算灋反彙編能力更强。我們常用的Android逆向工具裡面,使用的反彙編算灋如下:
2.2.2開源項目
(1)https://github.com/thuxnder/dalvik-obfuscator
可以結合文章[5]一起看。
(2)https://github.com/faber03/AndroidMalwareEvaluatingTools
這個工具是義大利薩尼奧大學的laswatlab團隊打造出來的惡意程式免殺工具,其實就是使用各種混淆科技,其中也包括花指令插入,在AndroidMalwareEvaluatingTools/transformations sources/JunkInsertion/目錄下。該工具的使用報告可以參考文獻[4]。
(3)https://github.com/strazzere/APKfuscator
APKFuscator通過插入下圖的垃圾指令使得反彙編器出錯。
2.2.3對抗
檢測出花指令的位置和長度,然後用NOP指令替換即可。
2.3識別字混淆
2.3.1概念和思路
識別字混淆就是對來源程式中的包名、類名、方法名和變數名進行重命名,用無意義的識別字來替換,使得破解這分析起來更困難。最常用的就是ProGuard開源工具,其混淆後效果如右圖所示。
甚至通過定制混淆字典,可以達到下麵這種混淆效果,參攷開源項目[7]:
那麼這個識別字混淆的原理是怎樣的呢?要瞭解這個原理,我們得事先對dex檔案格式有一定瞭解,這個資料大家可以在網上找,很多,這裡就不詳細說了。
我們知道dex檔案中的類名、方法名、變數名其實都對應的一個string_id的字串索引,如下圖。每一個類對應著class_def_item結構體,其中class_idx就是指向類名的字串索引。
同樣,每個方法也是對應一個method_id_item的結構體,其中name_idx就是指向方法名的字串索引。
欄位名也一樣,對應著一個field_id_item的結構體,其中name_idx是指向欄位名的字串索引。
也就是說,我們只要修改相應的string_id索引錶中的字串,就可以達到識別字混淆的目的。
具體的實現可以參考文章[10],它還提供了一個dex混淆器的簡單原型:DexConfuse。
2.3.2開源項目
(1)ProGuard
(2)https://github.com/burningcodes/DexConfuse
DexConfuse是一個簡單的dex混淆器,可以混淆類名、方法名和欄位名。
(3)https://github.com/strazzere/APKfuscator
APKFuscator作者通過解析修改Dex檔案格式,修改類名,使類名字元個數超過255個,使得反彙編器報錯。
修改類名使得字元個數超過255個
2.3.3對抗
文獻[8]採用的一種反混淆管道就是通過大規模的學習為混淆的APK,然後總結出一個概率模型,通過這個概率模型來識別混淆後的程式碼。其反混淆流程如下圖分為3個步驟:
Step1:生成一個依賴關係圖,每個節點代表要重命名的元素,每條線代表依賴關係。
Step2:匯出一些限制規則,這些規則可以保證回復的APK是個正常的APK,且和原APK語義相同。
Step3:根據概率模型提供的權重,對混淆的元素的原始名稱進行預測和恢復。
作者將論文中的反混淆方法做成了一個線上的反混淆工具提供使用:
http://apk-deguard.com/
2.4字串混淆
2.4.1概念和思路
很多時候,為了避免反匯編後的程式碼容易被破解者分析讀懂,往往會來源程式中一些比較關鍵的字串變數進行混淆,使得破解者分析成本提高。這裡的字串混淆有兩種,一種是Java層的字串混淆,另一種是native層的字串混淆,也就是so檔案中的字串混淆。上面我們介紹了Proguard免費混淆工具,它可以混淆類名、方法名和變數名,但是不支持字串混淆,要使用字串混淆就需要使用DexGuard商業版混淆器。
實現思路如下:
(1)編碼混淆
編碼混淆就是先將字串轉換成16進制的數組或者Unicode編碼,在使用的時候才恢復成字串。這樣破解者在逆向後看到的是一串數位或者亂碼,很難直接分析。
如下程式碼所示,其實就是輸出一個Hello World。但是我們硬編碼的時候是保存它的ASCII對應的十六進位,在使用的時候才轉換成字元。在反編譯成smali後,就看不到任何的有意義的字串了。
Java程式碼:
apktool反編譯後的smali程式碼:
同樣的在native層的程式碼也可以使用類似的管道實現對C或C++中的字串進行混淆。
(2)加密處理
加密處理就是實現在本地將字串加密,然後將密文硬編碼到來源程式中,再實現一個解密函數,在引用密文的地方調用解密函數解密即可。如下圖。
還有一種管道是我們可以修改dex檔案。對於Java層的字串加密,我們可以在dex檔案中,找到要加密的字串在字串常量表中的位置,然後對它用加密演算法加密。然後在自定義Application的attachBaseContext方法中在運行時對密文進行解密,或者可以在native層加密,提高破解難度。
同樣的,我們也可以修改SO檔案。SO檔案中也存在只讀常數區”.rodata”,如下圖所示。我們可以根據section header table來找到”.rodata”的位置和大小,然後實現對只讀常數區進行加密混淆,在運行的時候再調用相應的解密算灋解密即可。
2.4.2開源項目
https://github.com/ysrc/obfuseSmaliText
obfuseSmaliText是國內同程安全的一個員工實現免費字串混淆工具,它是通過apktool反編譯安裝包,在smali層對字串進行混淆,現時採用的是异或+十六進位的管道進行混淆。效果如下圖:
2.4.3對抗
對於使用了字串混淆,只能找到響應的解密函數,調用解密函數去解密就可以恢復明文。
三、結束
這次就寫到這裡,後面我還會繼續補充其他的混淆科技,包括控制流變換、模擬器檢測、反調試、Java程式碼native化等。
參攷
[1] obfuscating C++ Programs via Control Flow Flattening
http://www.inf.u-szeged.hu/~akiss/pub/pdf/laszlo_obfuscating.pdf
[2]利用符號執行去除控制流平坦化
https://security.tencent.com/index.php/blog/msg/112
[3] Deobfuscation: recovering an OLLVM-protected program.
http://blog.quarkslab.com/deobfuscation-recovering-an-ollvm-protected-program.html
(備註:中文翻譯版,http://www.0daybank.org/?p=7845 )
[4] Evaluating malwares obfuscation techniques against antimalware detection algorithms.
http://www.iswatlab.eu/wp-content/uploads/2015/09/mobile_antimalware_evaluation.pdf
[5] Dalvik Bytecode Obfuscation on Android http://www.dexlabs.org/blog/bytecode-obfuscation
[6] Detecting repackaged android apps using server-side analysis
https://pure.tue.nl/ws/files/46945161/855432-1.pdf
[7] https://github.com/ysrc/AndroidObfuseDictionary
[8] Statistical Deobfuscation of Android Application. http://www.srl.inf.ethz.ch/papers/deguard.pdf
[9] Android字串及字典開源混淆實現https://mp.weixin.qq.com/s/SRv1Oar87w1iKuDXS4oaew
[10] Dex混淆的原理及實現
http://burningcodes.net/dex%E6%B7%B7%E6%B7%86%E7%9A%84%E5%8E%9F%E7%90%86%E5%8F%8A%E5%AE%9E%E7%8E%B0/
[11] Android Code Protection via Obfuscation Techniques Past,Present and Future Directions.
https://arxiv.org/pdf/1611.10231.pdf
轉載自:http://bobao.360.cn/learning/detail/3704.html 原文作者:ix__xi