hello.dex 详细结构分析

本文详细剖析了DEX文件格式的内部结构,包括头部信息、索引区和数据区等内容,并通过一个具体的例子(hello.dex)展示了如何理解DEX文件中的各种元素。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一: 前言

文件数据分析离不开结构分析, 而结构定义权威参考当然是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表,指出了整个文件的不同区域划分!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值