当我们编写Java代码时,生成的文件是. Java文件,但JVM不知道这一点,所以首先将其转换为class文件,但在Android端,Android上的Davlik虚拟机可以执行. dex 因此,dex文件包含所有app代码,并且可以使用反编译工具检索java代码。
也就是说,dex文件是Android Dalvik虚拟机运行的程序。
为了加深图像,首先创建dex文件。
公共类dex { int a=0; 静态字符串b=’ hellodalvik ‘; 公共int getnumber (inti,int j ) ) inte=3; return e i j; } publicstaticvoidmain (字符串[ ] args ) { int c=1; int d=2; DEX dex=new DEX (; stringsaynumber=string.value of (dex.getnumber (c,d ) ); system.out.println (hellodalvik ‘ say number ); }先运行javac DEX.java
这将生成. class文件,并在SDK中找到dx.bat。
运行xx\XXX\XXX\dx– dex– output=dex.Java dex.class
这将生成DEX.dex文件,如果发生does not match path错误,则执行以下操作:
d :\SDK\build-tools\27.0.1\dx– dex– output=dex.dexcom _ example _ ASUS1_ rexiu fu _ dex.ccoom
DEX文件结构
让我们先看看Header :
文件头包含dex文件的信息,所有数据的大致分布情况
接下来,我们来看看Header的数据图。 让我们打个满意的电话看看:
可以看到第一个。 是magic[8]。 这表示dex文件中的文件标记,一般称为魔数。 用于识别名为dex的文件,可以确定当前dex文件是否有效。 可以看到,它由8字节的1字节无符号数表示。 我们在满意的电话中看到“64 65 78 0A 30 33 35 00字节。 所有这些字节都用十六进制表示。 这8个字节通过ASCII码转换为dex.035。 “.”不是转换的。 现在,德克斯的魔数固定在德克斯. 035
第二个是checksum,这是dex文件的校验和,从而可以确定dex文件是否损坏或篡改。 占用4个字节
可以看到,该值及其对应的4字节正好相反。 这是因为dex文件采用了小字节顺序的编码方法,低阶比特中存储的是低字节的内容。
第三个字段SHA1 signature[20],signature用于验证dex文件,实际上是整个dex文件在SHA-1上签名的值。 这里占用了20字节。
第四个是fileSize,表示整个文件的大小,占用4个字节
第五个是headerSize,表示DexHeader报头结构的大小,占用4个字节。
第六个是endianTag,表示端序符号,用于dex运行环境中的cpu。 默认值为0x 12345678,101满意的电话支持“78 56 34 12”
以下两个分别是linkSize和linkOff,这是用于指定链接段大小和文件偏移的字段,通常均为0 : 如果linkSize为0,则表示静态连接。
接下来是mapOff字段。 这指定DexMapList的文件偏移,也就是dex文件映射的最后一个层次。
以下两个3358www.Sina.com/和StringIdsSize:这些字段指定在dex文件中使用的所有字符串的数量和位置偏移。 首先,让我们看看StringIdsSize。 目前,十进制值为28。 也就是说,这个dex文件共有28个字符串。 StringIdsOff的值为700000,表示字符串的偏移位置为70h。 然后,找到70h的位置。
第四个字符串是” HelloDalVik “,
让我们来看看dex的结构图:
然后我们继续看
接下来是StringIdsOff和typeIdsSize,它们表示类类型的数量和位置的偏差,均占4个字节,为类型大小
的的值为9,表示dex文件中用到的类的类型一共有9个,typeIdsOff的值为“E0 00 00 00 ”,即偏移位置在E0:
接下来两个是protoIdsSize和protoIdsOff,它们表示dex文件中方法原型的个数和位置偏移,现在protoIdsSize的值为7,说明有7个方法原型,然后位置偏移是104h
这里涉及到一个数据结构:
struct DexProtoId{u4 shortyIdx;/*指向DexStringId列表的索引*/u4 returnTypeIdx;/*指向DexTypeId列表的索引*/u4 parametersOff;/*指向DexTypeList的位置偏移*/}
可以看到,这个数据结构由三个变量组成。第一个shortyIdx,它指向我们上面分析的DexStringId列表的索引,代表的是方法声明字符串。第二个returnTypeIdx它指向的是我们上班分析的DexTypeId列表索引,代表的是方法返回类型字符串。第三个parameterOff指向的是DexTypeList的位置索引,这又是一个新的数据结构,这里面存储的是方法的参数类别。
可以看到这三个参数,方法声明字符串,返回类型,参数列表,这基本上确定了我们一个方法的大体内容。
struct DexTypeList{u4 size;/*DexTypeItem的个数*/DexTypeItem list[1];/*DexTypeItem结构*/}struct DexTypeItem{u2 typeIdx;/*指向DexTypeId列表的索引*/}
这样的话,我们可以看到,第一个方法为 int(int,int)
我们继续看下面的两个,fieldIdsSize和fieldIdsOff,指向的是dex文件中字段名的信息。这里fieldIdsSize的大小为3,fieldIdsOff的值为“58 01 00 00 ”:
又涉及到有个数据结构:
struct DexFieldId{u2 classIdx;/*类的类型,指向DexTypeId列表的索引*/u2 typeIdx;/*字段类型,指向DexTypeId列表的索引*/u4 nameIdx;/*字段名,指向DexStringId列表的索引*/}
我们可以看到第一个DexFieldId是Dex中的a
继续继续,methodIdsSize和methodIdsOff,指明了方法所在的类,方法的声明以及方法名,现在methodIdsSize的值为10,methodIdsOff的值为“70 01 00 00”,
它涉及到的数据结构:
struct DexMethodId{u2 classIdx;/*类的类型,指向DexTypeId列表的索引*/u2 protoIdx;/*声明类型,指向DexProtoId列表的索引*/u4 nameIdx;/*方法名,指向DexStringId列表的索引*/}
分析可以得到,第一个方法为 void DEX.<clinit>()
接下来是classDefsSize和classDefsOff,这两个字段指明的是dex文件中类的定义的相关信息,在这里,classDefsSize的值是1,classDefsOff的是“C0 01 00 00”,
这里涉及的数据结构:
struct DexClassDef{u4 classIdx;/*类的类型,指向DexTypeId列表的索引*/u4 accessFlags;/*访问标志*/u4 superclassIdx;/*父类类型,指向DexTypeId列表的索引*/u4 interfacesOff;/*接口,指向DexTypeList的偏移*/u4 sourceFileIdx;/*源文件名,指向DexStringId列表的索引*/u4 annotationsOff;/*注解,指向DexAnnotationsDirectoryItem结构*/u4 classDataOff;/*指向DexClassData结构的偏移*/u4 staticValuesOff;/*指向DexEncodedArray结构的偏移*/}
我们可以看到,这个找到的类是DEX
接下来是DataSize和DataOff,这里DataOff的值是“E0 01 00 00 ”,找到01E0h,这里存放的是DexCode。
dex文件的加载流程
https://blog.csdn.net/jsqfengbao/article/details/52103439
https://www.jianshu.com/p/c9fd64e0b934
参考:
https://blog.csdn.net/sinat_18268881/article/details/55832757