日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

android 定义集合长度,Android Dex文件结构解析

發布時間:2023/11/27 生活经验 28 豆豆
生活随笔 收集整理的這篇文章主要介紹了 android 定义集合长度,Android Dex文件结构解析 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

Java源文件通過Java編譯器生成CLASS文件,再通過dx工具轉換為classes.dex文件。

DEX文件從整體上來看是一個索引的結構,類名、方法名、字段名等信息都存儲在常量池中,這樣能夠充分減少存儲空間,相較于Java字節碼文件更適合手機設備。

DEX文件的相關結構聲明定義在/dalvik/libdex/DexFile.h文件中,下面我們先來看一下DEX文件中使用到的數據結構。

表1 dex文件使用到的數據結構

類型

含義

u1

等同于uint8_t,表示1字節的無符號數

u2

等同于uint16_t,表示2字節的無符號數

u4

等同于uint32_t,表示4字節的無符號數

u8

等同于uint64_t,表示8字節的無符號數

sleb128

有符號LEB128,可變長度1~5字節

uleb128

無符號LEB128,可變長度1~5字節

uleb128p1

無符號LEB128加1,可變長度1~5字節

DEX文件的基本結構如下圖所示:

header

string_ids

type_ids

proto_ids

field_ids

method_ids

class_def

data

link_data

圖1 DEX文件結構

header是DEX文件頭,包含magic字段、alder32校驗值、SHA-1哈希值、string_ids的個數以及偏移地址等。DEX文件的頭結構很固定,占用0x70個字節,具體定義代碼如下所示(摘自DexFile.h):

/*

* Direct-mapped "header_item" struct.

*/

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;

};

magic[8]:共8個字節。目前為固定值dexn035。

checksum:文件校驗碼,使用alder32算法校驗文件除去magic、checksum外余下的所有文件區域,用于檢查文件錯誤。

signature:使用 SHA-1算法hash除去magic,checksum和signature外余下的所有文件區域 ,用于唯一識別本文件 。

fileSize:DEX文件的長度。

headerSize:header大小,一般固定為0x70字節。

endianTag:指定了DEX運行環境的cpu字節序,預設值ENDIAN_CONSTANT等于0x12345678,表示默認采用Little-Endian字節序。

linkSize和linkOff:指定鏈接段的大小與文件偏移,大多數情況下它們的值都為0。link_size:LinkSection大小,如果為0則表示該DEX文件不是靜態鏈接。link_off用來表示LinkSection距離DEX頭的偏移地址,如果LinkSize為0,此值也會為0。

mapOff:DexMapList結構的文件偏移。

stringIdsSize和stringIdsOff:DexStringId結構的數據段大小與文件偏移。

typeIdsSize和typeIdsOff:DexTypeId結構的數據段大小與文件偏移。

protoIdsSize和protoIdsSize:DexProtoId結構的數據段大小與文件偏移。

fieldIdsSize和fieldIdsSize:DexFieldId結構的數據段大小與文件偏移。

methodIdsSize和methodIdsSize:DexMethodId結構的數據段大小與文件偏移。

classDefsSize和classDefsOff:DexClassDef結構的數據段大小與文件偏移。

dataSize和dataOff:數據段的大小與文件偏移。

下面我們來看某apk中classes.dex的解析結果,確實與上面的結構一致:

2.DexMapList區段(大綱)

Dalvik虛擬機解析DEX文件的內容,最終將其映射成DexMapList數據結構,它實際上包含所有其他區段的結構大綱。DexHeader中的mapOff字段指明了DexMapList結構在DEX文件中的偏移。具體定義代碼如下所示:

struct DexMapList {

u4 size; /* DexMapItem的個數 */

DexMapItem list[1]; /* DexMapItem的結構 */

};

struct DexMapItem {

u2 type; /* kDexType開頭的類型 */

u2 unused; /* 未使用,用于字節對齊 */

u4 size; /* type指定類型的個數,它們在dex文件中連續存放 */

u4 offset; /* 指定類型數據的文件偏移 */

};

/* type字段為一個枚舉常量,通過類型名稱很容易判斷它的具體類型。 */

/* map item type codes */

enum {

kDexTypeHeaderItem = 0x0000,

kDexTypeStringIdItem = 0x0001,

kDexTypeTypeIdItem = 0x0002,

kDexTypeProtoIdItem = 0x0003,

kDexTypeFieldIdItem = 0x0004,

kDexTypeMethodIdItem = 0x0005,

kDexTypeClassDefItem = 0x0006,

kDexTypeMapList = 0x1000,

kDexTypeTypeList = 0x1001,

kDexTypeAnnotationSetRefList = 0x1002,

kDexTypeAnnotationSetItem = 0x1003,

kDexTypeClassDataItem = 0x2000,

kDexTypeCodeItem = 0x2001,

kDexTypeStringDataItem = 0x2002,

kDexTypeDebugInfoItem = 0x2003,

kDexTypeAnnotationItem = 0x2004,

kDexTypeEncodedArrayItem = 0x2005,

kDexTypeAnnotationsDirectoryItem = 0x2006,

};

下面我們來看一下010Editor對某classes.dex文件的解析出的DexMapList結構。上面DexMapList結構中的size字段表示list數組的成員個數,即DexMapItem結構的數量:圖中是11h,表示共有17個DexMapItem結構,與圖中的list數組大小相符。

然后我們再來看下DexMapItem的結構。例如對于下圖中的DexMapItem的第一項來說,type等于0說明其是kDexTypeHeaderItem類型的結構;unused一般都為0;size為1代表該結構僅有一個,即只有一個Dex文件頭;offset為0代表Dex文件頭從0h開始。喎�"/kf/ware/vc/" target="_blank" class="keylink">vcD4NCjxwPjxpbWcgYWx0PQ=="image" src="/uploadfile/Collfiles/20160627/20160627092154831.png" title="" />

最后我們將所有DexMapItem結構整理成下表:

類型(type)

個數(size)

偏移(offset)

kDexTypeHeaderItem(0x0000)

0x1

0x0

kDexTypeStringIdItem(0x0001)

0xA115

0x70

kDexTypeTypeIdItem(0x0002)

0x1D38

0x284C4

kDexTypeProtoIdItem(0x0003)

0x2505

0x2F9A4

kDexTypeFieldIdItem(0x0004)

0x9FB9

0x4B5E0

kDexTypeMethodIdItem(0x0005)

0xC344

0x9B3A8

kDexTypeClassDefItem(0x0006)

0x189D

0xFCDC8

kDexTypeAnnotationSetItem(0x1003)

0x10E0

0x12E168

kDexTypeCodeItem(0x2001)

0x96DB

0x138A34

kDexTypeAnnotationsDirectoryItem(0x2006)

0xCE6

0x4A3EEC

kDexTypeTypeList(0x1001)

0x1620

0x4B9894

kDexTypeStringDataItem(0x2002)

0xA115

0x4C74CA

kDexTypeDebugInfoItem(0x2003)

0x8FCC

0x5C8544

kDexTypeAnnotationItem(0x2004)

0x101C

0x63FBC1

kDexTypeEncodedArrayItem(0x2005)

0x10E

0x653536

kDexTypeClassDataItem(0x2000)

0x184F

0x65B97A

kDexTypeMapList(0x1000)

0x1

0x6B8828

可以看出,其中區段的offset與header中的off是完全相等的。

3.DexStringId區段(字符串)

struct DexStringId {

u4 stringDataOff; /* 字符串數據偏移 */

}

DexStringId結構只有一個stringDataOff字段,直接指向字符串數據。這個區段中包含了DEX文件中用到的所有字符串。

4.DexTypeId區段(類名/類型名稱字符串)

struct DexTypeId {

u4 descriptorIdx; /* 指向 DexStringId列表的索引 */

};

descriptorIdx為指向DexStringId列表的索引,它對應的字符串代表了具體類的類型(DEX文件中用到的所有基本數據類型和類的名稱)。如下圖中的第一項值為0xAEB,表示其是DexStringId中第0xAEB(2795)項;而第8項值為0x1969,表示其是DexStringId中第0x1969(6505)項。經過我們的驗證,以上分析是正確的。

5.DexProtoId區段(方法聲明=返回類型 + 參數列表)

struct DexProtoId {

u4 shortyIdx; /* 指向DexStringId列表的索引 */

u4 returnTypeIdx; /* 指向DexTypeId列表的索引 */

u4 parametersOff; /* 指向DexTypeList的偏移 */

}

struct DexTypeList {

u4 size; /* 接下來DexTypeItem的個數 */

DexTypeItem list[1]; /* DexTypeItem結構 */

};

struct DexTypeItem {

u2 typeIdx; /* 指向DexTypeId列表的索引 */

};

下面結合實例進行分析:

DexProtoId

shortyIdx:方法聲明字符串,具體而言是由方法的返回類型與參數列表組成的一個字符串,并且返回類型位于參數列表的前面。如“III”“V”“VI”“VL”等。在下圖的三個方法聲明中分別為B、BL、DL。

returnTypeIdx:方法返回類型,指向DexTypeId列表。下圖的分別為byte、byte、double。

parametersOff:指向一個DexTypeList結構體,存放了方法的參數類型。下圖分別為0、0x4BA78C、0x4BA7BC。值為0表示參數為void。

DexTypeList

size:DexTypeItem的個數,即參數的數量。下圖分別為?、1、1,表示后兩個方法都只有一個參數。 list:指向size個DexTypeItem項,每一項代表方法的一個參數。

DexTypeItem

typeIdx:指向DexTypeId列表,最終指向參數類型的字符串。如第三圖61h(97)項在DexTypeId列表中正好指向”Landroid/content/Context;”類型字符串。

6.DexFieldId區段(字段)

DexFieldId結構中的數據全部是索引值,指明了字段所在的類、字段的類型以及字段名。

struct DexFieldId {

u2 classIdx; /* 類的類型,指向DexTypeId列表的索引 */

u2 typeIdx; /* 字段類型,指向DexTypeId列表的索引 */

u4 nameIdx; /* 字段名,指向DexStringId列表的索引 */

};

如下圖,可以看到字段所屬類名為MTT.ThirdAppInfoNew,字段類型為int,字段名為iCoreType。

7.DexMethodId區段(方法)

DexMethodId結構中的數據全部是索引值,指明了方法所在的類、方法的聲明以及方法名。

struct DexMethodId {

u2 classIdx; /* 類的類型,指向DexTypeId列表的索引 */

u2 protoIdx; /* 聲明類型,指向DexProtoId列表的索引 */

u4 nameIdx; /* 方法名,指向DexStringId列表的索引 */

};

如下圖,可以看到方法所屬類為MTT.ThirdAppInfoNew,方法聲明為V,方法名為。

8.DexTypeClassDefItem(類定義)

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結構的偏移 */

};

struct DexClassData {

DexClassDataHeader header; /* 指定字段與方法的個數 */

DexField* staticFields; /* 靜態字段,DexField結構 */

DexField* instanceFields; /* 實例字段,DexField結構 */

DexMethod* directMethods; /* 直接方法,DexMethod結構 */

DexMethod* virtualMethods; /* 虛方法,DexMethod結構 */

struct DexClassDataHeader {

u4 staticFieldsSize; /* 靜態字段個數 */

u4 instanceFieldsSize; /* 實例字段個數 */

u4 directMethodsSize; /* 直接方法個數 */

u4 virtualMethodsSize; /* 虛方法個數 */

};

struct DexField {

u4 fieldIdx; /* 指向DexFieldId的索引 */

u4 accessFlags; /* 訪問標志 */

};

struct DexMethod {

u4 methodIdx; /* 指向DexMethodId的索引 */

u4 accessFlags; /* 訪問標志 */

u4 codeOff; /* 指向DexCode結構的偏移 */

};

struct DexCode {

u2 registersSize; /* 使用的寄存器個數 */

u2 insSize; /* 參數個數 */

u2 outsSize; /* 調用其他方法時使用的寄存器個數 */

u2 triesSize; /* Try/Catch個數 */

u4 debugInfoOff; /* 指向調試信息的偏移 */

u4 insnsSize; /*指令集個數,以2字節為單位 */

u2 insns[1]; /* 指令集 */

DexClassDef

classIdx:索引值,表明類的類型。下圖中值為0x6,指向類型MTT.ThirdAppInfoNew。 accessFlags:類的訪問標志,它是以ACC_開頭的一個枚舉值。具體定義可以參考這里。下圖中值為0x11,表示同時具有ACC_PUBLIC和ACC_FINAL。 superclassIdx:父類類型索引值。下圖中值為0x1B13,指向java.lang.Object類。 interfacesOff:如果類中含有接口聲明或實現,interfaceOff會指向一個DexTypeList結構,否則這里的值為0。圖中值為0x4B9894(4954260),指向的DexTypeList結構為java.lang.Cloneable。 sourceFileIdx:字符串索引值,表示類所在的源文件名稱。圖中值為NO_INDEX(0xffffffff),表示該值丟失。 annotationsOff:指向注解目錄結構,根據類型不同會有注解類、注解方法、注解字段與注解參數,如果類中沒有注解,這里的值則為0。圖中值為0,表示類中沒有注解。 classDataOff:指向DexClassData結構,它是類的數據部分。圖中為0x65B97A。 staticValuesOff:指向DexEncodedArray結構,記錄了類中的靜態數據。圖中為0,表示類中沒有靜態數據。

DexClassData

header:一個DexClassDataHeader結構,指定字段與方法的個數。如下圖中的staticFieldsSize為0,表示沒有靜態字段;instanceFieldsSize為0xC,表示有12個實例字段;directMethodsSize為0x1,表示有一個直接方法;virtualMethodsSize為0x0,表示沒有虛方法。

staticFields*:指向一個DexField結構,表示靜態字段的類型與訪問標志。由于本例沒有靜態字段,因此該結構無效。

directMethods*:指向一個DexField結構,表示實例字段的類型與訪問標志。如下圖本例中有一個實例字段。

directMethods*:指向一個DexMethod結構,表示直接方法的原型、名稱、訪問標志、代碼數據塊。。如下圖本例中有12個實例字段。

virtualMethods*:指向一個DexMethod結構,表示虛方法的原型、名稱、訪問標志、代碼數據塊。由于本例沒有靜態字段,因此該結構無效。

DexField

fieldIdx:指向DexFieldId的索引,表示字段的所屬類、字段類型和字段名。 accessFlags:訪問標志。

DexMethod

methodIdx:指向DexMethodId的索引,表示方法的所在類、方法的聲明和方法名。 accessFlags:訪問標志。 codeOff:指向DexCode結構的偏移,圖中為0x138A34。

DexCode

registersSize:該方法使用的寄存器個數。下圖中為3。 insSize:該方法的參數個數,對應smali語法中的”.register”指令。下圖中為1。 outsSize:該方法調用其他方法時,對應smali語法中的”.paramter”指令。例如現在有一個方法,使用了5個寄存器,其中有2個為參數,而該方法調用了另一個方法,后者使用了20個寄存器,那么Dalvik虛擬機在分配時,會在分配自身方法寄存器空間時加上那20個寄存器空間。下圖中為1。 triesSize:方法中Try/Catch的個數。 debugInfoOff:如果dex文件保留了調試信息,debugInfoOff字段會指向它。 insnsSize:指令個數,以2字節為單位。 insns[1]:真正的指令部分。

總結

以上是生活随笔為你收集整理的android 定义集合长度,Android Dex文件结构解析的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。