Dalvik虛擬機器【2】——Dex檔案格式

來源:互聯網
上載者:User

標籤:

  • 整個檔案的布局
  • 檔案頭
  • 索引區
    • string_ids
    • type_ids
    • proto_ids
    • field_ids
    • method_ids
  • 資料區
    • class_def
      • class_data_item
        • code_item
    • data
  • 附錄
    • 測試用的Dex的java代碼
    • 參考資料

整個檔案的布局

整個Dex檔案可以分成三部分,檔案頭、索引區、資料區,如所示。

  • 檔案頭
    記錄Dex檔案的概覽、包含檔案大小、校正碼以及其他欄位的位移和大小
  • 索引區
    記錄字串常量、類型、方法原形、域、方法的資訊的索引
  • 資料區
    包含類的定義區class_defs,該部分記錄類資訊;以及資料區data,該部分包含實際資訊(字串、代碼)等;link_data是連結資料區,主要和依賴庫有關

使用 010 Editor 編輯器加上它官方的Dex模板可以方便、直觀查看Dex檔案內容.

檔案頭
位移地址 欄位名字 大小(byte) 說明
0 Magic[8] 8 魔數,用於識別Dex檔案,內容為”dex\n035\0”
8 checksum 4 檔案校正碼
C Signature[20] SHA-1簽名
20 file_size 4 Dex檔案總長度
24 header_size 4 檔案頭大小,一般固定為0x70
28 endan_tag 4 大小端標誌,標誌dex檔案格式為小端,一般固定為0x12345678
2C link_size 4 連結段的大小
30 link_off 4 連結段的基址
34 map_off 4 map item資料的基址
38 string_ids_size 4 字串常量列表的個數
3C string_ids_off 4 字串常量列表的基址
40 type_ids_size 4 類型的個數
44 type_ids_off 4 類型的基址
48 proto_ids_size 4 方法原形的個數
4C proto_ids_off 4 方法原形的基址
50 field_ids_size 4 域的個數
54 field_ids_off 4 域的基址
58 method_ids_size 4 方法的個數
5C method_ids_off 4 方法的基址
60 class_defs_size 4 class_def的個數
64 class_defs_off 4 class_def的基址
68 data_size 4 資料區段的大小
6C data_off 4 資料區段的基址
索引區string_ids

這地區儲存了字串常量的索引資訊。字串常量並不僅僅是代碼中定義的字串,還包括所有的類名、方法名、類型名等資訊.
該地區儲存的是一個基址,也就是字串實際內容在Dex檔案的地址(在data區),它被Dalvik虛擬機器讀取後會轉換成如下資料結構

// /android4.0.4/dalvik/libdex/DexClass.h/* * Direct-mapped "string_id_item". */struct DexStringId {    u4 stringDataOff;      /* file offset to string_data_item */};

根據位移地址stringDataOff讀取到字串常量,該常量在記憶體的資料結構string_data_item為

struct string_data_item {    uleb128 utf16_size; //字串長度    ubyte data; //字串}

用010 Editor查看一個測試用的Dex檔案的string_ids地區如下

type_ids

這地區儲存了dex 檔案裡的所有資料類型的索引資訊,包括class類型,數群組類型(array types)、基本類型(primitive types) 。其資料結構為

/* * Direct-mapped "type_id_item". */struct DexTypeId {    u4  descriptorIdx;      /* index into stringIds list for type descriptor */};

和string_ids不一樣,descriptorIdx並不是位移地址,而是string_ids裡的index序號,如descriptorIdx=8,則代表string_ids[8]=”V”,則代表類型為Void。如,根據檔案頭找到typd_ids的基址為A8H,size為7,從A8H第一個4位元組為0x0003,即是string_idsp[3],即是”LFoo”,代表class類型Foo

proto_ids

proto是方法原形,包含方法的輸入參數和輸出參數,每個大小為12位元組。其資料結構為

/* * Direct-mapped "proto_id_item". */struct DexProtoId {    u4  shortyIdx;          /* index into stringIds for shorty descriptor */    u4  returnTypeIdx;      /* index into typeIds list for return type */    u4  parametersOff;      /* file offset to type_list for parameter types */};
  • shorty_idx
    跟 type_ids 一樣,它的值是一個string_ids的index號,最終是一個簡短的字串描述 ,
  • returnTypeIdx
    傳回型別,值是type_ids的index序號
  • parametersOff
    參數的基址

如

field_ids

這個地區裡有dex檔案引用的所有field(就是類的屬性,包括靜態)索引,每個大小為12位元組。其資料結構為

struct DexFieldId {    u2  classIdx;           /* index into typeIds list for defining class */    u2  typeIdx;            /* index into typeIds for field type */    u4  nameIdx;            /* index into stringIds for field name */};
  • classIdx
    該field所屬的class,它的值是type_ids的index號
  • typeIdx
    該field的類型,它的值也是type_ids的index號
  • nameIdx
    該field的名稱,它的值是string_ids的index號

如

method_ids

這個地區有dex檔案所有方法的索引,格式和field_ids類似,每個大小為12位元組。其資料結構為

/* * Direct-mapped "method_id_item". */struct DexMethodId {    u2  classIdx;           /* index into typeIds list for defining class */    u2  protoIdx;           /* index into protoIds for method prototype */    u4  nameIdx;            /* index into stringIds for method name */};
  • classIdx
    該方法所屬的class,它的值是type_ids的index號
  • protoIdx
    該方法的原形,它的值是proto_ids的index號
  • nameIdx
    該方法的名稱,它的值是string_ids的index號

如

資料區class_def

儲存著Dex檔案每一個類的相關資訊,每個大小為32位元組,其資料結構為

/* * Direct-mapped "class_def_item". */struct DexClassDef {    u4  classIdx;           /* index into typeIds for this class */    u4  accessFlags;    u4  superclassIdx;      /* index into typeIds for superclass */    u4  interfacesOff;      /* file offset to DexTypeList */    u4  sourceFileIdx;      /* index into stringIds for source file name */    u4  annotationsOff;     /* file offset to annotations_directory_item */    u4  classDataOff;       /* file offset to class_data_item */    u4  staticValuesOff;    /* file offset to DexEncodedArray */};
  • classIdx
    這個類的類型,值為type_ids的index
  • accessFlags
    qccess標誌,指示public、private等
  • superclassIdx
    父類的類型,值為type_ids的index
  • interfacesOff
    DexTypeList的位移地址,該結構代表這個類所擁有的interface,若沒有,值為0
  • sourceFileIdx
    源檔案名稱,值為string_ids的index
  • annotationsOff
    annotations_directory_item的位移地址,在data區,代表注釋,若沒有注釋,值為0
  • classDataOff
    class_data_item的位移地址,在data區,代表一個類的詳細資料,包含field、method、method所執行的代碼等,後面會詳細介紹
  • staticValuesOff
    值為位移地址,指向類的static field

如

class_data_item

DexClassDef的classDataOff欄位指示了class_data_item在Dex檔案中的地址,讀入記憶體後的資料結構為DexClassData,在DexClass.h檔案中

/* expanded form of class_data_item. Note: If a particular item is * absent (e.g., no static fields), then the corresponding pointer * is set to NULL. */struct DexClassData {    DexClassDataHeader header;//記錄staticFields、instanceFields、directMethods、virtualMethods的size    DexField*          staticFields;//類的static域    DexField*          instanceFields;//類的執行個體域    DexMethod*         directMethods;//類的方法    DexMethod*         virtualMethods;//類的virtual方法};

DexClassDataHeader、DexField、DexMethod資料結構如下

/* expanded form of a class_data_item header */struct DexClassDataHeader {    u4 staticFieldsSize;    u4 instanceFieldsSize;    u4 directMethodsSize;    u4 virtualMethodsSize;};/* expanded form of encoded_field */struct DexField {    u4 fieldIdx;    /* index to a field_id_item */    u4 accessFlags;};/* expanded form of encoded_method */struct DexMethod {    u4 methodIdx;    /* index to a method_id_item */    u4 accessFlags;    u4 codeOff;      /* file offset to a code_item */};

fieldIdx值為索引區的field_ids的index,methodIdx值為索引區的method_ids的index,重點看codeOff,值為位移地址,指示code_item

code_item

code_item記錄類的方法的運行時相關資訊,其資料結構在DexFile.h中聲明:

struct DexCode {    u2  registersSize;//寄存器的個數    u2  insSize;//輸入參數的個數    u2  outsSize;//本段代碼調用其他方法需要的參數    u2  triesSize;//try item結構的個數,    u4  debugInfoOff;       /* file offset to debug info stream */    u4  insnsSize;          /* 指令列表的大小,以16-bit為單位 */    u2  insns[1];//指令(就是位元組碼)    /* followed by optional u2 padding */    /* followed by try_item[triesSize] */    /* followed by uleb128 handlersSize */    /* followed by catch_handler_item[handlersSize] */};
  • insnsSize和insns[1]
    insnsSize指示了指令個數,insns[1]就是實際的指令,大小並不是1,而是insnsSize
  • try_item 和 catch_handler_item
    在insns[1]後面可能還存在try_item和catch_handler_item,這2個用於捕獲Java的異常,常見的Java代碼有try catch

如

data

儲存著字串常量、位元組碼、map_item等實際內容

附錄測試用的Dex的java代碼

Foo.java:

class Foo {    public static void main(String[] args) {        System.out.println("Hello, world");     }}
參考資料

http://bbs.pediy.com/showthread.php?t=184761

Dalvik虛擬機器【2】——Dex檔案格式

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.