Dex文件分析,从magic到data的全字段,逐字节分析!小白也能懂

文章目录

  • 1、class和dex文件的宏观区别
  • 2、dex文件和class字节码的基本区别
  • 3、dex文件实例分析
    • 3.1配置dx环境变量
    • 3.2Java源文件
    • 3.3 编译成class二进制码
    • 3.4 将二进制class文件优化成dex文件
  • 4、分析dex文件
    • 4.1头文件 header
      • 4.1.1 解析头文件
    • 4.2 索引区的分析
      • 4.2.1 索引区的分析介绍
      • 4.2.2 实例分析

前言:上一次分析了class字节码的文件,然后继续看书的过程中。需要自己制作分析一个dex的工具。制作工具之前,首先是得明白原理,然后再如说是没问题的,今天就此记录我的分析理解。如有不足之处希望大家指出!

1、class和dex文件的宏观区别

dex文件是从class字节码文件中优化出来的产物,class字节码是对于java虚拟机来说的。则dex文件则是对前者优化之后提供给android(安卓davlik虚拟机,应该是安卓4.4版本之前)来说。

2、dex文件和class字节码的基本区别

通过上面的说明,大致我们能明白,dex是建立在class基础之上优化过来的。那两者的区别有哪些呢?

区别 class字节码 dex文件
endian(字符序) 低位在右边,高位在左 低位在左,高位在后
文件区分不同 常量池/data 头文件/索引区/数据区
LEB128 在int基础之上变种的数据类型,高位第7位数(索引为0)据表示是否结束,如果为1则表示后面还有字节。如果第7位表示0,则终止。当第二个或者第三个字节有存在的时候,第二个字节的第0索引,对应的是第一个字节的第七位!每个字节的第七位是判断位

3、dex文件实例分析

3.1配置dx环境变量

我相信能看到这里的人,java环境已经是配置好了的。

找到<SDK_HOME>/build-tools/<VERSION>

这里是你会看到一个dx.bat的批处理脚本。
打开我的电脑,环境变量中,找到环境变量中的path,将全路径放进入。
此时,按住win+r输入cmd,打出dx --version

dx --version
dx version 1.16

3.2Java源文件

package com.company.jvm;
public class Sample {
    public String m1;
    public String m2;
    public Object [] arr;

    public static void main(String[] args) {
        Sample sample = new Sample();
        sample.m1="22";
        sample.arr=new Object[12];
        System.out.println(sample.m1);
    }
}

3.3 编译成class二进制码

javac Sample

3.4 将二进制class文件优化成dex文件

	dx --dex --output=Sample.dex com/comany/jvm/Sample.class

输入上面的指令之后,有可能会报错,出现的问题为:

class name (com/company/jvm/Sample) does not match path (Sample.class)
...while parsing Sample.class

大致意思就说,找不到路径。此时我们需要到包名的根目录下,进入cmd。

4、分析dex文件

上面已经说过,dex文件基本可以分为三个区域:1、头文件 2、索引区 3、数据区

4.1头文件 header

类型 字节长度 说明
magic U8 标识类型,列入class的文件是cafebabe,dex则是dex\n035\0
checksum U4 (除 magic 和此字段之外的所有内容)的 adler32 校验和
signature byte[20] 文件剩余内容(除 magic、checksum 和此字段之外的所有内容)的 SHA-1 签名(哈希);用于对文件进行唯一标识
file_size U4 整个文件(包括标头)的大小,以字节为单位
header_size U4 默认为0x70头文件(整个区段)的大小,以字节为单位。此项允许至少一定程度的向后/向前兼容性,而不会使格式失效。
endian_tag U4 默认为低字符序,取值为0x12345678。如果是big endian则为0x78654321,说明进行过字节交换,这里具体可以查看android关于endian tag的说明
link_size U4 链接区段的大小;如果此文件未进行静态链接,则该值为 0
link_off U4 从文件开头到链接区段的偏移量,如果 link_size == 0,则该值为 0。该偏移量(如果为非零值)应该是到
map_off U4 从文件开头到映射项的偏移量。该偏移量(必须为非零值)应该是到 data 区段的偏移量,而数据应采用下文中“map_list”指定的格式。

4.1.1 解析头文件

对应 偏移位 长度 字符节 说明
magic 0x0000 U8 64 65 78 0a 30 33 35 00 长度为8的byte数组,转换成字符之后就是dex 035
checkSum 0x0008 U4 85 71 f0 2c 其adler32校验和结果就是2CF07185的结果【高位字符序
signature 0x000C byte[20] ~0x10 其结果是sha-1的加密,我这里的结果为:6003000070000000785634120000000000000000
file_size 0x20 U4 60 03 00 00 计算得出为 864,说明当前有864个byte
header_size 0x24 U4 70 00 00 00 一般情况下都为0x70
endian_tag 0x28 U4 78 56 34 12 这里说明是已经是进行过交换处理
link_size 0x2c U4 00 00 00 00 说明没有静态链接,数量为0【何为静态链接,后面的文章应该会梳理。今天的内容不在此】
link_off 0x30 U4 00 00 00 00 偏移量为0
map_off 0x34 U4 C0 02 00 00 数据位置偏移为704

4.2 索引区的分析

4.2.1 索引区的分析介绍

类型 字节长度 说明
string_ids_size U4 字符串的数量
string_ids_off U4 从文件开头到标识符的偏移量
type_ids_size U4 类型标识符列表数量,最多为 65535
type_ids_off U4 从文件开头到类型标识符列表的偏移量;如果 type_ids_size == 0(不可否认是一种奇怪的极端情况),则该值为 0。该偏移量(如果为非零值)应该是到 type_ids 区段开头的偏移量。
proto_ids_size U4 原型标识符列表中的元素数量,最多为 65535
proto_ids_off U4 原型从文件开头到标识符的偏移量
field_ids_size U4 字段数量
field_ids_off U4 从文件开头到字段标识符列表的偏移量
method_ids_size U4 方法标识符列表中的元素数量
method_ids_off U4 从文件开头到方法标识符列表的偏移量
class_defs_size U4 类定义列表中的元素数量
class_defs_off U4 方从文件开头到类定义列表的偏移量
data_size U4 data 区段的大小(以字节为单位)。该数值必须是 sizeof(uint) 的偶数倍
method_ids_off U4 从文件开头到 data 区段开头的偏移量

4.2.2 实例分析

类型 偏移位 字节码 说明
string_ids_size 0x38 12 00 00 00 说明存在18个字符串
string_ids_off 0x3c 70 00 00 00 从文件开头到标识符的偏移量为112
type_ids_size 0x40 08 00 00 00 类型标识符列表数量为:8
type_ids_off 0x44 b8 00 00 00 从文件开头到类型标识符列表的偏移量为:0xb8
proto_ids_size 0x48 03 00 00 00 原型标识符列表中的元素数量为:3
proto_ids_off 0x4c d8 00 00 00 原型从文件开头到标识符的偏移量为:0xd8
field_ids_size 0x50 04 00 00 00 字段数量为4
field_ids_off 0x54 fc 00 00 00 从文件开头到字段标识符列表的偏移量为0x54
method_ids_size 0x58 04 00 00 00 方法标识符列表中的元素数量为:4
method_ids_off 0x5c 1c 01 00 00 从文件开头到方法标识符列表的偏移量为:0x011c
class_defs_size 0x60 01 00 00 00 类定义列表中的元素数量为:1
class_defs_off 0x64 3c 01 00 00 方从文件开头到类定义列表的偏移量0x013c
data_size 0x70 c2 01 00 00 data 区段的大小(以字节为单位)。该数值必须是 sizeof(uint) 的偶数倍,为:450
data_off 0x74 c601 00 00 从文件开头到 data 区段开头的偏移量为0x01c6

~后文待续,坐了一个多小时了,休息会儿

你可能感兴趣的:(Android,java,jvm,开发语言)