一篇文章带你搞懂 DEX 文件的结构
?
From:https://blog.csdn.net/sinat_18268881/article/details/55832757
Dex文件格式詳解:https://www.jianshu.com/p/f7f0a712ddfe
dex文件解析(第三篇):https://blog.csdn.net/tabactivity/article/details/78950379
深入理解DEX文件格式( 有個 Python 讀 dex 文件?):https://mybeibei.net/archives/1103
一文讀懂 DEX 文件格式解析:https://cloud.tencent.com/developer/article/1663852
Android逆向之旅—解析編譯之后的Dex文件格式:http://www.520monkey.com/archives/579
圖解Dex文件結(jié)構(gòu)及解析要點:https://blog.csdn.net/beyond702/article/details/52460721
從 Android 運行時出發(fā),打造我們的脫殼神器:https://blog.csdn.net/earbao/article/details/51516116
? ? ? ? ? ??http://www.droidsec.cn/從android運行時出發(fā),打造我們的脫殼神器/
?
參考資料:《Android軟件安全與逆向分析》.非蟲
?
?
?
0x00■ ?構(gòu)造 DEX 文件
?
什么是 dex 文件?
DEX 文件就是 Android Dalvik 虛擬機運行的程序,關(guān)于 DEX 文件的結(jié)構(gòu)的重要性我就不多說了。
dex ?是 Android 系統(tǒng)的可執(zhí)行文件,包含應(yīng)用程序的全部操作指令以及運行時數(shù)據(jù)。
簡單的說,就是優(yōu)化后的 android版.exe。每個apk安裝包里都有。相對于PC上的 java 虛擬機能運行.class;android上的 Davlik 虛擬機能運行.dex。
?
為何要研究 dex 格式 ?
因為 dex 里面包含了所有 app 代碼,利用反編譯工具可以獲取 java 源碼。理解并修改 dex 文件,就能更好的 逆向?APK。
由于dalvik是一種針對嵌入式設(shè)備而特殊設(shè)計的java虛擬機,所以dex文件與標準的class文件在結(jié)構(gòu)設(shè)計上有著本質(zhì)的區(qū)別
當 java 程序編譯成 class 后,還需要使用 dx 工具將所有的 class 文件整合到一個 dex 文件,目的是其中各個類能夠共享數(shù)據(jù),在一定程度上降低了冗余,同時也是文件結(jié)構(gòu)更加經(jīng)湊,實驗表明,dex 文件是傳統(tǒng) jar 文件大小的 50% 左右
可以看見:dex 將原來 class 每個文件都有的共有信息合成一體,這樣減少了 class 的冗余
數(shù)據(jù)結(jié)構(gòu)
| u1 | unit8_t,1字節(jié)無符號數(shù) |
| u2 | unit16_t,2字節(jié)無符號數(shù) |
| u4 | unit32_t,4字節(jié)無符號數(shù) |
| u8 | unit64_t,8字節(jié)無符號數(shù) |
| sleb128 | 有符號LEB128,可變長度1~5 |
| uleb128 | 無符號LEB128, |
| uleb128p1 | 無符號LEB128值加1, |
其中 u1~u8 很好理解,表示 1 到 8 個字節(jié)的無符號數(shù),后面三個是dex特有的數(shù)據(jù)類型,
不理解的可以參考這里(?https://blog.csdn.net/zklth/article/details/7978362 )
更詳細的參考:(深入到源碼解析leb128數(shù)據(jù)類型)[http://i.woblog.cn/2016/07/23/leb128-format/]
?
下面開練。。。。。
建議:不要只看,跟著做。看再多遍不如自己親自實踐一遍來的可靠,別問我為什么知道。淚崩ing.....
下面會自己構(gòu)造一個 dex 文件,因為自己構(gòu)造的比較簡單,分析起來比較容易。等你簡單的會了,難的自然也就懂了。
首先,編寫一個簡單的 Java 程序,如下:
public class HelloWorld { int a = 0; static String b = "HelloDalvik"; public int getNumber(int i, int j) { int e = 3; return e + i + j; } public static void main(String[] args) { int c = 1; int d = 2; HelloWorld helloWorld = new HelloWorld(); String sayNumber = String.valueOf(helloWorld.getNumber(c, d)); System.out.println("HelloDex!" + sayNumber); } }然后將其編譯成 dex 文件:打開命令行,進入 HelloWorld.class 所在文件夾下,執(zhí)行命令:
javac HelloWorld.java接下來會出現(xiàn)一個HelloWorld.class文件,然后繼續(xù)執(zhí)行命令( dx 工具需要安裝Android SDK才能有的工具 ):
dx --dex --output=HelloWorld.dex HelloWorld.class就會出現(xiàn) HelloWorld.dex 文件了。
在當前工作路徑下 , 編譯方法如下 :
1. 編譯成 java class 文件,執(zhí)行命令 : javac Hello.java? 。編譯完成后 ,目錄下生成 Hello.class 文件 。可以使用命令 java Hello 來測試下 ,會輸出代碼中的 “Hello, Android!” 的字符串 。
2. 編譯成 dex 文件
編譯工具在 Android SDK 的路徑如下 ,其中 19.0.1 是Android SDK build_tools 的版本 ,請按照在本地安裝的 build_tools 版本來 。建議該路徑加載到 PATH 路徑下 ,否則引用 dx 工具時需要使用絕對路徑 :./build-tools/19.0.1/dx
執(zhí)行命令 :?dx –dex –output=Hello.dex Hello.class
編譯正常會生成 Hello.dex 文件 。
3. 使用 ADB 運行測試
? ? ? ? 測試命令和輸出結(jié)果如下 :
? ? ? ? $ adb root
? ? ? ? $ adb push Hello.dex /sdcard/
? ? ? ? $ adb shell
? ? ? ? root@maguro:/ # dalvikvm -cp /sdcard/Hello.dex Hello
4. 重要說明
(1) 測試環(huán)境使用真機和 Android 虛擬機都可以的 。核心的命令是
dalvikvm -cp /sdcard/Hello.dex Hello
-cp 是 class path 的縮寫 ,后面的 Hello 是要運行的 Class 的名稱 。網(wǎng)上有描述說輸入 dalvikvm –help
可以看到 dalvikvm 的幫助文檔 ,但是在 Android4.4 的官方模擬器和自己的手機上測試都提示找不到
Class 路徑 ,在Android 老的版本 ( 4.3 ) 上測試還是有輸出的 。
(2) 因為命令在執(zhí)行時 , dalvikvm 會在 /data/dalvik-cache/ 目錄下創(chuàng)建 .dex 文件 ,因此要求 ADB 的
執(zhí)行 Shell 對目錄 /data/dalvik-cache/ 有讀、寫和執(zhí)行的權(quán)限 ,否則無法達到預(yù)期效果 。
?
這時,我們需要下載一個十六進位文本編輯器,因為用它可以解析二進制文件,我們用它打開 dex 文件就會全部以十六進制的數(shù)進行展現(xiàn)了。
這里推薦 010Editor,下載地址:https://www.sweetscape.com/010editor/(收費軟件,可以免費試用30天)。
下載完成之后,我們可以用它打開dex文件了,打開之后,你的界面應(yīng)該是這樣的:
一下子看到這些東西,是不是立馬懵逼了,正常,我剛開始看的時候也是,這什么玩意兒啊!其實,這就是二進制流文件中的內(nèi)容,010Editor把它轉(zhuǎn)化成了16進制的內(nèi)容,以方便我們閱讀的。
?
?
0x01■ ?DEX文件結(jié)構(gòu)總覽
?
一張圖搞懂dex
( 可以 右鍵 ---> 在新標簽頁中打開圖片 ,就可以看清圖片)
不要慌,下面我跟你解釋,這些東西我們雖然看了懵逼,但是 Dalvik 虛擬機不會,因為它就是解析這些東西的,這些東西雖然看起來頭大,但是它是有自己的格式標準的。dex文件的結(jié)構(gòu)如下圖所示:
這就是 dex 的文件格式了,下面我們從最上面的 Header 說起,Header 中存儲了什么內(nèi)容呢?下面我們還得來一張圖:
從宏觀上來說 dex 的文件結(jié)果很簡單,實際上是由多個不同結(jié)構(gòu)的數(shù)據(jù)體以首尾相接的方式拼接而成。如下圖:
| header | dex文件頭部,記錄整個dex文件的相關(guān)屬性 |
| string_ids | 字符串數(shù)據(jù)索引,記錄了每個字符串在數(shù)據(jù)區(qū)的偏移量 |
| type_ids | 類似數(shù)據(jù)索引,記錄了每個類型的字符串索引 |
| proto_ids | 原型數(shù)據(jù)索引,記錄了方法聲明的字符串,返回類型字符串,參數(shù)列表 |
| field_ids | 字段數(shù)據(jù)索引,記錄了所屬類,類型以及方法名 |
| method_ids | 類方法索引,記錄方法所屬類名,方法聲明以及方法名等信息 |
| class_defs | 類定義數(shù)據(jù)索引,記錄指定類各類信息,包括接口,超類,類數(shù)據(jù)偏移量 |
| data | 數(shù)據(jù)區(qū),保存了各個類的真是數(shù)據(jù) |
| link_data | 連接數(shù)據(jù)區(qū) |
/dalvik/libdex/DexFile.h? 定義如下:
struct DexFile {const DexHeader* pHeader;const DexStringId* pStringIds;const DexTypeId* pTypeIds;const DexFieldId* pFieldIds;const DexMethodId* pMethodIds;const DexProtoId* pProtoIds;const DexClassDef* pClassDefs;const DexLink* pLinkData; }注意:其中一些定義的字段是在內(nèi)存中并沒有存到真實的 dex 文件中
header 簡單記錄了dex文件的一些基本信息,以及大致的數(shù)據(jù)分布。長度固定為0x70,其中每一項信息所占用的內(nèi)存空間也是固定的,好處是虛擬機在處理 dex 時不用考慮 dex 文件的多樣性
| magic | 0x0 | 8 | 魔數(shù)字段,值為"dex\n035\0" |
| checksum | 0x8 | 4 | 校驗碼 |
| signature | 0xc | 20 | sha-1簽名 |
| file_size | 0x20 | 4 | dex文件總長度 |
| header_size | 0x24 | 4 | 文件頭長度,009版本=0x5c,035版本=0x70 |
| endian_tag | 0x28 | 4 | 標示字節(jié)順序的常量 |
| link_size | 0x2c | 4 | 鏈接段的大小,如果為0就是靜態(tài)鏈接 |
| link_off | 0x30 | 4 | 鏈接段的開始位置 |
| map_off | 0x34 | 4 | map數(shù)據(jù)基址 |
| string_ids_size | 0x38 | 4 | 字符串列表中字符串個數(shù) |
| string_ids_off | 0x3c | 4 | 字符串列表基址 |
| type_ids_size | 0x40 | 4 | 類列表里的類型個數(shù) |
| type_ids_off | 0x44 | 4 | 類列表基址 |
| proto_ids_size | 0x48 | 4 | 原型列表里面的原型個數(shù) |
| proto_ids_off | 0x4c | 4 | 原型列表基址 |
| field_ids_size | 0x50 | 4 | 字段個數(shù) |
| field_ids_off | 0x54 | 4 | 字段列表基址 |
| method_ids_size | 0x58 | 4 | 方法個數(shù) |
| method_ids_off | 0x5c | 4 | 方法列表基址 |
| class_defs_size | 0x60 | 4 | 類定義標中類的個數(shù) |
| class_defs_off | 0x64 | 4 | 類定義列表基址 |
| data_size | 0x68 | 4 | 數(shù)據(jù)段的大小,必須4k對齊 |
| data_off | 0x6c | 4 | 數(shù)據(jù)段基址 |
/dalvik/libdex/DexFile.h? 定義如下:
struct DexHeader {u1 magic[8]; /* includes version number */u4 checksum; /* adler32 checksum */u1 signature[kSHA1DigestLen]; /* SHA-1 hash */u4 fileSize; /* length of entire file */u4 headerSize; /* offset to start of next section */u4 endianTag;u4 linkSize;u4 linkOff;u4 mapOff;u4 stringIdsSize;u4 stringIdsOff;u4 typeIdsSize;u4 typeIdsOff;u4 protoIdsSize;u4 protoIdsOff;u4 fieldIdsSize;u4 fieldIdsOff;u4 methodIdsSize;u4 methodIdsOff;u4 classDefsSize;u4 classDefsOff;u4 dataSize;u4 dataOff; };我們可以用:hexdump -c classes.dex 查看 dex 單字節(jié)顯示的結(jié)果,如下:
0000000 d e x \n 0 3 5 \0 022 217 ? w z ? 031 221 0000010 ? \f ? ? ? ? ? ? 217 235 200 z ? 030 I ? 0000020 ? 003 \0 \0 p \0 \0 \0 x V 4 022 \0 \0 \0 \0 0000030 \0 \0 \0 \0 ? 002 \0 \0 024 \0 \0 \0 p \0 \0 \0 0000040 \b \0 \0 \0 ? \0 \0 \0 005 \0 \0 \0 ? \0 \0 \0 0000050 001 \0 \0 \0 034 001 \0 \0 005 \0 \0 \0 $ 001 \0 \0 0000060 001 \0 \0 \0 L 001 \0 \0 8 002 \0 \0 l 001 \0 \0 0000070 l 001 \0 \0 t 001 \0 \0 201 001 \0 \0 204 001 \0 \0 0000080 222 001 \0 \0 226 001 \0 \0 ? 001 \0 \0 ? 001 \0 \0 0000090 ? 001 \0 \0 ? 001 \0 \0 004 002 \0 \0 \a 002 \0 \0 00000a0 \v 002 \0 \0 002 \0 \0 ( 002 \0 \0 . 002 \0 \0 00000b0 4 002 \0 \0 9 002 \0 \0 B 002 \0 \0 L 002 \0 \0 00000c0 003 \0 \0 \0 005 \0 \0 \0 006 \0 \0 \0 \a \0 \0 \0 00000d0 \b \0 \0 \0 \t \0 \0 \0 \n \0 \0 \0 \f \0 \0 \0 00000e0 002 \0 \0 \0 003 \0 \0 \0 \0 \0 \0 \0 004 \0 \0 \0 00000f0 004 \0 \0 \0 x 002 \0 \0 \n \0 \0 \0 006 \0 \0 \0 0000100 \0 \0 \0 \0 \v \0 \0 \0 006 \0 \0 \0 x 002 \0 \0 0000110 \v \0 \0 \0 006 \0 \0 \0 p 002 \0 \0 005 \0 001 \0 0000120 020 \0 \0 \0 \0 \0 004 \0 017 \0 \0 \0 001 \0 003 \0 0000130 021 \0 \0 \0 004 \0 002 \0 \0 \0 \0 \0 004 \0 001 \0 0000140 \r \0 \0 \0 004 \0 \0 \0 022 \0 \0 \0 \0 \0 \0 \0 0000150 001 \0 \0 \0 002 \0 \0 \0 \0 \0 \0 \0 ? ? ? ? 0000160 \0 \0 \0 \0 ? 002 \0 \0 \0 \0 \0 \0 006 < i n 0000170 i t > \0 \v H e l l o W o r l d 0000180 \0 001 L \0 \f L H e l l o W o r l d 0000190 ; \0 002 L L \0 025 L j a v a / i o / 00001a0 P r i n t S t r e a m ; \0 022 L j 00001b0 a v a / l a n g / O b j e c t ; 00001c0 \0 022 L j a v a / l a n g / S t r 00001d0 i n g ; \0 031 L j a v a / l a n g 00001e0 / S t r i n g B u i l d e r ; \0 00001f0 022 L j a v a / l a n g / S y s t 0000200 e m ; \0 001 V \0 002 V L \0 023 [ L j a 0000210 v a / l a n g / S t r i n g ; \0 0000220 006 a p p e n d \0 004 a r g s \0 004 m 0000230 a i n \0 003 o u t \0 \a p r i n t l 0000240 n \0 \b t o S t r i n g \0 016 ? ? 231 0000250 ? 230 ? ? ? 200 ? ? ? ? 211 213 ? 206 231 ? 0000260 232 204 s m a l i ? ? 236 ? ? 213 \0 \0 \0 0000270 001 \0 \0 \0 \a \0 \0 \0 001 \0 \0 \0 003 \0 \0 \0 0000280 \0 \0 \0 \0 \0 \0 \0 \0 \0 001 017 \a \0 \0 \0 \0 0000290 \v \0 001 \0 002 \0 \0 \0 210 002 \0 \0 ( \0 \0 \0 00002a0 b \0 \0 \0 \0 \0 \0 \0 \0 \0 022 2 023 003 ? ? 00002b0 030 004 \0 \0 001 \0 \0 \0 \0 \0 034 005 003 \0 001 & 00002c0 " \a 004 \0 p 020 002 \0 \a \0 032 \b 023 \0 n 00002d0 003 \0 207 \0 \f \a n 020 004 \0 \a \0 \f \t n 00002e0 001 \0 220 \0 032 001 001 \0 n 001 \0 020 \0 016 \0 00002f0 \0 \0 001 \0 \0 \t 220 005 016 \0 \0 \0 \0 \0 \0 \0 0000300 001 \0 \0 \0 \0 \0 \0 \0 001 \0 \0 \0 024 \0 \0 \0 0000310 p \0 \0 \0 002 \0 \0 \0 \b \0 \0 \0 ? \0 \0 \0 0000320 003 \0 \0 \0 005 \0 \0 \0 ? \0 \0 \0 004 \0 \0 \0 0000330 001 \0 \0 \0 034 001 \0 \0 005 \0 \0 \0 005 \0 \0 \0 0000340 $ 001 \0 \0 006 \0 \0 \0 001 \0 \0 \0 L 001 \0 \0 0000350 002 \0 \0 024 \0 \0 \0 l 001 \0 \0 001 020 \0 \0 0000360 002 \0 \0 \0 p 002 \0 \0 003 020 \0 \0 002 \0 \0 \0 0000370 200 002 \0 \0 003 \0 \0 001 \0 \0 \0 210 002 \0 \0 0000380 001 \0 \0 001 \0 \0 \0 220 002 \0 \0 \0 \0 \0 0000390 001 \0 \0 \0 ? 002 \0 \0 \0 020 \0 \0 001 \0 \0 \0 00003a0 ? 002 \0 \0 00003a4還可以用 -C 顯示 16 進制 和 ASCII碼:hexdump -C classes.dex
00000000 64 65 78 0a 30 33 35 00 12 8f b1 77 7a e9 19 91 |dex.035....wz...| 00000010 f2 0c ff ce a0 ce aa cd 8f 9d 80 7a ac 18 49 bf |...........z..I.| 00000020 a4 03 00 00 70 00 00 00 78 56 34 12 00 00 00 00 |....p...xV4.....| 00000030 00 00 00 00 f8 02 00 00 14 00 00 00 70 00 00 00 |............p...| 00000040 08 00 00 00 c0 00 00 00 05 00 00 00 e0 00 00 00 |................| 00000050 01 00 00 00 1c 01 00 00 05 00 00 00 24 01 00 00 |............$...| 00000060 01 00 00 00 4c 01 00 00 38 02 00 00 6c 01 00 00 |....L...8...l...| 00000070 6c 01 00 00 74 01 00 00 81 01 00 00 84 01 00 00 |l...t...........| 00000080 92 01 00 00 96 01 00 00 ad 01 00 00 c1 01 00 00 |................| 00000090 d5 01 00 00 f0 01 00 00 04 02 00 00 07 02 00 00 |................| 000000a0 0b 02 00 00 20 02 00 00 28 02 00 00 2e 02 00 00 |.... ...(.......| 000000b0 34 02 00 00 39 02 00 00 42 02 00 00 4c 02 00 00 |4...9...B...L...| 000000c0 03 00 00 00 05 00 00 00 06 00 00 00 07 00 00 00 |................| 000000d0 08 00 00 00 09 00 00 00 0a 00 00 00 0c 00 00 00 |................| 000000e0 02 00 00 00 03 00 00 00 00 00 00 00 04 00 00 00 |................| 000000f0 04 00 00 00 78 02 00 00 0a 00 00 00 06 00 00 00 |....x...........| 00000100 00 00 00 00 0b 00 00 00 06 00 00 00 78 02 00 00 |............x...| 00000110 0b 00 00 00 06 00 00 00 70 02 00 00 05 00 01 00 |........p.......| 00000120 10 00 00 00 00 00 04 00 0f 00 00 00 01 00 03 00 |................| 00000130 11 00 00 00 04 00 02 00 00 00 00 00 04 00 01 00 |................| 00000140 0d 00 00 00 04 00 00 00 12 00 00 00 00 00 00 00 |................| 00000150 01 00 00 00 02 00 00 00 00 00 00 00 ff ff ff ff |................| 00000160 00 00 00 00 f0 02 00 00 00 00 00 00 06 3c 69 6e |.............<in| 00000170 69 74 3e 00 0b 48 65 6c 6c 6f 20 57 6f 72 6c 64 |it>..Hello World| 00000180 00 01 4c 00 0c 4c 48 65 6c 6c 6f 57 6f 72 6c 64 |..L..LHelloWorld| 00000190 3b 00 02 4c 4c 00 15 4c 6a 61 76 61 2f 69 6f 2f |;..LL..Ljava/io/| 000001a0 50 72 69 6e 74 53 74 72 65 61 6d 3b 00 12 4c 6a |PrintStream;..Lj| 000001b0 61 76 61 2f 6c 61 6e 67 2f 4f 62 6a 65 63 74 3b |ava/lang/Object;| 000001c0 00 12 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 74 72 |..Ljava/lang/Str| 000001d0 69 6e 67 3b 00 19 4c 6a 61 76 61 2f 6c 61 6e 67 |ing;..Ljava/lang| 000001e0 2f 53 74 72 69 6e 67 42 75 69 6c 64 65 72 3b 00 |/StringBuilder;.| 000001f0 12 4c 6a 61 76 61 2f 6c 61 6e 67 2f 53 79 73 74 |.Ljava/lang/Syst| 00000200 65 6d 3b 00 01 56 00 02 56 4c 00 13 5b 4c 6a 61 |em;..V..VL..[Lja| 00000210 76 61 2f 6c 61 6e 67 2f 53 74 72 69 6e 67 3b 00 |va/lang/String;.| 00000220 06 61 70 70 65 6e 64 00 04 61 72 67 73 00 04 6d |.append..args..m| 00000230 61 69 6e 00 03 6f 75 74 00 07 70 72 69 6e 74 6c |ain..out..printl| 00000240 6e 00 08 74 6f 53 74 72 69 6e 67 00 0e e8 bf 99 |n..toString.....| 00000250 e6 98 af e4 b8 80 e4 b8 aa e6 89 8b e5 86 99 e7 |................| 00000260 9a 84 73 6d 61 6c 69 e5 ae 9e e4 be 8b 00 00 00 |..smali.........| 00000270 01 00 00 00 07 00 00 00 01 00 00 00 03 00 00 00 |................| 00000280 00 00 00 00 00 00 00 00 00 01 0f 07 00 00 00 00 |................| 00000290 0b 00 01 00 02 00 00 00 88 02 00 00 28 00 00 00 |............(...| 000002a0 62 00 00 00 00 00 00 00 00 00 12 32 13 03 ff ff |b..........2....| 000002b0 18 04 00 00 01 00 00 00 00 00 1c 05 03 00 01 26 |...............&| 000002c0 22 07 04 00 70 10 02 00 07 00 1a 08 13 00 6e 20 |"...p.........n | 000002d0 03 00 87 00 0c 07 6e 10 04 00 07 00 0c 09 6e 20 |......n.......n | 000002e0 01 00 90 00 1a 01 01 00 6e 20 01 00 10 00 0e 00 |........n ......| 000002f0 00 00 01 00 00 09 90 05 0e 00 00 00 00 00 00 00 |................| 00000300 01 00 00 00 00 00 00 00 01 00 00 00 14 00 00 00 |................| 00000310 70 00 00 00 02 00 00 00 08 00 00 00 c0 00 00 00 |p...............| 00000320 03 00 00 00 05 00 00 00 e0 00 00 00 04 00 00 00 |................| 00000330 01 00 00 00 1c 01 00 00 05 00 00 00 05 00 00 00 |................| 00000340 24 01 00 00 06 00 00 00 01 00 00 00 4c 01 00 00 |$...........L...| 00000350 02 20 00 00 14 00 00 00 6c 01 00 00 01 10 00 00 |. ......l.......| 00000360 02 00 00 00 70 02 00 00 03 10 00 00 02 00 00 00 |....p...........| 00000370 80 02 00 00 03 20 00 00 01 00 00 00 88 02 00 00 |..... ..........| 00000380 01 20 00 00 01 00 00 00 90 02 00 00 00 20 00 00 |. ........... ..| 00000390 01 00 00 00 f0 02 00 00 00 10 00 00 01 00 00 00 |................| 000003a0 f8 02 00 00 |....| 000003a4?
?
0x02■ ?DEX文件結(jié)構(gòu)解析
先看下就行,不用著急,下面我們一步一步來,首先點擊你的010Editor的這里:
對,就是箭頭指的那里,點擊之后,你會發(fā)現(xiàn)上面的有一片區(qū)域成了選中的顏色,這部分里面存儲的就是Header中的數(shù)據(jù)了,下面我們根據(jù)Header的數(shù)據(jù)圖以此來進行分析。
首先,我們看到DexHeader中每個數(shù)據(jù)前面有個u1或者u4,這個是什么意思呢?它們其實就是代表1個或者4個字節(jié)的無符號數(shù)。下面我們依次根據(jù)Header中的數(shù)據(jù)段進行解釋。
?
1. 從第一個看起,magic[8];它代表dex中的文件標識,一般被稱為魔數(shù)。是用來識別dex這種文件的,它可以判斷當前的dex文件是否有效,可以看到它用了8個1字節(jié)的無符號數(shù)來表示,我們在010Editor中可以看到也就是“64 65 78 0A 30 33 35 00 ”這8個字節(jié),這些字節(jié)都是用16進制表示的,用16進制表示的話,兩個數(shù)代表一個字節(jié)(一個字節(jié)等于8位,一個16進制的數(shù)能表示4位)。這8個字節(jié)用ASCII碼表轉(zhuǎn)化一下可以轉(zhuǎn)化為:dex.035(點擊這里可以進行十六進制轉(zhuǎn)ASCII,你可以試試:其中,'.' 不是轉(zhuǎn)化來的)。目前,dex的魔數(shù)固定為dex.035。
?
2.?第二個是,checksum; ?它是dex文件的校驗和,通過它可以判斷dex文件是否被損壞或者被篡改。它占用4個字節(jié),也就是“5D 9D F9 59”。這里提醒一下,在010Editor中,其實可以分別識別我們在DexHeader中看到的這些字段的,你可以點一下這里:
你可以看到這個header列表展開了,其實我們分析下來就和它這個結(jié)構(gòu)是一樣的,你可以先看下,我們現(xiàn)在分析到了checksum中了,你可以看到后面對應(yīng)的值是“59 F9 9D 5D”。咦?這好像和上面的字節(jié)不是一一對應(yīng)的啊。對的,你可以發(fā)現(xiàn)它是反著寫的。這是由于dex文件中采用的是小字節(jié)序的編碼方式,也就是低位上存儲的就是低字節(jié)內(nèi)容,所以它們應(yīng)該要反一下。
?
3.?第三個到了 signature[kSHA1DigestLen] 了,signature字段用于檢驗dex文件,其實就是把整個dex文件用SHA-1簽名得到的一個值。這里占用20個字節(jié),你可以自己點010Editor看一看。
?
4.?第四個 fileSize ;表示整個文件的大小,占用4個字節(jié)。
?
5.?第五個 headerSize ;表示 DexHeader 頭結(jié)構(gòu)的大小,占用4個字節(jié)。
可以看到它一共占用了112個字節(jié),112對應(yīng)的16進制數(shù)為70h。
?
?6. 第6個是 endianTag ;代表 字節(jié)序標記,用于指定dex運行環(huán)境的cpu,預(yù)設(shè)值為0x12345678,對應(yīng)在101Editor中為“78 56 34 12”(小字節(jié)序)。
?
7.?接下來兩個分別是 linkSize 和 u4 ?linkOff ;這兩個字段,它們分別指定了鏈接段的大小和文件偏移,通常情況下它們都為0。linkSize 為 0 的話表示靜態(tài)鏈接。
?
8.?再下來就是 mapOff 字段了,它指定了DexMapList的文件偏移,這里我們先不過多介紹它,你可以看一下它的值為“14 04 00 00”,它其實對應(yīng)的16進制數(shù)就是414h(別忘了小字節(jié)序),我們可以在414h的位置看一下它在哪里:
其實就是dex文件最后一部分內(nèi)容。關(guān)于這部分內(nèi)容里面是什么,我們先不說,繼續(xù)往下看。
?
9.?stringIdsSize 和 stringIdsOff 字段:這兩個字段指定了dex文件中所有用到的字符串的個數(shù)和位置偏移,我們先看stringIdsSize,它的值為:“1C 00 00 00”,16進制的1C也就是十進制的28,也就是說我們這個dex文件中一共有28個字符串,然后stringIdsOff為:“70 00 00 00”,代表字符串的偏移位置為70h,這下我們找到70h的地方:
這下我們就要先介紹一下DexStringId這個結(jié)構(gòu)了,圖中從70h開始,所有被選中的都是DexStringId這種數(shù)據(jù)結(jié)構(gòu)的內(nèi)容,DexStringId代表的是字符串的位置偏移,每個DexStringId占用4個字節(jié),也就是說它里面存的還不是真正的字符串,它們只是存儲了真正字符串的偏移位置。
下面我們先分析幾個看看,
① 取第一個“B2 02 00 00”,它代表的位置偏移是2B2h,我們先找到這個位置: ? ?
可以發(fā)現(xiàn)我一共選中了10個字節(jié),這10個字節(jié)就表示了一個字符串。下面我們看一下dex文件中的字符串是如何表示的。dex中的字符串采用了一種叫做MUTF-8這樣的編碼,它是經(jīng)過傳統(tǒng)的UTF-8編碼修改的。在MTUF-8中,它的頭部存放的是由uleb128編碼的字符的個數(shù)。(至于uleb128編碼是什么編碼,這里我不詳細展開說,有興趣的可以搜索看看。)
也就是說在“08 3C 63 6C 69 6E 69 74 3E 00”這些字節(jié)中,第一個08指定的是后面需要用到的編碼的個數(shù),也就是8個,即“ 3C 63 6C 69 6E 69 74 3E”這8個,但是我們?yōu)槭裁匆还策x中了10個字節(jié)呢,因為最后一個空字符“0”表示的是字符串的結(jié)尾,字符個數(shù)沒有把它算進去。下面我們來看看“ 3C 63 6C 69 6E 69 74 3E”這8個字符代表了什么字符串:
依舊可以點這里查詢ASCII (?http://www.ab126.com/goju/1711.html )。(要說明的一點是,這里湊巧這幾個uleb128編碼的字符都用了1個字節(jié),所以我們可以這樣進行查詢,uleb128編碼標準用的是1~5個字節(jié), 這里只是恰好都是一個字節(jié))。也就是說上面的70h開始的第一個DexStringId指向的其實是字符串“<clinit>”(但是貌似我們的代碼中沒有用到這個字符串啊,先不用管,我們接著分析)。再看到這里:
② 剛剛我們分析到“B2 02 00 00”所指向的真實字符串了,下面我們接著再分析一個,我們直接分析第三個,不分析第二個了。第三個為“C4 02 00 00”,對應(yīng)的位置也就是2C4h,我們找到它:
看這里,這就是2C4h的位置了。我們首先看第一個字符,它的值為0Bh,也就是十進制的11,也就是說接下來的11個字符代表了它的字符串,我們依舊是查看接下來11個字符代表的是什么,經(jīng)過查詢整理: ??
依舊可以點這里查詢ASCII (?http://www.ab126.com/goju/1711.html )。上面就是“HelloDalvik”這個字符串,可以看看我們的代碼,我們確實用了一個這樣的字符串,bingo。下面剩下的字符串就不分析了。經(jīng)過整理,可以整理出我們一共用到的28個字符串為:
ok,字符串這里告一段落,下面我們繼續(xù)看DexHeader的下面的字段。頭好暈~乎乎
?噢,讀了,還不能結(jié)束呢,你現(xiàn)在可以看一下最開始發(fā)的那張dex結(jié)構(gòu)圖了:
看到了吧,我們這半天分析的stringIdsSize 和 stringIdsOff字段指向的位置就是上面那個箭頭指向的位置,它們里面存儲的是真實字符串的位置偏移,它們都存儲在data區(qū)域。(先透露一下,后面我們要分析的幾個也和stringIdsSize 與stringIdsOff字段類似,它們里面存儲的基本都是位置偏移,并不是真正的數(shù)據(jù),真正的數(shù)據(jù)都在data區(qū)域)
好,我們繼續(xù)。
?
10. 繼續(xù)看DexHeader圖,我們現(xiàn)在該typeIdsSize和typeIdsOff了。它們代表什么呢?它們代表的是類的類型的數(shù)量和位置偏移,也是都占4個字節(jié),下面我們看它們的值
可以看到,typeIdsSize的值為9h,也就是我們dex文件中用到的類的類型一共有9個,位置偏移在E0h位置,下面我們找到這個位置
看到了吧,我選中的位置就是了。這里我們又得介紹一種數(shù)據(jù)結(jié)構(gòu)了,因為這里的數(shù)據(jù)也是一種數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù)組成的。那就是DexTypeId,也就是說選中的內(nèi)容都是DexTypeId這種數(shù)據(jù),這種數(shù)據(jù)結(jié)構(gòu)中只有一個變量,如下所示:
struct DexTypeId{u4 descriptorIdx; /*指向DexStringId列表的索引*/ }看到了吧,這就是DexTypeId數(shù)據(jù)結(jié)構(gòu),它里面只有一個數(shù)據(jù)descriptorIdx,它的值的內(nèi)容是DexStringId列表的索引。還記得DexStringId是什么嗎?在上面我們分析字符串時,字符串的偏移位置就是由DexStringId這種數(shù)據(jù)結(jié)構(gòu)描述的,也就是說descriptorIdx指向的是所有的DexStringId組成的列表的索引。上面我們整理出了所有的字符串,你可以翻上去看看圖。然后我們看這里一共是9個類的類型代表的都是什么。先看第一個“05 00 00 00”,也就是05h,即十進位的5。然后我們在上面所有整理出的字符串看看5索引的是什么?翻上去可以看到是“I”。接下來我們依次整理這些類的類型,也可以得到類的類型的列表
看到了吧,這就是我們dex文件中所有用到的類的類型。比如“I”代表的就是int,LHelloWorld代表的就是HelloWorld,Ljava/io/PrintStream代表的就是java.io.PrintStream。后面的幾個先就不說了。我們接著往下分析。
?
11. 這下到了protoIdsSize和protoIdsOff了,它們代表的是dex文件中方法原型的個數(shù)和位置偏移。我們先看它們的值
如上圖就是它們的值了,protoIdsSize的值為十進制的7,說明有7個方法原型,然后位置偏移為104h,我們找到這個位置
看到了吧,這里就是了。對,下面又有新的數(shù)據(jù)結(jié)構(gòu)了。這下一個數(shù)據(jù)結(jié)構(gòu)不能滿足這塊的內(nèi)容了,我們先看第一個數(shù)據(jù)結(jié)構(gòu),DexProtoId
struct DexProtoId{u4 shortyIdx; /*指向DexStringId列表的索引*/u4 returnTypeIdx; /*指向DexTypeId列表的索引*/u4 parametersOff; /*指向DexTypeList的位置偏移*/ }可以看到,這個數(shù)據(jù)結(jié)構(gòu)由三個變量組成。第一個shortyIdx它指向的是我們上面分析的DexStringId列表的索引,代表的是方法聲明字符串。第二個returnTypeIdx它指向的是 我們上邊分析的DexTypeId列表的索引,代表的是方法返回類型字符串。第三個parametersOff指向的是DexTypeList的位置索引,這又是一個新的數(shù)據(jù)結(jié)構(gòu)了,先說一下這里面 存儲的是方法的參數(shù)列表。可以看到這三個參數(shù),有方法聲明字符串,有返回類型,有方法的參數(shù)列表,這基本上就確定了我們一個方法的大體內(nèi)容。
我們接著看看DexTypeList這個數(shù)據(jù)結(jié)構(gòu),看看參數(shù)列表是如何存儲的。
struct DexTypeList{u4 size; /*DexTypeItem的個數(shù)*/DexTypeItem list[1]; /*DexTypeItem結(jié)構(gòu)*/ }看到了嘛,它有兩個參數(shù),其中第一個size說的是DexTypeItem的個數(shù),那DexTypeItem又是啥咧?它又是一種數(shù)據(jù)結(jié)構(gòu)。我們繼續(xù)看看
struct DexTypeItem{u2 typeIdx; /*指向DexTypeId列表的索引*/ }恩,還好,里面就一個參數(shù)。也比較簡單,就是一個指向DexTypeId列表的索引,也就是代表參數(shù)列表中某一個具體的參數(shù)的位置。
分析完這幾個數(shù)據(jù)結(jié)構(gòu)了,下面我們具體地分析一個類吧。別走神,我們該從上圖的104h開始了。
在104h這里,由于 都是DexProtoId這種數(shù)據(jù)結(jié)構(gòu)的數(shù)據(jù),一個DexProtoId一共占用12個字節(jié)。所以,我們?nèi)∏?2個字節(jié)進行分析。“06 00 00 00,00 00 00 00,94 02 00 00”,這就是那12個字節(jié)了。首先“06 00 00 00”代表的是shortyIdx,它的值是指向DexStringId列表的索引,我們找到DexStringId列表中第6個對應(yīng)的值,也就是III,說明這個方法中聲明字符串為三個int。接著,“00 00 00 00”代表的是returnTypeIdx,它的值指向的是DexTypeId列表的索引,我們找到對應(yīng)的值,也就是I,說明這個方法的返回值是int類型的。最后,我們看“94 02 00 00”,它代表的是DexTypeList的位置偏移,它的值為294h,我們找到這個位置
這里是DexTypeList結(jié)構(gòu),首先看前4個字節(jié),代表的是DexTypeItem的個數(shù),“02 00 00 00 ”也就是2,說明接下來有2個DexTypeItem的數(shù)據(jù),每個DexTypeItem占用2個字節(jié),也就是兩個都是“00 00”,它們的值是DexTypeId列表的索引,我們?nèi)フ乙幌?#xff0c;發(fā)現(xiàn)0對應(yīng)的是I,也就是說它的兩個參數(shù)都是int型的。因此這個方法的聲明我們也就確定了。也就是int(int,int),可以看看我們的源代碼,getNumber方法確實是這樣的。好,第一個方法就這樣分析完了,下面我們依舊是將這些方法的聲明整理成列表,后面可能有數(shù)據(jù)會指向它們的索引。
終于又完了一個。我們準備繼續(xù)下面的。累了就先去聽聽歌吧,歇一歇再看 -_-
?
12.?fieldIdsSize和fieldIdsOff字段。這兩個字段指向的是dex文件中字段名的信息。我們看到這里
可以看到,fieldIdsSize為3h,說明共有3個字段。fieldIdsOff為158h,說明偏移為158h,我們繼續(xù)看到158h這里
咳咳,又該新的數(shù)據(jù)結(jié)構(gòu)了,再忍一忍,接下來的數(shù)據(jù)結(jié)構(gòu)是DexFieldId,我們看下
struct DexFieldId{u2 classIdx; /*類的類型,指向DexTypeId列表的索引*/u2 typeIdx; /*字段類型,指向DexTypeId列表的索引*/u4 nameIdx; /*字段名,指向DexStringId列表的索引*/ }可以看到,這三個數(shù)據(jù)都是指向的索引值,具體的就不說了,看后面的備注就是。我們依舊是分析一下第一個字段,“01 00 ,00 00,13 00 00 00”,類的類型為DexTypeId列表的索引1,也就是HelloWorld,字段的類型為DexTypeId列表中的索引0,也就是int,字段名為DexStringId列表中的索引13h,即十進制的19,找一下,是a,也就是說我們這個字段就確認了,即int HelloWorld.a。這不就是我們在HelloWorld.java文件里定義的變量a嘛。然后我們依次把我們所有的3個字段都列出來:
〇int HelloWorld.a , ①java.lang.String HelloWorld.b ,②java.io.PrintStream java.lang.System.out
ok,先告一段落。繼續(xù)分析下一個
?
13.?methodIdsSize和methodIdsOff字段。這倆字段指明了方法所在的類、方法的聲明以及方法名。我們看看
先是,methodIdsSize,為Ah,即十進制的10,說明共有10個方法。methodIdsOff,為170h,說明它們的位置偏移在170h。我們看到這里
對對對,又是新的數(shù)據(jù)結(jié)構(gòu),不過這個和上個一樣簡單,請看DexMethodId
struct DexMethodId{u2 classIdx; /*類的類型,指向DexTypeId列表的索引*/u2 protoIdx; /*聲明類型,指向DexProtoId列表的索引*/u4 nameIdx; /*方法名,指向DexStringId列表的索引*/ }對吧,這個也簡單,三個數(shù)據(jù)也都是指向?qū)?yīng)的結(jié)構(gòu)的索引值。我們直接分析一下第一個數(shù)據(jù),“01 00, 04 00, 00 00 00 00”,首先,classIdx,為1,對應(yīng)DexTypeId列表的索引1,也就是HelloWorld;其次,protoIdx,為4,對應(yīng)DexProtoId列表中的索引4,也就是void();最后,nameIdx,為0,對應(yīng)DexStringId列表中的索引0,也就是<clinit>。因此,第一個數(shù)據(jù)就出來了,即void HelloWorld.<clinit>() 。后面的不進行分析了,我們依舊是把其余的9個方法列出來
好了,這個就算分析完了。下面真正開始我們的重頭戲了。先緩一緩再繼續(xù)吧。
?
14.?classDefsSize和classDefsOff字段。這兩個字段指明的是dex文件中類的定義的相關(guān)信息。我們先找到它們的位置。
classDefsSize字段,為1,也就是只有一個類定義,classDefsOff,為1C0h,我們找到它的偏移位置。
這里就是了,到了這里,你現(xiàn)在應(yīng)該也知道又有新的數(shù)據(jù)結(jié)構(gòu)了。對的,接下來的數(shù)據(jù)結(jié)構(gòu)是DexClassDef,請看
struct DexClassDef{u4 classIdx; /*類的類型,指向DexTypeId列表的索引*/u4 accessFlags; /*訪問標志*/u4 superclassIdx; /*父類類型,指向DexTypeId列表的索引*/u4 interfacesOff; /*接口,指向DexTypeList的偏移*/u4 sourceFileIdx; /*源文件名,指向DexStringId列表的索引*/u4 annotationsOff; /*注解,指向DexAnnotationsDirectoryItem結(jié)構(gòu)*/u4 classDataOff; /*指向DexClassData結(jié)構(gòu)的偏移*/u4 staticValuesOff; /*指向DexEncodedArray結(jié)構(gòu)的偏移*/ }不多說了,我們直接根據(jù)結(jié)構(gòu)開始分析吧,反正就只有一個類定義。classIdx為1,對應(yīng)DexTypeId列表的索引1,找到是HelloWorld,確實是我們源程序中的類的類型。accessFlags為1,它是類的訪問標志,對應(yīng)的值是一個以ACC_開頭的枚舉值,1對應(yīng)的是 ACC_PUBLIC,你可以在010Editor中看一下,說明我們的類是public的。superclassIdx的值為3,找到DexTypeId列表中的索引3,對應(yīng)的是java.lang.object,說明我們的類的父類類型是Object的。interfaceOff指向的是DexTypeList結(jié)構(gòu),我們這里是0說明沒有接口。如果有接口的話直接對應(yīng)到DexTypeList,就和之前我們分析的一樣了,這里不多解釋,有興趣的可以寫一個有接口的類驗證下。再下來sourceFileIdx指向的是DexStringId列表的索引,代表源文件名,我們這里位4,找一下對應(yīng)到了字符串"HelloWorld.java",說明我們類程序的源文件名為HelloWorld.java。annotationsOff字段指向注解目錄接口,根據(jù)類型不同會有注解類、注解方法、注解字段與注解參數(shù),我們這里的值為0,說明沒有注解,這里也不過多解釋,有興趣可以自己試試。
接下來是classDataOff了,它指向的是DexClassData結(jié)構(gòu)的位置偏移,DexClassData中存儲的是類的數(shù)據(jù)部分,我們開始詳細分析一下它,首先,還是先找到偏移位置3F8h
接著,我們看看DexClassData數(shù)據(jù)結(jié)構(gòu)
struct DexClassData{DexClassDataHeader header; /*指定字段與方法的個數(shù)*/DexField* staticFields; /*靜態(tài)字段,DexField結(jié)構(gòu)*/DexField* instanceFields; /*實例字段,DexField結(jié)構(gòu)*/DexMethod* directMethods; /*直接方法,DexMethod結(jié)構(gòu)*/DexMethod* virtualMethods; /*虛方法,DexMethod結(jié)構(gòu)*/ }可以看到,在DexClassData結(jié)構(gòu)中又引入了三種結(jié)構(gòu),我們一起寫出來看一下吧
struct DexClassDataHeader{u4 staticFieldsSize; /*靜態(tài)字段個數(shù)*/u4 instanceFieldsSize; /*實例字段個數(shù)*/u4 directMethodsSize; /*直接方法個數(shù)*/u4 virtualMethodsSize; /*虛方法個數(shù)*/ }struct DexField{u4 fieldIdx; /*指向DexFieldId的索引*/u4 accessFlags; /*訪問標志*/ }struct DexMethod{u4 methodIdx; /*指向DexMethodId的索引*/u4 accessFlags; /*訪問標志*/u4 codeOff; /*指向DexCode結(jié)構(gòu)的偏移*/ }/*指向DexFieldId的索引*/u4 accessFlags; /*訪問標志*/ }struct DexMethod{u4 methodIdx; /*指向DexMethodId的索引*/u4 accessFlags; /*訪問標志*/u4 codeOff; /*指向DexCode結(jié)構(gòu)的偏移*/ }代碼中的注釋寫的也都很清楚了,我們就不多說了。但是請注意,在這些結(jié)構(gòu)中的u4不是指的占用4個字節(jié),而是指它們是uleb128類型(占用1~5個字節(jié))的數(shù)據(jù)。關(guān)于uleb128還是不多說,想了解的可以自己查查看。
好,接下來開始分析,對于DexClassData,第一個為DexClassDataHeader,我們找到相應(yīng)的位置,第一個staticFieldsSize其實只占用了一個字節(jié),即01h就是它的值,也就是說共有一個靜態(tài)字段,接下來instanceFieldsSize,directMethodsSize,virtualMethodsSize也都是只占用了一個字節(jié),即實例字段的個數(shù)為1,直接方法的個數(shù)為3,虛方法的個數(shù)為1。(這里只是湊巧它們幾個都占用一個字節(jié),并不一定是只占用一個字節(jié),這關(guān)于到uleb128數(shù)據(jù)類型,具體可以自己了解下)。
然后接下來就是staticFields了,它對應(yīng)的數(shù)據(jù)結(jié)構(gòu)為DexField,可以看到,第一個fieldIdx,是指向DexFieldId的索引,值為1,找到對應(yīng)的索引值為java.lang.String HelloWorld.b。第二個accessFlags,值為8,對應(yīng)的ACC_開頭的數(shù)據(jù)為ACC_STATIC(可以在010Editor中對應(yīng)查看一下),說明我們這個靜態(tài)字段為:static java.lang.String HelloWorld.b。可以對應(yīng)我們的源代碼看一下,我們確實定義了一個static的b變量。
接著看instanceFields,它和staticFields對應(yīng)的數(shù)據(jù)結(jié)構(gòu)是一樣的,我們直接分析,第一個fieldIdx,值為0,對應(yīng)的DexField的索引值為int HelloWorld.a。第二個accessFlags,值為0,對應(yīng)的ACC_開頭的數(shù)據(jù)為空,就是什么也沒有。說明我們這個實例字段為:int HelloWorld.a。可以對應(yīng)我們的源碼 看看,我們確實定義了一個a實例變量。
再接著,根據(jù)directMethodsSize,有3個直接方法,我們先看第一個,它對應(yīng)的數(shù)據(jù)結(jié)構(gòu)是DexMethod,首先methodIdx指向的是DexMethodId的索引,值為0,找到對應(yīng)的索引值為void HelloWorld.<clinit>()。然后accessFlages為......為......為....我的個天!我以為就這樣能蒙混過關(guān)了,沒想到還真碰到一個uleb128數(shù)據(jù)不是占用一個字節(jié)的,這個accessFlags對應(yīng)的值占用了三個字節(jié),“88 80 04”,為什么?因為是按照uleb128格式的數(shù)據(jù)讀出來的(還是自己去查查吧,這個坑先不填了,其實這種數(shù)據(jù)也不麻煩,就是前面字節(jié)上的最高位指定了是否需要下一個字節(jié)上的內(nèi)容)。“88 80 04”對應(yīng)的ACC_開頭的數(shù)據(jù)為 ACC_STATIC ACC_CONSTRUCTOR,表明這個方法是靜態(tài)的,并且是構(gòu)造方法。最后,看看codeOff,它對應(yīng)了DexCode結(jié)構(gòu)的偏移,DexCode中存放了方法的指令集等信息,也就是真正的代碼了。我們暫且不分析DexCode,就先看看它的偏移位置為“E0 03”,這個等于多少呢?uleb128轉(zhuǎn)化為16進制數(shù)結(jié)果為:1E0h。也就是DexCode存放在偏移位置1E0h的位置上。
具體的DexCode我們就先不分析了,因為它里面存放的一些指令局需要根據(jù)相關(guān)資料一一查找,有興趣的自己可以找資料看看。剩下的兩個直接方法我們也不分析了。
接下來,我們看根據(jù)virtualMethodsSize,有1個虛方法,我們直接看。首先methodIdx的值為2,對應(yīng)的DexMethodId的索引值為int HelloWorld.getNumber(int, int)。然后accessFlags為1,對應(yīng)的值為ACC_PUBLIC,表明這是一個public類。codeOff為“FC 04”,對應(yīng)的位置為27Ch,這里就不上圖了,自己找找吧。
好了,我們整個DEX文件的結(jié)構(gòu)就這樣從DexHeader開始基本分析完了,好累啊,不過這樣分析一遍,對DEX文件的格式會有更深刻的認識。總是看別人的真不如自己來一遍來的實在!
?
?
0x03■ ?參考資料
參考資料:
《Android軟件安全與逆向分析》.非蟲
?
?
?
?
總結(jié)
以上是生活随笔為你收集整理的一篇文章带你搞懂 DEX 文件的结构的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 简明Python教程学习笔记_3_模块
- 下一篇: Linux 文件 IO