part-class-defs

ClassDefs 表示某个类的全部信息,包括类类型、访问权限、父类、接口、源文件名、注解和代码等信息。
ClassDefs 的大小和文件偏移在 DexHeader 和 map_list 中都有指定。


结构

ClassDefs 以4字节对齐,即总大小为 4 * 8 * ClassDefsSize .

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
* Direct-mapped "class_def_item".
*/
struct DexClassDef {
u4 classIdx; /* 指向 typeIds 的索引,表示类的类型 */
u4 accessFlags; /* 类的访问标识*/
u4 superclassIdx; /* 指向 typeIds 的索引,表示父类类型 */
u4 interfacesOff; /* 指向 DexTypeList 的文件偏移,表示接口*/
u4 sourceFileIdx; /* 指向 stringIds 的索引,表示源文件名 */
u4 annotationsOff; /* 指向 annotations_directory_item 的文件偏移,表示注解*/
u4 classDataOff; /* 指向 class_data_item 的文件偏移*/
u4 staticValuesOff; /* 指向 DexEncodedArray 的文件偏移*/
};

classIdx

指向 typeIds 的索引,类类型,必须是一个类类型而不是数组或者基本类型。


accessFlags

类的访问标识,如 public、final 等,常量定义如下,包括类、字段和方法的访问标识:

Name Value For Classes (and InnerClass annotations) For Fields For Methods
ACC_PUBLIC 0x1 public: visible everywhere public: visible everywhere public: visible everywhere
ACC_PRIVATE 0x2 * private: only visible to defining class private: only visible to defining class private: only visible to defining class
ACC_PROTECTED 0x4 * protected: visible to package and subclasses protected: visible to package and subclasses protected: visible to package and subclasses
ACC_STATIC 0x8 * static: is not constructed with an outer this reference static: global to defining class static: does not take a this argument
ACC_FINAL 0x10 final: not subclassable final: immutable after construction final: not overridable
ACC_SYNCHRONIZED 0x20 synchronized: associated lock automatically acquired around call to this method.Note: This is only valid to set when ACC_NATIVE is also set.
ACC_BRIDGE 0x40 bridge method, added automatically by compiler as a type-safe bridge
ACC_VOLATILE 0x40 volatile: special access rules to help with thread safety
ACC_TRANSIENT 0x80 transient: not to be saved by default serialization
ACC_VARARGS 0x80 last argument should be treated as a “rest” argument by compiler
ACC_NATIVE 0x100 native: implemented in native code
ACC_INTERFACE 0x200 interface: multiply-implementable abstract class
ACC_ABSTRACT 0x400 abstract: not directly instantiable abstract: unimplemented by this class
ACC_STRICT 0x800 strictfp: strict rules for floating-point arithmetic
ACC_SYNTHETIC 0x1000 not directly defined in source code not directly defined in source code not directly defined in source code
ACC_ANNOTATION 0x2000 declared as an annotation class
ACC_ENUM 0x4000 declared as an enumerated type declared as an enumerated value
(unused) 0x8000
ACC_CONSTRUCTOR 0x10000 constructor method (class or instance initializer)
ACC_DECLARED_SYNCHRONIZED 0x20000 declared synchronized. Note: This has no effect on execution (other than in reflection of this flag, per se).

superclassIdx

指向 typeIds 的索引,父类类型;如果没有父类值为 NO_INDEX . 注意 NO_INDEX 值不是0,因为 0 是一个合法的索引,而且 NO_INDEX 是以 uleb128p1 编码的。

1
uint NO_INDEX = 0xffffffff; // == -1 if treated as a signed int

interfacesOff

指向 DexTypeList 的文件偏移(在数据段中),表示接口;如果没有接口此值为 0 。
DexTypeList 中的值必须是类类型,并且没有重复。

1
2
3
4
5
6
7
8
9
10
11
12
13
/*
* Direct-mapped "type_list".
*/
struct DexTypeList {
u4 size; /* DexTypeItem的个数 */
DexTypeItem list[1]; /* DexTypeItem的内容 */
};
/*
* Direct-mapped "type_item".
*/
struct DexTypeItem {
u2 typeIdx; /* 指向 typeIds 的索引 */
};

sourceFileIdx

指向 stringIds 的索引,表示本类所在的源文件名,如果没有这个信息值为 NO_INDEX


annotationsOff

指向 annotations_directory_item 的文件偏移,表示注解;如果没有注解,此值为 0 。

annotations_directory_item

1
2
3
4
5
6
7
8
9
10
11
12
/*
* Direct-mapped "annotations_directory_item".
*/
struct DexAnnotationsDirectoryItem {
u4 classAnnotationsOff; /* 指向 DexAnnotationSetItem 的文件偏移,若无,值为0*/
u4 fieldsSize; /* DexFieldAnnotationsItem 的个数*/
u4 methodsSize; /* DexMethodAnnotationsItem 的个数*/
u4 parametersSize; /* DexParameterAnnotationsItem 的个数*/
/* followed by DexFieldAnnotationsItem[fieldsSize] */
/* followed by DexMethodAnnotationsItem[methodsSize] */
/* followed by DexParameterAnnotationsItem[parametersSize] */
};

annotation_set_item

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
* Direct-mapped "annotation_set_item".
*/
struct DexAnnotationSetItem {
u4 size; /* DexAnnotationItem 的个数*/
u4 entries[1]; /* DexAnnotationItem 的内容*/
};
/*
* Direct-mapped "annotation_item".
*
* NOTE: this structure is byte-aligned.
*/
struct DexAnnotationItem {
u1 visibility; /* 可见性 */
u1 annotation[1]; /* 以 encoded_annotation 格式编码 */
};

visibility 定义:

Name Value Description
VISIBILITY_BUILD 0x00 编译时可见
VISIBILITY_RUNTIME 0x01 运行时可见
VISIBILITY_SYSTEM 0x02 运行时可见, 但是只对系统可见,用户代码不可见

encoded_annotation 格式定义:

Name Format Description
type_idx uleb128 注解类型. 必须是类类型.
size uleb128 注解中 name-value 键值对的个数.
elements annotation_element[size] 注解的元素(不是偏移). 元素需按 string_id 的索引升序排列.

annotation_element格式:

Name Format Description
name_idx uleb128 代表元素名称,是指向 stringIds 的索引 .
value encoded_value 元素值

encoded_value格式:

Name Format Description
(value_arg << 5) | value_type ubyte 表示后面 value 的类型, 可选高三位 clarifying argument .下面详述. value_arg 表示 value 的长度(size - 1), 比如 0 表示 value 需要 1字节, 7 表示 value 需要8字节,不过还是有例外,下面详述.
value ubyte[] 值,不同的类型有不同的解码方式, 通常是小端存储。

value 的格式:

类型名 类型值 value_arg Format value Format 描述
VALUE_BYTE 0x00 必须是0 ubyte[1] 有符号1字节整形值
VALUE_SHORT 0x02 size - 1 (0…1) ubyte[size] 有符号4字节整型值,符号扩展
VALUE_CHAR 0x03 size - 1 (0…1) ubyte[size] 无符号4字节整型值,0扩展
VALUE_INT 0x04 size - 1 (0…3) ubyte[size] 有符号4字节整型值,符号扩展
VALUE_LONG 0x06 size - 1 (0…7) ubyte[size] 有符号8字节整型值,符号扩展
VALUE_FLOAT 0x10 size - 1 (0…3) ubyte[size] 4字节位模式,0扩展为右侧,以 IEEE754 32位浮点类型解码
VALUE_DOUBLE 0x11 size - 1 (0…7) ubyte[size] 8字节位模式,0扩展为右侧,以 IEEE754 64位浮点类型解码
VALUE_STRING 0x17 size - 1 (0…3) ubyte[size] 无符号(0扩展)4字节整形,解码为指向string_ids的索引,代表字符串
VALUE_TYPE 0x18 size - 1 (0…3) ubyte[size] 符号(0扩展)4字节整形,解码为指向type_ids的索引,代表类型或类
VALUE_FIELD 0x19 size - 1 (0…3) ubyte[size] 符号(0扩展)4字节整形,解码为指向field_ids的索引,代表字段
VALUE_METHOD 0x1a size - 1 (0…3) ubyte[size] 符号(0扩展)4字节整形,解码为指向method_ids的索引,代表方法
VALUE_ENUM 0x1b size - 1 (0…3) ubyte[size] 无符号(0扩展)4字节整形,解码为指向field_ids的索引,代表枚举常量
VALUE_ARRAY 0x1c 必须是0 encoded_array 数组,格式为encoded_array format.
VALUE_ANNOTATION 0x1d 必须是0 encoded_annotation 子注解, 格式为encoded_annotation format.
VALUE_NULL 0x1e 必须是0 (none) null
VALUE_BOOLEAN 0x1f boolean (0…1) (none) 一比特的值, 0 代表 false , 1 代表 true.

field_annotations_item

1
2
3
4
5
6
7
/*
* Direct-mapped "field_annotations_item".
*/
struct DexFieldAnnotationsItem {
u4 fieldIdx;
u4 annotationsOff; /* 指向 DexAnnotationSetItem 的文件偏移*/
};

method_annotations_item

1
2
3
4
5
6
7
/*
* Direct-mapped "method_annotations_item".
*/
struct DexMethodAnnotationsItem {
u4 methodIdx;
u4 annotationsOff; /* 指向 DexAnnotationSetItem 的文件偏移 */
};

parameter_annotations_item

1
2
3
4
5
6
7
/*
* Direct-mapped "parameter_annotations_item".
*/
struct DexParameterAnnotationsItem {
u4 methodIdx;
u4 annotationsOff; /* 指向 DexAnnotationSetRefList 的文件偏移*/
};
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
* Direct-mapped "annotation_set_ref_list".
*/
struct DexAnnotationSetRefList {
u4 size;
DexAnnotationSetRefItem list[1];
};
/*
* Direct-mapped "annotation_set_ref_item".
*/
struct DexAnnotationSetRefItem {
u4 annotationsOff; /* offset to DexAnnotationSetItem */
};

常量定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/* annotation constants */
enum {
kDexVisibilityBuild = 0x00, /* annotation visibility */
kDexVisibilityRuntime = 0x01,
kDexVisibilitySystem = 0x02,
kDexAnnotationByte = 0x00,
kDexAnnotationShort = 0x02,
kDexAnnotationChar = 0x03,
kDexAnnotationInt = 0x04,
kDexAnnotationLong = 0x06,
kDexAnnotationFloat = 0x10,
kDexAnnotationDouble = 0x11,
kDexAnnotationString = 0x17,
kDexAnnotationType = 0x18,
kDexAnnotationField = 0x19,
kDexAnnotationMethod = 0x1a,
kDexAnnotationEnum = 0x1b,
kDexAnnotationArray = 0x1c,
kDexAnnotationAnnotation = 0x1d,
kDexAnnotationNull = 0x1e,
kDexAnnotationBoolean = 0x1f,
kDexAnnotationValueTypeMask = 0x1f, /* low 5 bits */
kDexAnnotationValueArgShift = 5,
};

classDataOff

指向 class_data_item 的文件偏移,如果此类没有数据(如接口),值为0.
除了 DexCode 之外的结构是定义在 /dalvik/libdex/DexCLass.h 文件中的,并且采用的是 uleb128 编码方式。与之前不同

class_data_item 定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/* 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; /* 字段与方法的个数 */
DexField* staticFields; /* 静态字段结构 */
DexField* instanceFields; /* 实例字段结构 */
DexMethod* directMethods; /* 直接方法结构 */
DexMethod* virtualMethods; /* 虚方法结构 */
};
/* 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; /*指向 DexFieldId 的索引 */
u4 accessFlags; /* 访问标识 */
};
/* expanded form of encoded_method */
struct DexMethod {
u4 methodIdx; /* 指向 DexMethodId 的索引 */
u4 accessFlags; /* 访问标识 */
u4 codeOff; /* 指向 DexCode 的文件偏移,如果方法是abstract或者native的,值为0*/
};

code_item

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/*
* Direct-mapped "code_item".
*
* The "catches" table is used when throwing an exception,
* "debugInfo" is used when displaying an exception stack trace or
* debugging. An offset of zero indicates that there are no entries.
*/
struct DexCode {
u2 registersSize; /* 使用的寄存器个数 */
u2 insSize; /* 参数个数 */
u2 outsSize; /* 调用其他方法时使用的寄存器个数 */
u2 triesSize; /* Try 的个数*/
u4 debugInfoOff; /* 调试信息(行号和局部变量信息)的文件偏移,没有的话值为0,结构为 debug_info_item*/
u4 insnsSize; /* 指令个数,以2字节为单位*/
u2 insns[1]; /* 指令数组,指令含义参考dalvik字节码格式*/
/* 2字节用于对齐(try的结构是以4字节对齐的,只有triesSize不为0且insnsSize为奇数的时候此值才会出现) */
/* try_item[triesSize] DexTry 结构,指示哪里有异常,怎样处理;数组中的元素必须没有重叠和覆盖 */
/* try/catch 中 handler 的个数 */
/* catch_handler_item[handlersSize] DexCatchHandler结构*/
};

debug_info_item

每个 debug_info_item 以一个变长的 header 开始(长度取决于方法的参数个数),接着是操作码(用来修改状态机器码的值),最后是一个结束字节 DBG_END_SEQUENCE

状态机器码 包含5个寄存器,同时也追踪着每个寄存器中最后一个局部变量的名字和类型,为 DBG_RESTART_LOCAL 做准备。
address寄存器代表两字节指令的偏移地址,在每个 debug_info 序列里以0开始,单调递增;
line寄存器代表下一条指令的行数,它在 header 中被初始化,可能会加减变化但绝不会小于 1;
source_file寄存器代表行数所在的源文件,它的类型是 class_def_item 中的 source_file_idx;
prologue_endepilogue_begin 是布尔类型的标识(初始值为false),代表下一条指令是不是函数入口或者函数结束。

header 的格式:

Name Format Description
line_start uleb128 line 寄存器的初始值,不代表真实的入口
parameters_size uleb128 参数名字的个数. 如果是实例方法的话,不包括this.
parameter_names uleb128p1[parameters_size] 方法的参数名的字符串索引. NO_INDEX 表示相关参数没有名字. 类型描述符和签名同方法的类型描述符和签名.

debug_info 中操作的值:

名字 格式 参数 描述
DBG_END_SEQUENCE 0x00 (none) 代表调试信息的终止
DBG_ADVANCE_PC 0x01 uleb128 addr_diff addr_diff: 地址寄存器加上此值 使address寄存器指向下一个地址
DBG_ADVANCE_LINE 0x02 sleb128 line_diff line_diff: line寄存器加上此值 使line寄存器指向新的一行
DBG_START_LOCAL 0x03 uleb128 register_num,uleb128p1 name_idx,uleb128p1 type_idx register_num: 某个寄存器,name_idx: 指向string的索引,type_idx: 指向type的索引 在当前地址引入一个局部变量. name_idx 或 type_idx 可能是 NO_INDEX,代表此值未知.
DBG_START_LOCAL_EXTENDED 0x04 uleb128 register_num,uleb128p1 name_idx,uleb128p1 type_idx,uleb128p1 sig_idx register_num: 某个寄存器,name_idx: 指向string的索引,type_idx: 指向type的索引,sig_idx: 指向string的索引,表示类型签名 在当前地址引入一个带有类型签名的局部变量. name_idx 或 type_idx、sig_idx 可能是 NO_INDEX,代表此值未知.”dalvik.annotation.Signature” 有关于处理签名的说明.
DBG_END_LOCAL 0x05 uleb128 register_num register_num: 某个寄存器 代表当前地址的局部变量超出范围
DBG_RESTART_LOCAL 0x06 uleb128 register_num register_num: 重新赋值的寄存器 在当前地址重新引入一个局部变量.名字和类型同上一个局部变量.
DBG_SET_PROLOGUE_END 0x07 (none) 设置 prologue_end 状态寄存器, 表示下一个入口点应该被视作方法开始的结束(可设置方法断点的合适地方). prologue_end寄存器的值可以被任何>=0x0a的特殊操作码清空.
DBG_SET_EPILOGUE_BEGIN 0x08 (none) 设置epilogue_begin状态寄存器, 表示下一个入口点应该被视作方法结束的开始(在方法结束之前使其挂起的合适地方). epilogue_begin寄存器的值可以被任何>=0x0a的特殊操作码清空.
DBG_SET_FILE 0x09 uleb128p1 name_idx name_idx: 指向string的索引,表示源文件名; NO_INDEX 表示未知 表面接下来的行号入口都与这个文件相关, 而不是 code_item 指定的默认名字.
Special Opcodes 0x0a…0xff (none) line、address寄存器加减, 开启新的入口点, 清空 prologue_end、 epilogue_begin寄存器. 公式如下.

Special Opcodes:

使 line、address 寄存器小幅度变化/开启一个新的入口点. 范围是 0x0a ~ 0xff .

DBG_FIRST_SPECIAL = 0x0a // 最小的特殊操作码
DBG_LINE_BASE = -4 // 最小的行号增量
DBG_LINE_RANGE = 15 // 代表行号的变化值

公式:
adjusted_opcode = opcode - DBG_FIRST_SPECIAL
line += DBG_LINE_BASE + (adjusted_opcode % DBG_LINE_RANGE)
address += (adjusted_opcode / DBG_LINE_RANGE)

try_item

1
2
3
4
5
6
7
8
/*
* Direct-mapped "try_item".
*/
struct DexTry {
u4 startAddr; /* 异常起始地址, 2个字节为单位 */
u2 insnCount; /* 指令个数, 2个字节为单位,最后一个指令为 startAddr + insnCount - 1 */
u2 handlerOff; /* 以 handler 列表为起始的 指向异常对应的 handler 的偏移*/
};

catch_handler_item

1
2
3
4
5
6
7
/*
* Catch handler entry, used while iterating over catch_handler_items.
*/
struct DexCatchHandler {
u4 typeIdx; /* catch 到的异常的类型索引,指向 typeIds */
u4 address; /* handler 的地址 */
};

番外 - 关于 catch_handler_list

catch_handler_list 在源码中没有定义,下面的表格是其格式:

Name Format Description
size uleb128 handler 列表的个数
list encoded_catch_handler[handlers_size] handler 列表

单个 catch_handler 的格式:

Name Format Description
size sleb128 列表中 catch 到的类型的个数. 如果不是正数,则handler列表中含有可以捕获到所有异常的handler. 比如 0 表示没有指定异常的类型,只有一个所有异常handler. 2 表示有两个指定类型的异常. -1 有一个指定类型的异常和一个可以捕获到所有异常的handler.
handlers DexCatchHandler[abs(size)] abs(size) 个handler, 存放的是指定类型的异常.
catch_all_addr uleb128 (optional) 可以处理所有异常的 handler 的地址. size为0或者负数时此值有效.

staticValuesOff

指向 DexEncodedArray 的文件偏移,表示静态字段的初始值,值为0表示没有设定静态字段的初始值,静态字段被初始化为0或者null.

1
2
3
4
5
6
7
8
/*
* Direct-mapped "encoded_array".
*
* NOTE: this structure is byte-aligned.
*/
struct DexEncodedArray {
u1 array[1]; /* encoded_array 格式的数据 */
};

encoded_array 格式:

Name Format Description
size uleb128 数组元素的个数,必须不大于静态字段的个数和对应的field_list的个数,如果是小于,剩余的静态字段按照相应的类型被初始化为0或者null.
values encoded_value[size] 数组内容

手工查找

classDefsSize:0x02
classDefsOff:0x047c

0x047c ~ 0x04bc

DexClassDef数据及其解析

1
2
3
4
5
00000470 .. .. .. .... .. .. .. .. .. .. .. 05 00 00 00 |------------....|
00000480 01 00 00 00 0e 00 00 00 00 00 00 00 1f 00 00 00 |................|
00000490 00 00 00 00 c2 0f 00 00 00 00 00 00 06 00 00 00 |................|
000004a0 01 00 00 00 02 00 00 00 00 00 00 00 20 00 00 00 |............ ...|
000004b0 64 0a 00 00 de 0f 00 00 00 00 00 00

以第一个为例:

  1. classIdx=0x05,即第0x05个typeId,得类类型为 Lcom/shell/NativeApplication;

  2. accessFlags=0x01,查表得权限 ACC_PUBLIC

  3. superclassIdx=0x0e,即第0x0e个typeId,得父类类型为 Ljava/lang/Object;

  4. interfacesOff=0x0000,没有实现接口

  5. sourceFileIdx=0x1f,即第0x1f个stringId,得源文件名为 NativeApplication.java

  6. annotationsOff=0x0000,没有注解

  7. classDataOff=0x0fc2,得DexClassData偏移为0x0fc2

  8. staticValuesOff=0x0000,没有静态数据的初始值

DexClassData数据及其解析

1
2
3
00000fc0 .. .. 00 00 05 00 03 88 80 04 90 18 01 81 80 04 |................|
00000fd0 b8 18 01 89 02 00 01 89 02 00 01 89 02 00 00 00 |................|
00000fe0 03 04 08 81 80 04 d0 18 03 02 e8 18 01 09 f4 19 |................|

[注意DexClassData中数字的类型为uleb128]
headerstaticFieldsSize=0x00, instanceFieldsSize=0x00, directMethodsSize=0x05, virtualMethodsSize=0x00, 即0个静态字段,0个实例字段,5个直接方法,0个虚方法;

directMethods:(共5个,以第一个为例)

  • methodIdx=0x03,即第0x03个methodId,得直接方法为 void com.shell.NativeApplication.()
  • accessFlags=88 80 04,解码为0x10008,得方法访问权限为 ACC_STATIC 和 ACC_CONSTRUCTOR
  • codeOff=90 18,解码为0xc10,得 DexCode 偏移为 0xc10

DexCode数据及其解析

1
2
3
4
5
6
7
8
00000c10 01 00 00 00 01 00 00 00 7c 0a 00 00 0b 00 00 00 |........|.......|
00000c20 1a 00 00 00 71 10 20 00 00 00 1a 00 01 00 71 10 |....q. .......q.|
00000c30 20 00 00 00 0e 00 00 00 01 00 01 00 01 00 00 00 | ...............|
00000c40 83 0a 00 00 04 00 00 00 70 10 1d 00 00 00 0e 00 |........p.......|
00000c50 01 00 01 00 01 00 00 00 88 0a 00 00 04 00 00 00 |................|
00000c60 70 10 00 00 00 00 0e 00 0a 00 04 00 04 00 01 00 |p...............|
00000c70 8d 0a 00 00 38 00 00 00 6e 10 12 00 09 00 0c 05 |....8...n.......|
00000c80 6e 10 11 00 05 00 0a 05 39 05 09 00 6e 10 12 00 |n.......9...n...|
  • registersSize=0x0001,得寄存器个数为1
  • insSize=0x0000,得参数个数为0
  • outsSize=0x0001,调用其他方法使用寄存器个数为1
  • triesSize=0x0000,try的个数为0
  • debugInfoOff=0x0a7c,debug信息偏移为0x0a7c
  • insnsSize=0x0b,即有0xb个2字节指令,在 0x00000c20 ~ 0x00000c35 之间
  • insns={1a 00 00 00 71 10 20 00 00 00 1a 00 01 00 71 10 20 00 00 00 0e 00}

debug_info数据及其解析

1
2
00000a70 .. .. .. .. .. .. .. .. .. .. .. .. 09 00 07 0e |........\.......|
00000a80 5a 56 00
  • header:
    line_start(09)=0x09,得line寄存器的初始值为0x09;
    parameters_size(0x00)=0x00,得参数的名字的个数为0;
  • 操作码:
    0x07:DBG_SET_PROLOGUE_END,方法开始;
    0x0e:0x0e-0x0a=0x04,即行号+=DBG_LINE_BASE+(0x04%DBG_LINE_RANGE),地址+=(0x04/DBG_LINE_RANGE),得行号+0,地址+0;
    0x5a:0x5a-0x0a=0x50,即行号+=DBG_LINE_BASE+(0x50%DBG_LINE_RANGE),地址+=(0x50/DBG_LINE_RANGE),得行号+1,地址+5;
    0x56:0x56-0x0a=0x4c,即行号+=DBG_LINE_BASE+(0x4c%DBG_LINE_RANGE),地址+=(0x4c/DBG_LINE_RANGE),得行号+1,地址+5;
    0x00:DBG_END_SEQUENCE,调试结束。

insns 中的指令数据的解析

Dalvik bytecode 找到 OpCode 的含义及格式,在 Dalvik Executable instruction formats 找到该格式的表示方式。

第1条代码:

1a : 含义为 const-string vAA, string@BBBB, 格式为 1a 21c
21c : 格式为 AA|op BBBB,表示方式有三种:

1
2
3
op vAA, type@BBBB
op vAA, field@BBBB
op vAA, string@BBBB

1a 的含义已经为我们指明,我们应该采用第三种。1a 后面的6个字节为 00 00 00,即 AA 是 00,BBBB 是 0000。
则可翻译为 const-string v0, string@0000, 找到第0x0个 StringId 对应的字符串 /data/data/com.zyh.lightingbackup/.lib/libexec.so .
最终解析为 const-string v0, "/data/data/com.zyh.lightingbackup/.lib/libexec.so"

第2条代码:

71 : 含义为 invoke-static,格式为 71 35c
35c : 格式为 A|G|op BBBB F|E|D|C ,表示方式有7种:

1
2
3
4
5
6
7
[A=5] op {vC, vD, vE, vF, vG}, meth@BBBB
[A=5] op {vC, vD, vE, vF, vG}, type@BBBB
[A=4] op {vC, vD, vE, vF}, kind@BBBB
[A=3] op {vC, vD, vE}, kind@BBBB
[A=2] op {vC, vD}, kind@BBBB
[A=1] op {vC}, kind@BBBB
[A=0] op {}, kind@BBBB

71 后面的 A = 1, G = 0,所以应该采用方式 [A=1] op {vC}, kind@BBBB
而 BBBB = 0020, F|E|D|C = 0000,可翻译为 invoke-static {v0}, kind@0020,找到第 0x20 个methodId 对应的函数 void java.lang.System.load(java.lang.String) .
最终解析为 invoke-static {v0}, Ljava/lang/System;->load(Ljava/lang/String;)V

最后我们可以使用 apktool 将 apk 文件反编译,在 /smali/com/shell/NativeApplication.smali 文件中找到 方法,看代码对照!


写程序解析

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def parseClassdef_Name(f):
return DexStruct.DexTypes[struct.unpack('I',f.read(4))[0]]['content']
def parseClassdef_Accessflag(f):
return struct.unpack('I',f.read(4))[0]
def parseClassdef_Superclass(f):
class_superclass_id = struct.unpack('I',f.read(4))[0]
if class_superclass_id == -1:
return None
return DexStruct.DexTypes[class_superclass_id]['content']
def parseClassdef_Interface(f):
interface_off = struct.unpack('I',f.read(4))[0]
if interface_off == 0:
return None
f.seek(interface_off)
type_list_size = struct.unpack('I',f.read(4))[0]
type_list = []
for i in range(type_list_size):
type_id = struct.unpack('H',f.read(2))[0]
type_list.append(DexStruct.DexTypes[type_id]['content'])
return type_list
def parseClassdef_Sourcefile(f):
class_sourcefile_id = struct.unpack('I',f.read(4))[0]
if class_sourcefile_id == -1:
return None
return DexStruct.DexStrings[class_sourcefile_id]['content']
def parseClassdef_Annotations(f):
annotations_directory_off = struct.unpack('I',f.read(4))[0]
if annotations_directory_off == 0:
return None
#-----------
f.seek(annotations_directory_off)
class_Annotations_Off = struct.unpack('I',f.read(4))[0]
field_size = struct.unpack('I',f.read(4))[0]
method_size = struct.unpack('I',f.read(4))[0]
parameter_size = struct.unpack('I',f.read(4))[0]
#---------
annotations_directory = None
if class_Annotations_Off != 0:
# f.seek(class_Annotations_Off)
# annotation_set_item_size = struct.unpack('I',f.read(4))[0]
# for i in range(annotation_set_item_size):
# item_visibility = struct.unpack('B',f.read(1))[0]
# item_annotation = struct.unpack('B',f.read(1))[0]
pass # 解码暂且略过
#--------
f.seek(annotations_directory_off+4*4)
fieldAnnotation_list = []
for i in range(field_size):
field = DexStruct.DexFields[struct.unpack('I',f.read(4))[0]]
field_annotation_off = struct.unpack('I',f.read(4))[0]
fieldAnnotation_item = {
'field' : field,
'annotationsOff' : field_annotation_off,
}
fieldAnnotation_list.append(fieldAnnotation_item)
#--------
f.seek(annotations_directory_off+4*4+field_size*8)
methodAnnotation_list = []
for i in range(method_size):
method= DexStruct.DexMethods[struct.unpack('I',f.read(4))[0]]
method_annotation_off = struct.unpack('I',f.read(4))[0]
methodAnnotation_item = {
'method' : method,
'annotationsOff' : method_annotation_off,
}
methodAnnotation_list.append(methodAnnotation_item)
#--------
f.seek(annotations_directory_off+4*4+field_size*8+method_size*8)
parameterAnnotation_list = []
for i in range(parameter_size):
param_method = DexStruct.DexMethods[struct.unpack('I',f.read(4))[0]]
param_annotation_off = struct.unpack('I',f.read(4))[0]
parameterAnnotation_item = {
'method' : param_method,
'annotationsOff' : param_annotation_off,
}
parameterAnnotation_list.append(parameterAnnotation_item)
tmpDexAnnotationsDirectoryItem = {
'classAnnotations' : annotations_directory,
'fieldSize' : field_size,
'methodSize' : method_size,
'parameterSize' : parameter_size,
'fieldAnnotation' : fieldAnnotation_list,
'methodAnnotation' : methodAnnotation_list,
'parameterAnnotaions' : parameterAnnotation_list,
}
return tmpDexAnnotationsDirectoryItem
def parseClassdef_ClassData(f):
class_data_off = struct.unpack('I',f.read(4))[0]
if class_data_off == 0:
return None
f.seek(class_data_off)
#-----
header = {
'staticFieldsSize' : readuleb128(f),
'instanceFieldsSize' : readuleb128(f),
'directMethodsSize' : readuleb128(f),
'virtualMethodsSize' : readuleb128(f),
}
#-----
staticFields = []
if header['staticFieldsSize'] != 0:
for i in range(header['staticFieldsSize']):
tmpstaticFields = {
'field' : DexStruct.DexFields[readuleb128(f)],
'accessFlags' : readuleb128(f)
}
staticFields.append(tmpstaticFields)
#-----------
instanceFields = []
if header['instanceFieldsSize'] != 0:
for i in range(header['instanceFieldsSize']):
tmpinstanceFields = {
'field' : DexStruct.DexFields[readuleb128(f)],
'accessFlags' : readuleb128(f)
}
instanceFields.append(tmpinstanceFields)
#-----
directMethods = []
if header['directMethodsSize'] != 0:
for i in range(header['directMethodsSize']):
tmpdirectMethods = {
'method' : DexStruct.DexMethods[readuleb128(f)],
'accessFlags' : readuleb128(f),
'codeOff': readuleb128(f),
####### dexcode 还没解析
}
directMethods.append(tmpdirectMethods)
#-----
virtualMethods = []
if header['virtualMethodsSize'] != 0:
for i in range(header['virtualMethodsSize']):
tmpvirtualMethods = {
'method' : DexStruct.DexMethods[readuleb128(f)],
'accessFlags' : readuleb128(f),
'codeOff' : readuleb128(f)
####### dexcode 还没解析
}
virtualMethods.append(tmpvirtualMethods)
DexClassData = {
'DexClassDataHeader' : header,
'staticFields' : staticFields,
'instanceFields' : instanceFields,
'directMethods' : directMethods,
'virtualMethods' : virtualMethods,
}
return DexClassData
def parseClassdef_StaticValue(f):
staticvalue_off = struct.unpack('I',f.read(4))[0]
if staticvalue_off == 0:
return None
return None ## 还没解析 encoded value
def parseClassdefs(f):
'''
此函数基于之前所有的函数结果
'''
for i in range(DexStruct.DexHeader['classDefsSize']):
item_off = i*4*8 + DexStruct.DexHeader['classDefsOff']
f.seek(item_off)
class_name = parseClassdef_Name(f)
class_accessflag = parseClassdef_Accessflag(f)
class_superclass = parseClassdef_Superclass(f)
class_interface = parseClassdef_Interface(f)
f.seek(item_off+4*4)
class_sourcefile = parseClassdef_Sourcefile(f)
class_annotation = parseClassdef_Annotations(f)
f.seek(item_off+4*6)
class_classdata = parseClassdef_ClassData(f)
f.seek(item_off+4*7)
class_staticvalue = parseClassdef_StaticValue(f)
tmpDexClassDef = {
'class' : class_name,
'accessFlags' : class_accessflag,
'superclass' : class_superclass,
'interfaces' : class_interface,
'sourceFile' : class_sourcefile,
'annotations' : class_annotation,
'classData' : class_classdata,
'staticValue' : class_staticvalue,
}
DexStruct.DexClassDefs.append(tmpDexClassDef)

Reference

Dalvik Executable format

《Android 软件安全与逆向分析》