1. 程式人生 > >android .dex檔案探究

android .dex檔案探究

在我們寫Java程式碼的時候,生成的檔案是.java檔案,但是JVM並不識別這個,所以會先轉成class檔案,而在Android端,Android上的Davlik虛擬機器能執行.dex。所以dex檔案中包含了所有的app程式碼,可利用反編譯工具獲取java程式碼。

即dex檔案就是Android Dalvik虛擬機器執行的程式。

為了能夠加深印象,我們先構造一個dex檔案。

public class DEX {

    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; DEX dex = new DEX(); String sayNumber = String.valueOf(dex.getNumber(c,d)); System.out.println("HelloDalVik "+sayNumber); } }

先執行 javac DEX.java
這樣會生成一個.class檔案,然後在SDK中找到dx.bat,
執行 xx\xxx\xxx\dx --dex --output=DEX.java DEX.class
這樣就會生成DEX.dex檔案,如果出現does not match path 的錯誤,就,這樣執行:

D:\SDK\build-tools\27.0.1\dx --dex --output=DEX.dex com\example\asus1\rexiufu\DEX.class

然後我們使用010 Editor來開啟這個DEX.dex檔案

在這裡插入圖片描述

DEX檔案結構

在這裡插入圖片描述

我們先看Header:
在這裡插入圖片描述

檔案頭包含了dex檔案的資訊,所有資料的大致分佈情況

然後我們看看Header的資料圖:在Editor中檢視:
在這裡插入圖片描述

可以看到第一個,magic[8],它代表dex檔案中的檔案標識,一般被稱為魔數。是用來識別dex這種檔案的,它可以判斷當前的dex檔案是否有效,可以看到它用來8個1位元組的無符號數來表示,我們在Editor中可以看到是“64 65 78 0A 30 33 35 00”這8個位元組,這些位元組都是16進製表示的。這8個位元組用ASCII碼轉換為dex.035(“.”不是轉換來的)。目前,dex的魔數固定為dex.035

然後第二個,checksum,它是dex檔案的校驗和,通過它可以判斷dex檔案是否被損壞或者被篡改。它佔用4個位元組
在這裡插入圖片描述

我們可以看到它的值和它對應的四個位元組,剛好是反著的。這是由於dex檔案中採用的是小位元組序的編碼方法,也就是低位上儲存的就是低位元組的內容。

第三個是SHA1 signature[20],signature欄位用於檢驗dex檔案,其實就是把整個dex檔案用SHA-1簽名得到的一個值。這裡佔用了20個位元組。

第四個是fileSize,表示整個檔案的大小,佔用4個位元組

第五個是headerSize,表示DexHeader頭結構的大小,佔用4個位元組。

第六個是endianTag,代表位元組序標記,用於執行dex執行環境的cpu,預設值為0x12345678,對應在101Editor中為“78 56 34 12”

接下來兩個分別是linkSizelinkOff,這連個欄位,分別指定了連結段的大小和檔案偏移,通常情況下它們都為0,。linkSize為0的話表示靜態連線。

再下來就是mapOff欄位,它指定了DexMapList的檔案偏移,就是dex檔案結構圖中的最後一層。

接下來的兩個StringIdsSizeStringIdsOff:這兩個欄位指定了dex檔案中所有用到的字串的個數和位置偏移。我們先看StringIdsSize,現在它的是十進位制值為28,也就是說我們這個dex檔案一共有28個字串,StringIdsOff的值為“70 00 00 00”,表示字串的偏移位置為70h,然後我們找到70h的地方:
在這裡插入圖片描述

在第4箇中,顯示的字串是“HelloDalVik”,
然後我們再看看dex的結構圖:
在這裡插入圖片描述

然後我們繼續看
接下來是typeIdsSizetypeIdsOff,它們代表類的型別的數量和位置偏移,都佔4個位元組,typeIdsSize的的值為9,表示dex檔案中用到的類的型別一共有9個,typeIdsOff的值為“E0 00 00 00 ”,即偏移位置在E0:
在這裡插入圖片描述

接下來兩個是protoIdsSizeprotoIdsOff,它們表示dex檔案中方法原型的個數和位置偏移,現在protoIdsSize的值為7,說明有7個方法原型,然後位置偏移是104h
在這裡插入圖片描述

這裡涉及到一個數據結構:


struct DexProtoId{
	u4 shortyIdx;			/*指向DexStringId列表的索引*/
	u4 returnTypeIdx;		/*指向DexTypeId列表的索引*/
	u4 parametersOff;		/*指向DexTypeList的位置偏移*/
}

可以看到,這個資料結構由三個變數組成。第一個shortyIdx,它指向我們上面分析的DexStringId列表的索引,代表的是方法宣告字串。第二個returnTypeIdx它指向的是我們上班分析的DexTypeId列表索引,代表的是方法返回型別字串。第三個parameterOff指向的是DexTypeList的位置索引,這又是一個新的資料結構,這裡面儲存的是方法的引數類別。
可以看到這三個引數,方法宣告字串,返回型別,引數列表,這基本上確定了我們一個方法的大體內容。


struct DexTypeList{
	u4 size;		/*DexTypeItem的個數*/
	DexTypeItem list[1];	/*DexTypeItem結構*/
}


struct DexTypeItem{
	u2 typeIdx;				/*指向DexTypeId列表的索引*/
}

這樣的話,我們可以看到,第一個方法為 int(int,int)
在這裡插入圖片描述

我們繼續看下面的兩個,fieldIdsSizefieldIdsOff,指向的是dex檔案中欄位名的資訊。這裡fieldIdsSize的大小為3,fieldIdsOff的值為“58 01 00 00 ”:

在這裡插入圖片描述

又涉及到有個資料結構:

struct DexFieldId{
	u2 classIdx;		/*類的型別,指向DexTypeId列表的索引*/
	u2 typeIdx;		/*欄位型別,指向DexTypeId列表的索引*/
	u4 nameIdx;		/*欄位名,指向DexStringId列表的索引*/
}

我們可以看到第一個DexFieldId是Dex中的a

繼續繼續,methodIdsSizemethodIdsOff,指明瞭方法所在的類,方法的宣告以及方法名,現在methodIdsSize的值為10,methodIdsOff的值為“70 01 00 00”,
在這裡插入圖片描述

它涉及到的資料結構:

struct DexMethodId{
	u2 classIdx;		/*類的型別,指向DexTypeId列表的索引*/
	u2 protoIdx;		/*宣告型別,指向DexProtoId列表的索引*/
	u4 nameIdx;		/*方法名,指向DexStringId列表的索引*/
}

分析可以得到,第一個方法為 void DEX.<clinit>()

接下來是classDefsSizeclassDefsOff,這兩個欄位指明的是dex檔案中類的定義的相關資訊,在這裡,classDefsSize的值是1,classDefsOff的是“C0 01 00 00”,

在這裡插入圖片描述

這裡涉及的資料結構:

struct DexClassDef{
	u4 classIdx;		/*類的型別,指向DexTypeId列表的索引*/
	u4 accessFlags;		/*訪問標誌*/
	u4 superclassIdx;	/*父類型別,指向DexTypeId列表的索引*/
	u4 interfacesOff;	/*介面,指向DexTypeList的偏移*/
	u4 sourceFileIdx;	/*原始檔名,指向DexStringId列表的索引*/
	u4 annotationsOff;	/*註解,指向DexAnnotationsDirectoryItem結構*/
	u4 classDataOff;	/*指向DexClassData結構的偏移*/
	u4 staticValuesOff;	/*指向DexEncodedArray結構的偏移*/
}

我們可以看到,這個找到的類是DEX

接下來是DataSizeDataOff,這裡DataOff的值是“E0 01 00 00 ”,找到01E0h,這裡存放的是DexCode。

dex檔案的載入流程

https://blog.csdn.net/jsqfengbao/article/details/52103439
https://www.jianshu.com/p/c9fd64e0b934

參考:
https://blog.csdn.net/sinat_18268881/article/details/55832757