android study 4
1.文件结构
1.1 ELF文件结构
1.1.1 ELF文件结构概述
ELF文件由三部分组成,ELF文件头(位置固定,大小固定),段头表,节头表。
ELF整体结构如下:
1 | ELF Header -> ELF 文件头的位置是固定的 |
Program Header Table中存储了segment的描述信息,segment是站在系统的角度对section的一种组织方式,对于操作系统而言,数据属性通常是读,写,执行,符合同一数据属性的 section 理论上就可以放到一起以节省加载时的内存,所以一个segment 中可以包含连续的多个 section。
而 section header 和 program header 都是对于 elf 文件中 sections 的描述,只是采用了不同的方式,elf 文件中的 sections 按照 segment 的组成形式进行排列,这样就不需要为每个 segment 重新生成一份针对 segment 的 sections 的组合.
1.2.2 链接视图与执行视图
静态链接器会以链接视图解析ELF文件,编译时生成的.o文件以及链接后的.so文件均可通过链接视图进行解析,链接视图是没有段表的,如.o文件不会有段表。执行视图则是在程序被装载运行时用到的视图。链接视图以section为单位,执行视图以segment为单位。
1.2.3 ELF文件头
ELF文件头记录了ELF文件类型,结构,版本,程序入口地址等信息,并提供了节头表,程序头表在文件中的偏移位置。ELF文件头具体结构如下:
1 | typedef struct { |
1.2.4 程序头表
程序头表会记录ELF文件中所有段的信息,包括段的类型,段的偏移地址,段的虚拟地址,物理地址等信息。段类型则可以分为PT_LOAD(描述可装载的段,如代码段,数据段,这些可被装载进内存中),PT_DYNAMIC(动态链接文件特有,包含了动态链接文件所需要的信息) ,PT_NOTE(保存了与特定供应商或者系统相关的附加信息),PT_INTERP,PT_PHDR(程序头表本身位置和大小)
1.2.5 节头部表
节头表用于描述ELF文件各节区的位置和大小,主要用于链接与调试,节头对于程序的运行来说不是必须的。
1.2 Dex文件结构
1.2.1 Dex文件头
dex文件头一般固定为0x70个字节大小,包含标志、版本号、校验码、sha-1 签名以及其他一些方法、类的数量和偏移地址等信息。如下图所示。
1.2.2 字符串解析
在文件头0x38和0x3c存储了字符串信息,分别是字符串数量以及字符串索引区的偏移地址。在字符串索引区,四字节一组表示一个字符串在数据区的偏移地址。偏移地址里采用了MUTF-8编码,第一个字节表示字符串长度,最后一个字节00表示字符串结束
1.2.3 类的类型解析
类的偏移地址里存储了该类名在字符串数组中的索引值,4字节一组。
1.2.4 方法原型的解析
Dex中的方法原型定义了一个方法的返回值类型和参数类型,例如一个方法返回值为void,参数类型为int,则方法原型表示为V(I)。一共12个字节,前四个字节是用到的字符串索引,后八个字节是返回值,参数用到的类的索引。
1.2.5 字段解析
在偏移地址处有8个字节,前两个字节是之前解析出类的索引,表示这个字段在该类中定义。3-4字节也是类的索引,表示该字段类型。最后四个字节是字符串列表的索引,用来表示字段名。
1.2.6 方法定义解析
在偏移地址处有8个字节,前两个字节是类解析的索引,用来表示该方法属于哪个类。3-4字节是方法原型的索引,最后四个字节是字符串索引用来表示方法名。
1.2.7 类的解析
class_def_item有32个字节,1-4字节是之前类类型解析的索引,也就是类名。5-8字节是access_flags,是该类的访问标志,表明这个类是public还是private。9-12字节是父类类型解析的索引,也就是父类名。13-16字节是接口信息的偏移地址。17-20字节是字符串索引,表明该类所在的java文件名。21-24字节是注释信息的偏移地址,25-28字节指向class_data_off,是类数据第二层结构的偏移地址,该结构中记录了该类的方法和字段。29-32字节在没有相关信息情况下为0,如果有信息会指向一个结构的偏移地址。
类的第二次层结构:class_data_item
class_data_item中第一个uleb128编码,指明了该类中静态字段的数量。第二个uleb128编码,指明了该类中实例字段的数量。第三个uleb128编码指明了该类中直接方法的个数。第四个uleb128编码指明了该类中虚方法的个数。然后如果各字段/方法数量>0,又会有指明相应字段/方法详细信息的结构。这里具体以方法信息为例,里面有3个uleb128编码,第一个是方法原型的索引,第二个是访问标志,第三个则是方法具体字节码的偏移地址。对应结构体是code_item,里面记录了smali代码。
类的第三层结构: code_item
code_item中会记录该方法使用的寄存器数量,参数个数,try-catch数量,调试信息结构体偏移,指令列表等信息。指令列表里面就是一些opcode。
到这里,其实就可以根据以上信息对dex进行一个反编译为smali指令的工作了。