hello.dex 详细结构分析

一: 前言

文件数据分析离不开结构分析, 而结构定义权威参考当然是DexFile.h
/dalvik/libdex/DexFile.h
https://github.com/plum-umd/dexdump 有代码可以参考

二: 准备:

  1. 源文件java
$ cat hello.java
public class hello
{
   public static void main(String[] argv)
   {
       System.out.println("hello world");
   } 
}
  1. 编译为class
    $ java -c hello.java

  2. 将class 变为dex 文件
    $ dx –dex –output=hello.dex hello.class

  3. 用davikvm 执行文件
    将文件上传到手机: adb push hello.dex /data
    登陆手机控制台,执行: davikvm -cp /data/hello.hex
    -cp 是class path的简写

三. dex 文件格式分析.

3.0 文件整体结构

struct DexFile  
{  
    DexHeader           Header;                     //定义了各表的偏移地址及元素个数
    DexStringId         StringIds[stringIdsSize];   //修改过的utf8字符串定义 
    DexTypeId           TypeIds[typeIdsSize];       //变量类型定义 
    DexProtoId          ProtoIds[protoIdsSize];     //函数原型定义 
    DexFieldId          FieldIds[fieldIdsSize];     //成员变量定义 
    DexMethodId         MethodIds[methodIdsSize];   //成员方法定义 
    DexClassDef         ClassDefs[classDefsSize];   //类定义 
    DexData             Data[];     //数据, 
    DexLink             LinkData;   //链接数据 
};  

与java ClassFile 相比, 他把表的长度都集中到头部进行统一管理.
可以简单划分为3个部分,头部区,索引区,数据区
中间的从DexStringId 开始, 到DexClassDef[classDefsSize]为止都是索引区

在DexFile.h 中, DexFile 的结构定义略有差别, 它是为内存使用而定义的.
它能够更好的管理和使用文件中的数据.并且还有一些扩充. 这里是简单的hello分析
高级功能暂不涉及.内存中对应的项正是文件中相应项的映射.

typedef struct DexFile {
    /* directly-mapped "opt" header */
    const DexOptHeader* pOptHeader;

    /* pointers to directly-mapped structs and arrays in base DEX */
    const DexHeader*    pHeader;
    const DexStringId*  pStringIds;
    const DexTypeId*    pTypeIds;
    const DexFieldId*   pFieldIds;
    const DexMethodId*  pMethodIds;
    const DexProtoId*   pProtoIds;
    const DexClassDef*  pClassDefs;
    const DexLink*      pLinkData;

    /*
     * These are mapped out of the "auxillary" section, and may not be
     * included in the file.
     */
    const DexClassLookup* pClassLookup;
    DexIndexMap         indexMap;
    const void*         pRegisterMapPool;       // RegisterMapClassPool

    /* points to start of DEX file data */
    const u1*           baseAddr;

    /* track memory overhead for auxillary structures */
    int                 overhead;

    /* additional app-specific data structures associated with the DEX */
    //void*               auxData;
} DexFile;

下面具体看看那些结构元素.
3.1 头部信息0x70 bytes

    struct DexHeader 
    { 
      u1  magic[8];         //field_0,1     ;dex 版本标识,"dex.035"  
      u4  checksum;         //field_2,      ;adler32 检验  
      u1  signature[20];    //f_3,4,5,6,7   ;SHA-1 哈希值,20个字节  
      u4  fileSize;         //field_8   ;整个 dex 文件大小  
      u4  headerSize;       //field_9   ;DexHeader 结构大小,0x70  
      u4  endianTag;        //field_10  ;字节序标记,小端 "0x12345678",大端"0x78563412"  
      u4  linkSize;         //field_11  ;链接段大小  
      u4  linkOff;          //field_12  ;链接段偏移  
      u4  mapOff;           //field_13  ;DexMapList 的偏移  
      u4  stringIdsSize;    //field_14  ;DexStringId 的个数  
      u4  stringIdsOff;     //field_15  ;DexStringId 的偏移      字符串  
      u4  typeIdsSize;      //field_16  ;DexTypeId 的个数  
      u4  typeIdsOff;       //field_17  ;DexTypeId 的偏移        类型  
      u4  protoIdsSize;     //field_18  ;DexProtoId 的个数  
      u4  protoIdsOff;      //field_19  ;DexProtoId 的偏移       声明  
      u4  fieldIdsSize;     //field_20  ;DexFieldId 的个数  
      u4  fieldIdsOff;      //field_21  ;DexFieldId 的偏移       字段  
      u4  methodIdsSize;    //field_22  ;DexMethodId 的个数  
      u4  methodIdsOff;     //field_23  ;DexMethodId 的偏移      方法  
      u4  classDefsSize;    //field_24  ;DexClassDef 的个数  
      u4  classDefsOff;     //field_25  ;DexClassDef 的偏移      类  
      u4  dataSize;         //field_26  ;数据段的大小  
      u4  dataOff;          //field_27  ;数据段的偏移  
    };  
共28DWORD, 0x70bytes
0000000: 6465 780a 3033 3500 db5e 64f4 14f0 bf23  dex.035..^d....#
0000010: b4c7 881c 1f88 a158 a1e7 a7ca 54fe a2d5  .......X....T...
//magic               : 'dex.035'
//checksum            : f4645edb
//signature           : 14f0...a2d5
0000020: e002 0000 7000 0000 7856 3412 0000 0000  ....p...xV4.....
//file_size           : 736(0x02e0),  文件长度.
//header_size         : 112(0x70)   ,  header 大小
//endian_tag          : 0x12345678 小端, 显然
//link_size           : 0
0000030: 0000 0000 4002 0000 0e00 0000 7000 0000  ....@.......p...
//link_off            : 0 (0x000000) , 
//查资料知,link_size,link_off 在静态链接时有值,这里是动态链接,故为0
//map_off             : 0x0240       , map表偏移 
//string_ids_size     : 14           , 14 个string, 见后.
//string_ids_off      : 112 (0x000070),从偏移0x70开始,紧接头部
0000040: 0700 0000 a800 0000 0300 0000 c400 0000  ................
//type_ids_size       : 7            , 7 个type(类型), 从0xa8开始
//type_ids_off        : 168 (0x0000a8)
//proto_ids_size      : 3            , 3 个proto(函数原型),从0xc4
//proto_ids_off       : 196 (0x0000c4)
0000050: 0100 0000 e800 0000 0400 0000 f000 0000  ................
//field_ids_size      : 1            , 1 个field(字段),从0xe8开始
//field_ids_off       : 232 (0x0000e8)
//method_ids_size     : 4            , 4 个method(方法),从0xf0开始
//method_ids_off      : 240 (0x0000f0)
0000060: 0100 0000 1001 0000 b001 0000 3001 0000  ............0...
//class_defs_size     : 1            , 1 个类定义, 从0x110开始
//class_defs_off      : 272 (0x000110)
//data_size           : 432          , 数据,从0x130 开始
//data_off            : 304 (0x000130)

找到数据所在, 理解数据含义才算理解.
下面是14个strings

3.2 DexStringId

typedef struct _DexStringId  
{  
    u4  stringDataOff;                  // 指向MUTF-8 字符串的偏移(修改过的utf8字符串)
}DexStringId, *PDexStringId;  

我们看到,它索引的是地址偏移.占4个bytes
从0x70到0xa7, 因为0xa8是type_ids_off, 每个string 占4byte, 14个string
从0x70 正好到0xa7

0000070: 7601 0000 7e01 0000 8701 0000 9e01 0000  v...~...........
0000080: b201 0000 c601 0000 da01 0000 dd01 0000  ................
0000090: e101 0000 f601 0000 0402 0000 1002 0000  ................
00000a0: 1602 0000 1b02 0000 
顺便把string 也拿过来吧. 这些string, 位于数据区了!
0000170: 0100 0000 0600 063c 696e 6974 3e00 074c  .......<init>..L
0000180: 6865 6c6c 6f3b 0015 4c6a 6176 612f 696f  hello;..Ljava/io
0000190: 2f50 7269 6e74 5374 7265 616d 3b00 124c  /PrintStream;..L
00001a0: 6a61 7661 2f6c 616e 672f 4f62 6a65 6374  java/lang/Object
00001b0: 3b00 124c 6a61 7661 2f6c 616e 672f 5374  ;..Ljava/lang/St
00001c0: 7269 6e67 3b00 124c 6a61 7661 2f6c 616e  ring;..Ljava/lan
00001d0: 672f 5379 7374 656d 3b00 0156 0002 564c  g/System;..V..VL
00001e0: 0013 5b4c 6a61 7661 2f6c 616e 672f 5374  ..[Ljava/lang/St
00001f0: 7269 6e67 3b00 0c68 656c 6c6f 2077 6f72  ring;..hello wor
0000200: 6c64 0a00 0a68 656c 6c6f 2e6a 6176 6100  ld...hello.java.
0000210: 046d 6169 6e00 036f 7574 0007 7072 696e  .main..out..prin
0000220: 746c 6e00 0100 070e 0004 0100 070e 7800  tln...........x.

我们看到
0. 00000176->06, 后面跟6字节
1. 0000017e->07, 后面跟7字节Lhello;
2. 00000187->15, 后面跟0x15字节Ljava/io/PrintStream;
3. 0000019e->12, 后面跟0x12字节Ljava/lang/Object;
4. 000001b2->12, 后面跟0x12字节Ljava/lang/String;
5. 000001c6->12, 后面跟0x12字节Ljava/lang/System;
6. 000001da->01, 后面跟0x1字节V
7. 000001dd->02, 后面跟0x2字节VL
8. 000001e1->18, 后面跟0x13字节[Ljava/lang/String;
9. 000001f6->0c, 后面跟0xc字节hello world
10. 00000204->0a, 后面跟0xa字节hello.java
11. 00000210->04, 后面跟0x4字节main
12. 00000216->03, 后面跟6字节out
13. 0000021b->07, 后面跟6字节println

所以说mutf8 是说前面是长度,后面是utf8字符串,前面的长度是leb128编码.
leb128是little endian base 128, 是一种变长编码,只用低7位表示有效数据,
最高位为1表示有后续byte, 为0表示无后续byte. 最多占用5byte,表示一个32位数.
用leb128编码长度更灵活.

3.3 DexTypeId

typedef struct _DexTypeId  
{  
    u4     descriptorIdx;   // 指向 DexStringId 列表的索引  
}DexTypeId, *PDexTypeId;  
7个类型,0xa8始,0xe8止
它索引的是个序号,如果字符串不是很多,4byte数据高位肯定是0.
00000a0:                     0100 0000 0200 0000  ................
00000b0: 0300 0000 0400 0000 0500 0000 0600 0000  ................
00000c0: 0800 0000 

分别是
0. ->1 “Lhello;”
1. ->2 “Ljava/io/PrintStream;
2. ->3 “Ljava/lang/Object;”
3. ->4 “Ljava/lang/String;”
4. ->5 “Ljava/lang/System;”
5. ->6 “V”
6. ->8 “[Ljava/lang/String;”
共7个字符串,已经把参考字符串copy过来了

3.4 DexProtoId

typedef struct _DexProtoId  
{  
    u4  shortyIdx;          // 方法声明字符串,指向 DexStringId 
    u4  returnTypeIdx;      // 方法返回类型字符串,指向 DexTypeId 
    u4  parametersOff;      // 方法的参数列表,指向 DexTypeList 
}DexProtoId, *PDexProtoId;  

函数原型既有字符串索引,索引名字,又有序号索引,索引返回值类型,还有函数参数列表索引,该索引是一个地址偏移量,指向一个DexTypeList结构,DexTypeList 结构数据位于数据区了,更详细的见后述.

3 个proto(函数原型)


00000c0:           0600 0000 0500 0000 0000 0000  ................

\0.
6 -> “V”
5 -> 6 -> “V”
0 -> 无参数

00000d0: 0700 0000 0500 0000 6801 0000 0700 0000  ........h.......

\1.
7 -> “VL”
5 -> 6 -> “V”
0x168 ->参数0x168 -> Ljava/lang/String
\2.
7 -> “VL”
5 -> 6 -> “V”
0x170 ->参数0x170 -> [Ljava/lang/String

00000e0: 0500 0000 7001 0000                      ....p...........

info: 参数列表
typedef struct DexTypeList {
u4 size; /* #of entries in list */
DexTypeItem list[1]; /* entries */ ,实际上是跟size 个项
} DexTypeList;
typedef struct DexTypeItem {
u2 typeIdx; /* index into typeIds */
} DexTypeItem;
0000160: 0100 0000 0300 0000 n …………..
0x168处参数列表只有1个, 03 -> 04 -> Ljava/lang/String;
0000170: 0100 0000 0600
0x170处参数列表只有1个, 06 -> 08 -> [Ljava/lang/String;
这里,我要强调一下这个参数表的转换过程!

上一个gdb脚本, 分析一下内存结构.
set $j=((DexTypeList *)(pDexFile->baseAddr + pDexFile->pProtoIds[2].parametersOff))->list[0].typeIdx
set $k= pDexFile->pTypeIds[$j].descriptorIdx
p pDexFile->baseAddr + pDexFile->pStringIds[$k].stringDataOff+1
下面分析这个脚本
假如dex文件被加载到内存, pDexFile 结构均指向正确数据.
pDexFile->pProtoIds[2] 为第二个函数原型
pDexFile->pProtoIds[2].parametersOff 为第2个函数原型的参数列表的偏移量
pDexFile->baseAddr + pDexFile->pProtoIds[2].parametersOff, 为第2个函数原型的参数列表在内存中位置
这个位置是用u4定义的,把它强制转化为(DexTypeList *)
((DexTypeList *)(pDexFile->baseAddr + pDexFile->pProtoIds[2].parametersOff))->list[0].typeIdx
取出第2个函数原型参数列表的第一个参数的typeIdx
set $k= pDexFile->pTyp[$j].descriptorIdx
把typeIdx转换为stringIds index. 并付给$k
p pDexFile->baseAddr + pDexFile->pStringIds[$k].stringDataOff+1
简单描述为: 取到$k字符串的内存地址,加1是为了跳过第一个长度字节(已假定字符串不超过128).
则后面的utf8字符串会被打印出来.

3.5 DexFieldId

typedef struct _DexFieldId  
{  
    u2  classIdx;           // 类的类型,索引 DexTypeId 列表
    u2  typeIdx;            // 字段的类型,索引 DexTypeId 列表
    u4  nameIdx;            // 字段名,索引 DexStringId 列表
}DexFieldId, *PDexFieldId;  

成员变量的索引定义了所属类的索引,类型的所以,名称的索引.
这里只用了2个bytes来索引类,2个byte来索引类型,节省了空间.也要求类型个数不能超过65536个. 这个一般能满足.

1 个field(字段),从0xe8开始

00000e0:                     0400 0100 0c00 0000  ....p...........

classIdx : 4 -> 5 -> “Ljava/lang/System;”
typeIdx : 1 -> 2 -> “Ljava/io/PrintStream;”
nameIdx : 12 -> “out”
故为Ljava/lang/System 类out 字段, 类型Ljava/io/PrintStream;

3.6 DexMethodId

struct field_id_item
{
    u2  classIdx;           // 类的类型,索引 DexTypeId 列表
    u2  protoIdx;           // 声明的类型,索引 DexProtoId 列表
    u4  nameIdx;            // 方法名,索引 DexStringId 列表
}

成员函数定义了所属类的索引,所属函数原型的索引及名称索引, 跟成员变量很相似,它也要求类的个数及函数原型的个数不能超过65536, 因为它也是用2byte来索引的.

4 个method(方法),从0xf0开始

00000f0: 0000 0000 0000 0000 0000 0200 0b00 0000  ................
0. void hello()
1. 
0000100: 0100 0100 0d00 0000 0200 0000 0000 0000  ................

3.7 DexClassDef

struct DexClassDef
{
    u4     classIdx;                 // 类的类型,指向 DexTypeId 列表的索引
    u4     accessFlags;              // 访问标志
    u4     superclassIdx;            // 父类类型,指向 DexTypeId 列表的索引
    u4     interfacesOff;            // 接口,指向 DexTypeList 的偏移,否则为0
    u4     sourceFileIdx;            // 源文件名,指向 DexStringId 列表的索引
    u4     annotationsOff;           // 注解,指向 DexAnnotationsDirectoryItem 结构,或者为 0
    u4     classDataOff;             // 指向 DexClassData 结构的偏移,类的数据部分
    u4     staticValuesOff;          // 指向 DexEncodedArray 结构的偏移,记录了类中的静态数据,主要是静态方法
}

类定义比较复杂,因为它的索引结构包含了8个字段.
本类和父类的名称用类型序号表示,访问标志用一个整数表示.
一个类一般会对应一个源文件,源文件名用一个字符串序号表示,接口用dexTypelist偏移表示,前面说过.这个也是指向数据区的. 另外还有三个指向数据区的偏移:
标注的偏移,静态数据的偏移,这两个先不做分析,还有一个重要的偏移是类数据的偏移. 分析见后.

1 个类定义, 从0x110开始

0000110: 0000 0000 0100 0000 0200 0000 0000 0000  ................
0000120: 0a00 0000 0000 0000 2f02 0000 0000 0000  ......../.......
class_idx           : 0
access_flags        : 1 (0x0001)
superclass_idx      : 2
interfaces_off      : 0 (0x000000)
source_file_idx     : 10
annotations_off     : 0 (0x000000)
class_data_off      : 559 (0x00022f)
staticValuesOff     : 0 (0x000000)

class_data 会对应到如下信息, 见后
static_fields_size  : 0
instance_fields_size: 0
direct_methods_size : 2
virtual_methods_size: 0

3.8 数据区(0x130开始)

!:codeItem,0x02项,偏移0x0130
0000130: 0100 0100 0100 0000 2302 0000 0400 0000  ........#.......
0000140: 7010 0300 0000 0e00 0300 0100 0200 0000  p...............
0000150: 2802 0000 0800 0000 6200 0000 1a01 0900  (.......b.......
0000160: 6e20 0200 1000 0e00                      n ..............
code区现在先不做分析

!:typeList,0x02项,偏移0x0168
0000160:                     0100 0000 0300 0000  n ..............
0000170: 0100 0000 0600                           .......<init>..L
前面已经分析过了. typelist 还是直接映射的,先定义大小,每个ITEM大小用2byte来索引

!:stringDataItem,0x0e项,偏移0x0176
0000170:                063c 696e 6974 3e00 074c  .......<init>..L
0000180: 6865 6c6c 6f3b 0015 4c6a 6176 612f 696f  hello;..Ljava/io
0000190: 2f50 7269 6e74 5374 7265 616d 3b00 124c  /PrintStream;..L
00001a0: 6a61 7661 2f6c 616e 672f 4f62 6a65 6374  java/lang/Object
00001b0: 3b00 124c 6a61 7661 2f6c 616e 672f 5374  ;..Ljava/lang/St
00001c0: 7269 6e67 3b00 124c 6a61 7661 2f6c 616e  ring;..Ljava/lan
00001d0: 672f 5379 7374 656d 3b00 0156 0002 564c  g/System;..V..VL
00001e0: 0013 5b4c 6a61 7661 2f6c 616e 672f 5374  ..[Ljava/lang/St
00001f0: 7269 6e67 3b00 0b68 656c 6c6f 2077 6f72  ring;..hello wor
0000200: 6c64 000a 6865 6c6c 6f2e 6a61 7661 0004  ld..hello.java..
0000210: 6d61 696e 0003 6f75 7400 0770 7269 6e74  main..out..print
0000220: 6c6e 00                                                  
字符串数据前面分析过,为mutf8格式, 字符串的长度u4已经采用了leb128编码. 从空间占用上整体会减小.不过先不要嘲笑它减小不了多少空间.

!:debugInfoItem,0x02项,偏移0x0223
0000220:        01 0007 0e00 0501 0007 0e78 0000  ln...........x..

debug 信息现在不做分析!

!:classDataItem,0x01项,偏移022f

0000220:                                      00  ln...........x..
0000230: 0002 0000 8180 04b0 0201 09c8 0200 0000  ................

typedef struct DexClassData {
DexClassDataHeader header;
DexField* staticFields;
DexField* instanceFields;
DexMethod* directMethods;
DexMethod* virtualMethods;
} DexClassData;

typedef struct DexClassDataHeader {
u4 staticFieldsSize;
u4 instanceFieldsSize;
u4 directMethodsSize;
u4 virtualMethodsSize;
} DexClassDataHeader;
但这是uleb128编码长度. 结果如下,见后面分析
staticFieldsSize :00
instanceFieldsSize :00
directMethodsSize :02 2个方法
virtualMethodsSize :00
//类数据成员方法结构定义
typedef struct DexMethod {
u4 methodIdx; /* index to a method_id_item */
u4 accessFlags;
u4 codeOff; /* file offset to a code_item */
} DexMethod;
但对应数据仍然采用uleb128编码
类数据结构定义了类的成员方法索引,访问标志和代码偏移
类数据的大小,索引,访问标志及偏移地址都采用了uleb128编码来代替直接的u4编码
0.
methodIdx -> uleb128(00) -> 0x0
accessFlag -> uleb128(81 80 04) -> 0x010001
codeOff -> uleb128(b0 02) -> 0x130
1.
methodIdx -> uleb128(01) -> 0x1
accessFlag -> uleb128(09) -> 0x09
codeOff -> uleb128(c8 02 )-> 0x0148

3.9 map 数据, 从0x240 开始, 到文件尾.
struct DexMapList
{
u4 size; // DexMapItem 的个数
DexMapItem list[1]; // DexMapItem 结构
};
struct DexMapItem
{
u2 type; // kDexType 类型变量
u2 unused; // 未使用,用于对齐
u4 size; // 指定类型的个数
u4 offset; // 指定类型数据的文件偏移
};
typedef enum
{
kDexTypeHeaderItem = 0x0000, // 对应 DexHeader
kDexTypeStringIdItem = 0x0001, // 对应 stringIdsSize 与 stringIdsOff 字段
kDexTypeTypeIdItem = 0x0002, // 对应 typeIdsSize 与 typeIdsOff 字段
kDexTypeProtoIdItem = 0x0003, // 对应 protoIdsSize 与 protoIdsOff 字段
kDexTypeFieldIdItem = 0x0004, // 对应 fieldIdsSize 与 fieldIdsOff 字段
kDexTypeMethodIdItem = 0x0005, // 对应 methodIdsSize 与 methodIdsOff 字段
kDexTypeClassDefItem = 0x0006, // 对应 classDefsSize 与 classDefsOff 字段
kDexTypeMapList = 0x1000,
kDexTypeTypeList = 0x1001,
kDexTypeAnnotationSetRefList = 0x1002,
kDexTypeAnnotationSetItem = 0x1003,
kDexTypeClassDataItem = 0x2000,
kDexTypeCodeItem = 0x2001,
kDexTypeStringDataItem = 0x2002,
kDexTypeDebugInfoItem = 0x2003,
kDexTypeAnnotationItem = 0x2004,
kDexTypeEncodeArrayItem = 0x2005,
kDexTypeAnnotationsDirectoryItem = 0x2006
}kDexType;

0000240: 0d00 0000 0000 0000 0100 0000 0000 0000  ................
!:0xdMap项, DexHeader,1项,偏移为0
0000250: 0100 0000 0e00 0000 7000 0000 0200 0000  ........p.......
!:stringId,0x0e项,偏移为0x70,
!:typeId, 0x07项,偏移为0xa8
0000260: 0700 0000 a800 0000 0300 0000 0300 0000  ................
!:protoId,0x3项,偏移为0xc4
0000270: c400 0000 0400 0000 0100 0000 e800 0000  ................
!:fieldId,0x1项,偏移为0xe8
0000280: 0500 0000 0400 0000 f000 0000 0600 0000  ................
!:methodId,0x4项,偏移0xf0
!:classDef,0x1项,偏移0x110
0000290: 0100 0000 1001 0000 0120 0000 0200 0000  ......... ......
!:codeItem,0x02项,偏移0x0130
00002a0: 3001 0000 0110 0000 0200 0000 6801 0000  0...........h...
!:typeList,0x02项,偏移0x0168
00002b0: 0220 0000 0e00 0000 7601 0000 0320 0000  . ......v.... ..
!:stringDataItem,0x0e项,偏移0x0176
!:debugInfoItem,0x02项,偏移0x0223
00002c0: 0200 0000 2302 0000 0020 0000 0100 0000  ....#.... ......
!:classDataItem,0x01项,偏移022f
00002d0: 2f02 0000 0010 0000 0100 0000 4002 0000  /...........@...
typeMapList,0x01项,偏移0x0240

前面的map项与头定义是重复的,后面的map项对数据区又进一步进行了划分.
从0x130开始,到0x240止.又多了codeItem, typeList, stringDataItem,
debugInfoItem, classDataItem

至此hello.dex 才算分析完毕! 来点总结发言吧.
dex文件格式分为三个部分,头部,索引区,数据区.
以常量字符串为基础,定义了字符串表.
名称,类型以字符串序号为索引,
类型表是类型的数组.
参数列表定义的是size, 类型表索引,参数列表在数据区.
函数原型表元素包含了函数名,返回类型,参数列表.
成员变量表项包含了类名,类型及名称
成员函数表项包含了类名,函数原型,及名称.
类定义表项主要包含了类名,父类名,访问标志.类数据偏移. 还有类所在的文件名,接口,注释,静态数据等较次要信息.
类数据由它的头部各size定义及对应的数据实体构成.
在hello.dex中重点关注了dexMethod 实体,它由methodIdx, 访问标志及代码偏移来构成.
它们就是这样以表格的形式,被一层层定义和索引,
最后map表,指出了整个文件的不同区域划分!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值