Android下的DEX文件和SO文件梳理总结

描述

背景    

android逆向分析、脱壳破解分析过程中免不了和android的各种文件格式打交道(so、dex、xml、art、oat等等)。

Android下的两个最重要的文件是DEX文件和SO文件,下面重点对这两个文件及关联文件进行下文的梳理总结,以此用于温故知新。

DEX文件    

DEX它是android虚拟机的可执行字节码文件,我们知道java文件需要经过javac编译成class文件,dx工具会将所有的class文件合并处理最终生成dex文件。

dex文件分为四大部分: DEX文件头,索引结构区,data数据区,静态链接数据区。

在dex文件中所有的代码和数据都放在data数据区中,索引结构区中存放的是data中各种数据的对应的偏移和索引。

ELF文件

ODEX文件    

ODEX它的英文全称为Optimized DEX;即优化过的DEX。

在android5.0之前,Android采用的是JIT(just-in-time)即时编译,也就是程序边执行边编译。为了增加程序执行的效率,android在APK第一次安装的时候将程序的dex文件进行优化生成odex文件,并将其放在了/data/dalvik-cache目录下,等待下次apk运行时直接加载这个目录中经过优化的odex文件(优化基于当前系统的dalvik虚拟机版本,不同版本上的odex文件无法进行兼容),避免重复验证提高执行效率,加快APK的响应时间。

OAT文件    

在android5.0之后,android使用的是AOT(Ahead-of-time)事前编译,也就是程序在运行前先编译。oat是ART虚拟机运行的文件,是ELF格式二进制文件,包含DEX和编译的本地机器指令,oat文件包含DEX文件,因此比ODEX文件占用空间更大。

程序在首次安装的时候,dex2oat默认会把classes.dex翻译成本地机器指令,生成ELF格式的OAT文件,并将其放在了/data/dalvik-cache或者是/data/app/packagename/目录下。ART加载OAT文件后不需要经过处理就可以直接运行,它在编译时就从字节码装换成机器码了,因此运行速度更快。

在android5.0之后oat文件的后缀还是odex,但是已经不是android5.0之前的文件格式,而是ELF格式封装的本地机器码,可以认为oat在dex上加了一层壳,可以从oat里提取出dex。

ELF文件

(elf格式的oat)

因为此时的oat文件是一个标准的elf文件,识别其实其是不是oat文件的标准就是看其符号表。

ELF文件

oatdata指向的是ELF文件的.rodata节区,存放了OAT文件头OATHeader,OAT的DEX文件头,原始DEX文件的DexFile等信息。

oatexec指向的是ELF文件的.text节区,这里存放的是编译生成的指定平台的二进制代码。

oatlastword指向的是对应oat文件的结尾。

OAT文件大小差不多= dex文件+art文件

ELF文件

vdex文件    

android8.0(Android O)之前dex文件嵌入到oat文件本身中,在Android 8.0之后dex2oat将classes.dex优化生成两个文件oat文件(.odex)和vdex文件(.vdex),其中包含APK的未压缩DEX代码,以及一些旨在加快验证速度的元数据。

odex文件中包含了本机代码的OAT

vdex文件包含了原始的DEX文件副本

ELF文件

ART文件    

ART虚拟机在执行dex文件时,需要将dex文件中使用的类,字符串等信息转换为自定义的结构。art文件就是保存APK中使用的一些类,字符串等信息的ART内部表示,可以加快APK程序启动的速度。

ELF文件    

ELF文件格式提供了两种不同的视,在汇编器和链接器看来,ELF文件是由Section Header Table描述的一系列Section的集合,而执行一个ELF文件时,在加载器(Loader)看来它是由Program Header Table描述的一系列Segment的集合。

ELF它是 Executable and Linking Format 的缩写,它是android平台上通用的二进制文件格式。在 Android 的 NDK 开发中,几乎都是和 ELF 打交道。

比如:

1、c / c++ 文件编译得到的 .o(或者 .obj)文件就是 ELF 格式的文件;

2、动态库(.so)文件、可执行文件也是 ELF 文件;

3、动态库的字符串擦除、动态库加壳、动态库修复等都离不开 ELF;

ELF文件名称中的Executable和 Linking表明 ELF 有两种重要的特性。

1、Executable表示可执行的。ELF 文件将参与程序的执行(Execution)过程。包括二进制程序的运行以及动态库 .so 文件的加载。

2、Linking表示可连接的。ELF 文件参与编译链接过程。

ELF文件

ELF文件

ELF文件

文件加载    

Android中Java层通过System.load或System.loadLibrary来加载一个so文件,它的定义在Android源码中的路径

为/libcore/luni/src/main/java/java/lang/System.java,执行流程如下:

加载so的两种方式

1、System.loadLibrary(path),只能加载jniLIbs目录下的so文件,这个的执行流程

    1.1、先读取so文件的.init_array段

    1.2、执行JNI_OnLoad函数

    1.3、JNI_ONLoad是.so文件的初始函数

    1.4、最后调用具体的native方法

2、System.load(path),可以加载任意路径下的so

这两种方式最终都会调用Android底层的dlopen来打开so

ELF文件

dlopen用来打开一个动态链接库,并将其装入内存。它的定义在Android源码中的路径为/bionic/linker/dlfcn.cpp,执行流程如下:

ELF文件

So文件的入口为init_array、init_func这些初始化函数。这部分在dlopen的过程中就会执行,再之后的是JNI_Onload方法的调用。这里面可以注册一些本地方法,也可以继续做些变量的初始化等操作。






审核编辑:刘清

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分