2019年6月6日 星期四

Android 逆向 - 可執行檔案格式

markdown 要反組譯 Android 的程式,跟一般桌面 Java 應用程式比是要麻煩一些的,雖然 Android 上是用 Java 語言開發,但是底層的 Java 虛擬機並不是 Oracle 的 JVM,而是 Google 自己做的 Dalvik。而且從 Java 原始碼編譯出來的可執行檔案,隨著 Android 最佳化機制的演進,還會生成不同的檔案格式,因此要學 Android 逆向,首先要對這些編譯後的可執行檔案格式有些了解,在這篇會介紹一下這些檔案格式,幫自己理清思路,也順便做個筆記可供日後備查。 ## DEX 一般 Java 程式透過 javac 編譯後,得出的是一個一個 .class 檔案,內含 Java byte code,檔案格式為 [class file format](https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html),可以直接讓 JVM load 起來執行。但是 Android 自有的 Dalvik 虛擬機吃的不是 class 格式,而是 DEX 格式的檔案,DEX 也就是 Dalvik EXecutable 的意思。 要生成 DEX 格式檔案,在 Java 程式碼編譯為 class 檔案後,需用 Android 的 dx compiler (或是下一代 compiler [D8](https://developer.android.com/studio/command-line/d8)) 來將 class 檔再編譯成 DEX 檔案。 通常將 apk 解開來後,可以看到裡面都會有一個 classes.dex,這個就是 Dalvik 吃的 DEX 格式檔案,所有 App 的 Java 程式碼都會被編譯到這個檔案中。 ## ODEX Dalvik 在將 classes.dex 檔案跑起來的時候,會做一些最佳化例如將 virtual method 查找的動作移除改為直接呼叫某 index 上的 method 以節省時間,但這個動作是每次將 dex 載入時都會執行一次。為了節省這個時間,Android 將最佳化後的 dex 寫成檔案儲存到 Dalvik 的 cache 目錄中,也就是 odex 檔案,以後 Dalvik 要再執行同一個 App 時,載入的會是 cache 目錄中的 odex 檔。 這個 dex to odex 的轉換是由 Android 上自帶的工具 dexopt 完成的,odex 檔中大部分的內容都跟原本的 classes.dex 差不多,只是做了一些最佳化而已。 ## OAT Android 為了要讓 App 執行的更快速,在 Dalvik 中使用了 JIT 技術,將 Dalvik bytecode 轉換為 native code,但是 JIT 是在 App 執行過程中完成,而且是每次 App 跑起來都會做一次,這浪費了不必要的資源,因此在 Android 5.0 之後,採用了新的策略,在 App 安裝時就將 classes.dex 檔案裡的程式碼使用 Android 平台自帶的 dex2oat 工具編譯為 native code,並且將其放在另一種格式的檔案中。 這會造成 App 安裝的時間增加,但是 dex 到 native code 的轉換從此只要一次就好,而因為執行檔內容已經從 Dalvik bytecode 轉換為 native code 了,在這時期的虛擬機也從 Dalvik 變為 ART(Android Runtime) 來支援這種新執行檔格式。 這個新的檔案格式,實際上是一個 ELF 格式的檔案,但 ELF 只是一個殼,ELF 殼內存放的實際上是一個 Android 叫做 OAT 格式的資料。這可能不是那麼直觀,如果有網路封包概念的話,可以把它想像成類似 TCP/IP 封包架構,就像 MAC 封包的 payload 其實是 IP 封包,IP 封包的 payload 又是 TCP 封包。 而這個檔案的副檔名通常會是 .odex 或是 .oat,這可能也會讓人混淆,因為 Dalvik 時期 dex 最佳化後的檔案也叫 odex,因此 Android 上的副檔名不太可信,還是要實際看文件內容才能確定到底是甚麼格式的檔案。 要逆向 OAT 中的 native code 是極為困難的,但好在 OAT 檔案中已經包含了原本的 dex 檔案,說原本的也不太準確,它包含的是經過最佳化後的 dex 檔,但跟 native code 比起來還是好太多了,因此可以先從 OAT 中將 dex 提取出來,再作逆向。 ## VDEX 在 Android 8.0 之後,dex2oat 生成的不再是單一個 OAT 檔案,而是生成兩個檔案 classes.odex 跟 classes.vdex。 * classex.odex:包含 native code 的 OAT 檔 * classes.vdex:原本的 dex 檔的副本 這個時候要逆向,一樣可以從 vdex 中提取出 dex 檔,再作逆向 ## 結語 Android 上可執行檔的格式有 vdex、odex、oat、dex,其中又跟虛擬機 Dalvik、ART 牽扯在一起,要理清其中的關係的確不是那麼容易,在網路上看到一張圖,算是將這些檔案間的關係描述的相當清楚,放在這邊分享一下。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjdeIcIxbiOf2Bapn5YTfCIu3RMRVoHfFCmNVOkpMfg4bm2wO-EULWPambG_jNX2-SiMQQRJgHIHA_UmWDy3TFMcmSl1rZfJz0QE6Qg6Z_WkzOWlI-_EVfBnIQL96R71de0q6QwMPvWmTOe/s1600/658px-ART_view.png) Reference: * [Android formats](https://lief.quarkslab.com/doc/latest/tutorials/10_android_formats.html) * [Configuring ART](https://source.android.com/devices/tech/dalvik/configure) * [Android运行时ART加载OAT文件的过程分析](https://blog.csdn.net/Luoshengyang/article/details/39307813) * [Android ART运行时无缝替换Dalvik虚拟机的过程分析](https://blog.csdn.net/luoshengyang/article/details/18006645) * [ART view](https://en.wikipedia.org/wiki/File:ART_view.png)

沒有留言:

張貼留言