共计 3514 个字符,预计需要花费 9 分钟才能阅读完成。
DEX 文件简介
平安圈的敌人们,对于 DEX 文件应该是比拟理解的。咱们这次就简略介绍一下吧:
DEX 文件(Dalvik Executable)是一种专为 Android 操作系统 设计的可执行文件格局。DEX 文件蕴含了由 Java 语言编写的程序的字节码,这些程序在运行时被 Dalvik 虚拟机(DVM)解释执行。
在 Android 利用程序开发中,Java 代码通过编译器编译生成 Java 字节码文件(.class 文件),而后通过工具将字节码文件转换为 DEX 格局,最初打包成 APK 文件供装置和运行。因为 Android 设施的处理器架构和 Java 虚拟机的差别,所以须要将 Java 字节码转换为 DEX 格局,以便在 Dalvik 虚拟机上运行。
DEX 文件的长处:
1. 可能高效地应用内存和处理器资源,这是因为它采纳了基于寄存器的架构,绝对于传统的基于堆栈的 Java 虚拟机,在执行 Java 程序时,可能更快地加载和执行代码。
2.DEX 文件反对在利用程序运行时动静加载类和办法,提供了更高的灵活性。
所以咱们如果想要理解加固解决方案如何帮忙 Android 利用反抗逆向和破解,首先须要理解 DEX 文件到底是什么样的。
DEX 文件格式解析
1. 文件构造展现
DEX 文件在 010 中的体现
2. 文件构造详解
struct Header {uint8_t magic[8]; // dex 版本标识
uint32_t checksum; // adler32 校验和
uint8_t signature[kShalDigestSize]; // SHA- 1 哈希值
uint32_t file_size; // 文件大小
uint32_t header_size; //Header 构造大小
uint32_t endian_tag; // 字节序标记
uint32_t link_size; // 链接段大小
uint32_t link_off; // 链接段偏移
uint32_t map_off; // 映射项偏移
uint32_t string_ids_size; // 字符串标识符列表个数
uint32_t string_ids_off; // 字符串标识符列表偏移
uint32_t type_ids_size; // 类型标识符列表个数
uint32_t type ids_off; // 类型标识符列表偏移
uint32_t proto_ids_size; // 办法原型标识符列表个数
uint32_t proto_ids_off; // 办法原型标识符列表偏移
uint32 t field ids size; // 字段标识符列表个数
uint32_t field_ids_off; // 字段标识符列表偏移
uint32 t method_ids_size; // 办法标识符列表个数
uint32_t method_ids_off; // 办法标识符列表偏移
uint32_t class_defs_size; // 类定义列表个数
uint32_t class_defs_off; // 类定义列表偏移
uint32_t data_size; // 数据区大小
uint32_t data_off; // 数据区偏移
};
文件头
magic[8]:dex 版本标识。这类字节必须呈现在 .dex 文件的结尾,以便零碎将其原样辨认。该值会特意蕴含一个换行符 ("\n" 或 0x0a) 和空字节("\0" 或 0x00),以便帮助检测某些模式的损坏问题。该值还能够将格局版本号编码为 3 个十进制数字; 随着格局的演变,预计该值会枯燥递增。checksum:能够用于文件残余内容 (除 magic 和此字段之外的所有内容) 的 adler32 校验和。另外,还能够用于检测文件损坏状况。signature[kSha1DigestSize]:文件残余内容 (除 magic、checksum 和此字段之外的所有内容) 的 SHA-1 签名(哈希); 用于对文件进行惟一标识。file_size:整个文件 (包含标头) 的大小,以字节为单位。header_size:标头 (整个区段) 的大小,以字节为单位。这一项容许至多肯定水平的向后 / 向前兼容性,而不用让格局生效。endian_tag:字节序标记。ENDIAN_CONSTANT,示意小端字节序。REVERSE_ENDIAN_CONSTANT 示意大端字节序,默认值为 ENDIAN_CONSTANT。link_size 与 link_off:链接区段的大小与文件偏移。如果此文件未进行动态链接,则两个值都为 0。map_off:从文件结尾到映射项列表的文件偏移量。string_ids_size 与 string_ids_off:字符串标识符列表中的字符串数量与文件偏移。type_ids_size 与 type_ids_off:类型标识符列表中的元素数量及文件偏移。元素数量下限为 65535。proto_ids_size 与 proto_ids_off:原型标识符列表中的元素数量及文件偏移。元素数量下限为 65535。field_ids_size 与 field_ids_off:字段标识符列表中的元素数量及文件偏移。method_ids_size 与 method_ids_off:办法标识符列表中的元素数量及文件偏移。class_defs_size 与 class_defs_off:类定义列表中的元素数量及文件偏移。data_size 与 data_off:data 区段的大小及文件偏移。
字符串标识符列表 (dex_string_ids) 在 DEX 文件以 DexStringId[] 的模式存在,其构造如下。
struct DexStringId {u4 stringDataOff; // 字符串数据的文件偏移};
类型标识符列表 (dex_type_ids) 在 DEX 文件以 DexTypeId[] 的模式存在,其构造如下。
struct DexType {u4 descriptorIdx; // 类型描述符对应在字符串标识符列表中的索引};
办法原型标识符列表 (dex_proto_ids) 在 DEX 文件以 DexProtoId[] 的模式存在,其中 DexProtoId 构造如下。
struct DexProtoId {
u4 shortyIdx; // 办法原型的简写模式对应在字符串标识符列表中的索引
u4 returnTypeIds; // 返回值类型对应在类型标识符列表中的索引
u4 parametersOff; // 参数类型在 DEX 文件中的偏移,构造为 DexTypeList
};
DexTypeList 构造如下。
struct DexTypeItem {u2 typeIdx; // 类型在类型标识符表中的索引};
struct DexTypeList {
u4 size; // 返回值类型对应在类型标识符列表中的索引
DexTypeItem List[1]; // DexTypeItem 数组
};
办法标识符列表(dex_method_ids) 在 DEX 文件以 DexMethodId[] 的模式存在,其中 DexMethodId 构造如下
struct DexMethodId {
u2 classIdx; // 类定义在类型标识符列表中的索引
u2 protoIdx; // 办法原型类型在办法原型标识符列表中的索引
u2 nameIdx; // 办法名称在字符串列表中的索引
};
类定义列列表 (dex_class_defs) 在 DEX 文件以 DexClassDef[] 的模式存在,其中 DexClassDef 构造如下
struct DexClassId {
u4 classIdx; // 类定义在类型标识符列表中的索引
u4 accessFlags; // 类拜访标识
u4 superclassIdx; // 超类在类型标识符列表中的索引
u4 interfaceOff; // 接口,DexTypeList 构造的文件偏移
u4 sourceFileIdx; // 源文件名在字符串示意列表中的索引
u4 annotationsOff; // 注解,DexAnnotationsDirectoryItem 构造的文件偏移
u4 classDataOff; // 类数据,DexClassData 构造的文件偏移
u4 staticValuesOff; // 动态值,DexEncodeArray 构造的文件偏移
};
映射项列表(dex_map_list) 在 DEX 文件以 DexMapItem[] 的模式存在,其中 DexMapItem 构造如下。
struct DexMapItem {
u2 type; // 类型代码
u2 unused; // 未应用
u4 size; // 在指定偏移量处找到的项数量
u4 offset; // 相干项的文件偏移量
};
类型代码表如图所示。
明天就先讲到这里啦,下次将在第二篇文章中持续解析 DEX 文件的 DexAnnotationsDirectoryItem、DexClassData 与 DexEncodeArray 构造,请持续关注~