05.28 Art模式下,Android源代碼如何“金蟬脫殼”?

APK加固是作為保護APK不被反編譯、逆向、篡改的常用手段,既保護了敏感數據也隱藏了敏感方法(函數)。通常,APK加固是第三方廠商以開發者服務的手段提供給開發者。開發者把開發好的APK上傳到加固廠商,APK被加固後,開發者下載下來,再次簽名,就可以發佈到各大市場。

由於加固服務的開放性,一些惡意APK也會被提交併加固,給安全檢測和分析增加困難,因此從被加固保護的APK中解密出原始代碼(俗稱脫殼),是安全檢測的一道重要流程。

現在的加殼方法有兩種,一種是把dex加密,在APK啟動時再動態解密並加載;另外一種是類似vmp的方法,將原有的Android虛擬機字節碼做變換,自己充當虛擬機角色,解釋執行變換後的字節碼。

本文以第一種加殼方式為內容,通過修改Android源代碼來實現脫殼,一方面可以熟悉Android源代碼,另一方面也可以瞭解Android APK的加載流程。接下來,ISEC實驗室為大家詳解Android源代碼脫殼方法!

Art模式下,Android源代碼如何“金蟬脫殼”?

Android系統虛擬機有dalvik和art兩種模式,由於新版Android系統只支持art模式,所以我們以Andorid5.0源碼為基礎,通過修改art虛擬機代碼來脫殼。

在修改源碼之前,我們需要先簡單瞭解下art模式下APK安裝、dex加載流程和加固的基本工作原理。

1、安裝流程

A、APK的安裝通常由以下方式觸發:adb install命令、pm install命令、java代碼通過startActivity調用安裝接口或者在system/app目錄下自動安裝。

B、以上安裝方法最終都會調用到包管理器Package Manager。

C、Package Manager對安裝包進行一系列(如簽名、組件信息)處理後,通過local socket通知守護進程installed。

D、守護進程installd啟動dex2oat。

E、Dex2oat對安裝包中的classes.dex進行優化,生成優化後的文件。

2、動態加載過程

A、在java代碼中利用DexClassLoader或者PathClassLoader來動態加載dex、zip或者jar文件,調用到native層的DexFile_openDexFileNative。

Art模式下,Android源代碼如何“金蟬脫殼”?

圖1

Art模式下,Android源代碼如何“金蟬脫殼”?

圖2

Art模式下,Android源代碼如何“金蟬脫殼”?

圖3

B、DexFile_openDexFileNative會使用ClassLinker在處理classes.dex文件。

C、ClassLinker和installd流程差不多,會啟動dex2oat來生成oat文件。

Art模式下,Android源代碼如何“金蟬脫殼”?

圖4

從1、2可以看出,無論是APK安裝,還是動態加載,最終都會調用dex2oat去生成dex文件對應的oat文件。

接下來再來看看dex2oat在幹什麼?

A、Dex2oat會打開installed或者GenerateOatFile傳過來的文件,這個文件可以是zip文件、jar文件(jar也是zip格式)或者dex文件。

Art模式下,Android源代碼如何“金蟬脫殼”?

圖5

這裡來個小插曲:還記得cve2017-13156嗎?這個漏洞可以繞過v1版本的APK簽名,插入惡意代碼。

有以下兩個原因:

IsZipMagic和IsDexMagic是通過文件頭部來判斷文件類型的,如果我們在一個zip文件或者jar文件頭部放置一個dex文件,那麼這個zip或jar文件會被當作dex文件處理;

另外v1版簽名只會校驗zip的數據,新加的dex不屬於zip文件數據,所以不會影響簽名。Google的修補方案是強制校驗zip或jar包的頭部,如果不是zip頭部(0x06054b50),就返回錯誤。具體代碼可參考/system/core/libziparchive/zip_archive.cc。

Art模式下,Android源代碼如何“金蟬脫殼”?

圖6

B、如果是zip或jar文件,在內存中解壓縮出classes.dex(如果是多dex,逐一解壓縮)。

C、將dex映射到內存,解析出dex結構,生成DexFile對象。

Art模式下,Android源代碼如何“金蟬脫殼”?

圖7

D、Dex2oat利用生成的DexFile對象創建oat文件,oat的創建過程我們不需要關心,只需要關注dex文件被映射到內存後是如何被還原解密的。

Art模式下,Android源代碼如何“金蟬脫殼”?

圖8

從dex到oat的過程瞭解後,我們再看看殼是如何工作的。

1、加殼流程

A、加殼時會把原dex加密放到特定目錄(不同殼放置的目錄不一樣)。

B、修改AndroidManifest中的Application為殼的Application,把原來的Application的類名稱放到其它地方。

C、用自己的dex替換掉原來的classes.dex。

D、在APK中加入自己的native模塊,在自己的Application引用自己的native文件。

2、被加殼應用啟動流程

A、被加殼應用安裝過程中,被dex2oat處理的是殼的classes.dex。

B、APK被啟動後,實際上是運行的殼代碼,調用殼的Application。

C、通常會在Application中加載native模塊,並在native 層hook文件相關操作(read、write等)。

D、動態加載加密的dex,通過LD_PRELOAD的環境變量,把自己的模塊注入到dex2oat進程中,同樣會hook dex2oat進程的文件相關操作,在讀取過程或者文件映射過程,動態解密原始dex。此時,在生成DexFile對象時就是解密後的文件,當dex2oat處理完成,要把處理結果寫入到磁盤時,再通過hook把數據加密。

E、在主進程加載oat文件時,在加載過程中,hook會把加密後的oat文件還原。

F、有些殼會阻止dex2oat對dex進行處理,讓代碼以dalvik字節碼方式解釋執行,但還是需要還原出原始dex文件。

在明白了APK的安裝和動態加載過程後,我們會發現,殼的流程其實是一個動態加載的過程,無論是安裝還是動態加載,在進行dex2oat的過程中,dex文件最終都會以DexFile對象的方式出現在內存裡面,並且是被還原後的。因此,我們可以通過DexFile對象還原出原始的dex文件。

接下來通過修改源代碼,在DexFile對象生成的時候把dex文件給提取出來,具體實現過程如下:

A、在aosp中,定位到/art/runtime/dex_file.cc中的DexFile類。

B、通過修改DexFile類,在DexFile對象初始化時加載我們的代碼,DexFile的參數包含了dex文件在內存中的位置、大小以及dex文件結構的相關信息,我們可以通過這些信息還原出原始dex。

有兩種情況:1、整體加密,這時完全可以dump出原始dex文件;2、對方法字節碼進行加密,只有這些類被首次引用時才動態解密,這時我們可以根據DexFile參數中的dex文件信息,對dex中的類手動引用一次,然後再dump,就可以還原出原始數據。

Art模式下,Android源代碼如何“金蟬脫殼”?

圖9

C、因為read、write等函數被hook,dump文件時不能直接調用libc裡面的此類函數,因此需要我們自己實現文件操作函數(用syscall函數或者彙編實現)。

Art模式下,Android源代碼如何“金蟬脫殼”?

圖10

D、脫殼模塊根據殼的種類進行分類處理。

Art模式下,Android源代碼如何“金蟬脫殼”?

圖11

下面是對脫殼結果的簡單演示,第一個是隻有一個dex文件,第二個是多dex文件。

Art模式下,Android源代碼如何“金蟬脫殼”?

圖12

Art模式下,Android源代碼如何“金蟬脫殼”?

圖13

Art模式下,Android源代碼如何“金蟬脫殼”?

圖14

Art模式下,Android源代碼如何“金蟬脫殼”?

圖15

動態脫殼過程很簡單,實現方式也有多種,文中所述方法只是起到拋磚引玉的作用,在瞭解了APK運行加載流程、運行機制、hook、Android源代碼編譯過程等基礎後,相信你也可以get到更加強大的脫殼方式!


分享到:


相關文章: