Dex文件格式

Dex文件格式

Google虽然借鉴了Java的上层设计,但是虚拟机使用的是自己设计的Dalvik,Dalvik虚拟机读取、解释的文件是DEX文件。虽然在Android 4.0开始,开始引入类似C#的二次编译技术(Android自称ART),Android 5.0已经完全放弃Dalvik虚拟机(所以源码里已经没有Dalvik设计文档了),但是,二次编译技术是安装apk时候的事,我们用Java语言所写的代码,还是要经过.java->.class->.dex->.apk的过程,认识Dex文件格式,还是有助于反汇编成Smali语言,有助于逆向。

dex生成流程

以下Makefile脚本展示了dex文件生成流程:

MODULE_NAME := Hello
START_CLASS := Hellk
DX := ${SDK_PATH}\sdk\build-tools\19.1.0\dx.bat
INSTALL_PATH := /data/local/tmp
 
#用dalvikvm虚拟机解释运行dex文件,需要指定启动类
run:
    adb push ${MODULE_NAME}.dex ${INSTALL_PATH}
    adb shell dalvikvm -cp ${INSTALL_PATH}/${MODULE_NAME}.dex ${START_CLASS}
 
dx: ${MODULE_NAME}.dex ${MODULE_NAME}.class
 
#通过.class生成dx
${MODULE_NAME}.dex: ${MODULE_NAME}.class
    ${DX} --dex --output=${MODULE_NAME}.dex ${MODULE_NAME}.class
     
javac: ${MODULE_NAME}.class
 
#dx所支持的.class版本一般不是最新的
${MODULE_NAME}.class:
    javac -source 1.6 -target 1.6 ${MODULE_NAME}.java

学习Dex文件的工具

推荐使用010 Editor软件,它自带模板插件功能,并且已经有他人制作好的针对Dex文件的模版。可以高亮显示各字段,解析各字段,还附带各字段的注释。对照着Dalvik自带的文档看十六进制,事半功倍

Dex文件组成

按顺序解析dex文件,有以下几个部分:

  1. struct header_item dex_header
  2. struct string_id_list dex_string_ids
  3. struct type_id_list dex_type_ids
  4. struct proto_id_list dex_proto_ids
  5. struct field_id_list dex_field_ids
  6. struct method_id_list dex_method_ids
  7. struct class_def_item_list dex_class_defs
  8. struct map_list_type dex_map_list

其中两头两尾的header_itemmap_list是两张“总表”,包含着其它的表的偏移信息等,两者信息有重叠(冗余)。

各个表的功能及要求:

  1. string_id_item[]: 文件中要用到的所有字符串,按UTF-16编码有序排列
  2. type_id_item[]: 文件中要用到的所有类型信息,但里面并不直接记录着字符串,而是string_id_item[]中的数组下标,且按string_id_item中的数组下标有序排列
  3. proto_id_item[]: 文件中要用到的所有方法原型,相当于所有函数指针的类型信息,也是有序排列的,主序是返回类型,次序是参数类型
  4. field_id_item[]: 文件中要用到的所有成员(含静态与普通),按类的类型、成员名、成员类型优先级递减有序排列。
  5. method_id_item[]: 文件中要用到的所有方法(含静态与普通), 按类的类型、方法名、方法原型优先级递减有序排列。
  6. class_def_item[]: 类的信息在此表中,从此表中,可以解析出内部类、静态与普通成员/方法、Dalvik字符码的位置等与类有关的具体信息,都在此表中

文件头中的校验

在文件头中,以下几项比较关键,影响到dex文件能否被dalvikvm正常执行:

  1. uint checksum: 文件0x8偏移处,通过alder32算法,针对文件0xC至文件尾得到的的校验值。
  2. SHA1 signature[20]: 文件0xC偏移处,通过SHA1算法,镇上 对文件0x20至文件尾得到的HASH值。
  3. uint file_size: 文件0x20偏移处,记录文件长度

对Dex文件进行修改后,要依次更新file_size, signature[20], checksum三个字段,Dex才能正常运行。

dex的一些加固思路

大小尾标签

在header_item中有一个uint endian_tag字段,记录了常量0x12345678,dalvikvm在运行Dex文件时,会通过检查这个字段,来决定是以小尾还是大尾方式来解释dex文件(中的相关变量)。由于ARM与x86芯片都是小尾方式,现有的反汇编引擎都不会考虑这个字段(默认小尾),因此,若我们人为修改这个字段为大尾,并将dex文件中相关数据都反过来,可以对抗当前的各种反汇编引擎。

字符串混淆

因为dex文件的信息都很集中,所以将string_id_item[]中的字符串替换为无意义的字符串,整个文件中相关要用到的地方也同步更新了,可用此来混淆。有时候防守方做得太恶心了(如两个函数名:”oooo0o”与”o0oooo”),可以用比较弱的混淆器对抗下(abc一类的名称比数圈圈好)。

实践方案

以上的实验还只是针对dex的标识符的加固,不涉及代码。实际操作中,可以:

  1. 得到正常的dex
  2. 修改dex中的各表项,使阅读困难
  3. 用baksmali,反汇编成smali语法
  4. 针对smali文件,进行代码混淆
  5. 重新编译smali文件,得到加固后的dex文件

不过,不管怎样混淆,dalvikvm毕竟是开源的,dex文件的强度都比较弱。

发布了36 篇原创文章 · 获赞 55 · 访问量 34万+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章