Dex文件格式

Dex文件格式

Google雖然借鑑了Java的上層設計,但是虛擬機使用的是自己設計的Dalvik,Dalvik虛擬機讀取、解釋的文件是DEX文件。雖然在Android 4.0開始,開始引入類似C#的二次編譯技術(Android自稱ART),Android 5.0已經完全放棄Dalvik虛擬機(所以源碼裏已經沒有Dalvik設計文檔了),但是,二次編譯技術是安裝apk時候的事,我們用Java語言所寫的代碼,還是要經過.java->.class->.dex->.apk的過程,認識Dex文件格式,還是有助於反彙編成Smali語言,有助於逆向。

dex生成流程

以下Makefile腳本展示了dex文件生成流程:

MODULE_NAME := Hello
START_CLASS := Hellk
DX := ${SDK_PATH}\sdk\build-tools\19.1.0\dx.bat
INSTALL_PATH := /data/local/tmp
 
#用dalvikvm虛擬機解釋運行dex文件,需要指定啓動類
run:
    adb push ${MODULE_NAME}.dex ${INSTALL_PATH}
    adb shell dalvikvm -cp ${INSTALL_PATH}/${MODULE_NAME}.dex ${START_CLASS}
 
dx: ${MODULE_NAME}.dex ${MODULE_NAME}.class
 
#通過.class生成dx
${MODULE_NAME}.dex: ${MODULE_NAME}.class
    ${DX} --dex --output=${MODULE_NAME}.dex ${MODULE_NAME}.class
     
javac: ${MODULE_NAME}.class
 
#dx所支持的.class版本一般不是最新的
${MODULE_NAME}.class:
    javac -source 1.6 -target 1.6 ${MODULE_NAME}.java

學習Dex文件的工具

推薦使用010 Editor軟件,它自帶模板插件功能,並且已經有他人製作好的針對Dex文件的模版。可以高亮顯示各字段,解析各字段,還附帶各字段的註釋。對照着Dalvik自帶的文檔看十六進制,事半功倍

Dex文件組成

按順序解析dex文件,有以下幾個部分:

  1. struct header_item dex_header
  2. struct string_id_list dex_string_ids
  3. struct type_id_list dex_type_ids
  4. struct proto_id_list dex_proto_ids
  5. struct field_id_list dex_field_ids
  6. struct method_id_list dex_method_ids
  7. struct class_def_item_list dex_class_defs
  8. struct map_list_type dex_map_list

其中兩頭兩尾的header_itemmap_list是兩張“總表”,包含着其它的表的偏移信息等,兩者信息有重疊(冗餘)。

各個表的功能及要求:

  1. string_id_item[]: 文件中要用到的所有字符串,按UTF-16編碼有序排列
  2. type_id_item[]: 文件中要用到的所有類型信息,但裏面並不直接記錄着字符串,而是string_id_item[]中的數組下標,且按string_id_item中的數組下標有序排列
  3. proto_id_item[]: 文件中要用到的所有方法原型,相當於所有函數指針的類型信息,也是有序排列的,主序是返回類型,次序是參數類型
  4. field_id_item[]: 文件中要用到的所有成員(含靜態與普通),按類的類型、成員名、成員類型優先級遞減有序排列。
  5. method_id_item[]: 文件中要用到的所有方法(含靜態與普通), 按類的類型、方法名、方法原型優先級遞減有序排列。
  6. class_def_item[]: 類的信息在此表中,從此表中,可以解析出內部類、靜態與普通成員/方法、Dalvik字符碼的位置等與類有關的具體信息,都在此表中

文件頭中的校驗

在文件頭中,以下幾項比較關鍵,影響到dex文件能否被dalvikvm正常執行:

  1. uint checksum: 文件0x8偏移處,通過alder32算法,針對文件0xC至文件尾得到的的校驗值。
  2. SHA1 signature[20]: 文件0xC偏移處,通過SHA1算法,鎮上 對文件0x20至文件尾得到的HASH值。
  3. uint file_size: 文件0x20偏移處,記錄文件長度

對Dex文件進行修改後,要依次更新file_size, signature[20], checksum三個字段,Dex才能正常運行。

dex的一些加固思路

大小尾標籤

在header_item中有一個uint endian_tag字段,記錄了常量0x12345678,dalvikvm在運行Dex文件時,會通過檢查這個字段,來決定是以小尾還是大尾方式來解釋dex文件(中的相關變量)。由於ARM與x86芯片都是小尾方式,現有的反彙編引擎都不會考慮這個字段(默認小尾),因此,若我們人爲修改這個字段爲大尾,並將dex文件中相關數據都反過來,可以對抗當前的各種反彙編引擎。

字符串混淆

因爲dex文件的信息都很集中,所以將string_id_item[]中的字符串替換爲無意義的字符串,整個文件中相關要用到的地方也同步更新了,可用此來混淆。有時候防守方做得太噁心了(如兩個函數名:”oooo0o”與”o0oooo”),可以用比較弱的混淆器對抗下(abc一類的名稱比數圈圈好)。

實踐方案

以上的實驗還只是針對dex的標識符的加固,不涉及代碼。實際操作中,可以:

  1. 得到正常的dex
  2. 修改dex中的各表項,使閱讀困難
  3. 用baksmali,反彙編成smali語法
  4. 針對smali文件,進行代碼混淆
  5. 重新編譯smali文件,得到加固後的dex文件

不過,不管怎樣混淆,dalvikvm畢竟是開源的,dex文件的強度都比較弱。

發佈了36 篇原創文章 · 獲贊 55 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章