安卓逆向笔记

2017/2/28 网络安全互联网安全安卓逆向游戏安全

安卓如何逆向?

# 一、系统开发环境及工具

  • Window : Eclipse+ADT/Android Studio、 JDK1.7

  • Android测试工具:

    • APKTools - 进行反编译之后的classes.dex文件都被转换成了smali文件;
    • Dex2jar - 用来将dex文件转换成jar文件;
    • jd-gui - (很多时候可读性差)可以打开jar文件,查看java源码,直接打开jd-gui,使用内置的打开功能或者拖拽将jar包放入jd-gui中即可查看。
    • IDApro - 反编译神器,主要是分析so,lua,dll此类文件;
    • jadx - 可以直接反编译apk;
    • ClassyShark -可以直接反编译apk,更容易看APK的整个结构;
  • Drozer等

  • Web漏洞测试工具:Wireshark、Burpsuite、sqlmap等

# 二、Dalvik虚拟机简介

Dalvik是Google公司自己设计用于Android平台的虚拟机。Dalvik虚拟机是Google等厂商合作开发的Android移动设备平台的核心组成部分之一。它可以支持已转换为 .dex格式的Java应用程序的运行,.dex格式是专为Dalvik设计的一种压缩格式,适合内存和处理器速度有限的系统。

  1. Dalvik主要是完成对象生命周期管理,堆栈管理,线程管理,安全和异常管理,以及垃圾回收等等重要功能。
  2. Dalvik负责进程隔离和线程管理,每一个Android应用在底层都会对应一个独立的Dalvik虚拟机实例,其代码在虚拟机的解释下得以执行。
  3. 不同于Java虚拟机运行java字节码,Dalvik虚拟机运行的是其专有的文件格式dex
  4. dex文件格式可以减少整体文件尺寸,提高I/o操作的类查找速度。
  5. odex是为了在运行过程中进一步提高性能,对dex文件的进一步优化。
  6. 所有的Android应用的线程都对应一个Linux线程,虚拟机因而可以更多的依赖操作系统的线程调度和管理机制
  7. 有一个特殊的虚拟机进程Zygote,他是虚拟机实例的孵化器。它在系统启动的时候就会产生,它会完成虚拟机的初始化,库的加载,预制类库和初始化的操作。如果系统需要一个新的虚拟机实例,它会迅速复制自身,以最快的数据提供给系统。对于一些只读的系统库,所有虚拟机实例都和Zygote共享一块内存区域。

# 三、ART模式简介

ART(Android runtime)的机制与 Dalvik 不同。在Dalvik下,应用每次运行的时候,字节码都需要通过即时编译器转换为机器码,这会拖慢应用的运行效率,而在ART 环境中,应用在第一次安装的时候,字节码就会预先编译成机器码,使其成为真正的本地应用。这个过程叫做预编译(AOT,Ahead-Of-Time)。这样的话,应用的启动(首次)和执行都会变得更加快速。

ART优点:

  1. 系统性能的显著提升。
  2. 应用启动更快、运行更快、体验更流畅、触感反馈更及时。
  3. 更长的电池续航能力。
  4. 支持更低的硬件。 ART缺点:
  5. 机器码占用的存储空间更大,字节码变为机器码之后,可能会增加10%-20%(不过在应用包中,可执行的代码常常只是一部分。比如最新的 Google+ APK 是 28.3 MB,但是代码只有 6.9 MB。)
  6. 应用的安装时间会变长。

tips:现在智能手机大部分都可以让用户选择使用Dalvik还是ART模式。当然默认还是使用Dalvik模式。,现在旗舰机手机都默认ART了。 用法:设置-辅助功能-开发者选项(开发人员工具)-选择运行环境(不同的手机设置的步骤可能不一样)。

# 四、APK文件结构

APK是以ZIP打包的压缩包,

  • AndroidManifest.xml - Andorid工程基础属性文件;
  • apktool.yml - 重新打包必须文件;
  • assets - 资源,assets目录下的资源文件不需要生成索引文件,Java代码中使用AssetsManager来访问;通常音频和视频会放在Raw和Assets下,其他文件一般会放在res文件夹下;游戏引擎的资源文件都放在Assets文件夹下(索引的速度需要比较高的要求);
  • res - 资源库,res目录下的资源文件在编译的时候会自动生成索引文件(R.java),在Java代码中使用R.XX.XXX来引用;
  • lib - native动态库 so(ELF)文件存放的位置。一般由NDK编译得到,常见于使用游戏引擎或JNI native调用的工程中,so库文件分为不同的CPU架构;
  • smali - classes.dex,是Java代码编译得到Dalvik VM能直接执行的文件。
  • META-INF - 签名,存放属性文件;
  • resources.arsc - 对res目录下的资源的索引文件,保存原工程strings.xml等文件内容;

# 五、Class文件

Class文件到底是什么东西?我觉得一种通俗易懂的解释就是:

  • .java文件是人编写的,给人看的。
  • .class是通过工具处理*.java文件后的产物,它是给VM看的,给VM操作的 在某种哲学意义上看,java源文件和处理得到的class文件是同一种东西......

那么,这个给VM使用的class文件,其内部结构是怎样的呢?Jvm规范很聪明,它通过一个C的数据结构表达了class文件结构。这个数据结构如图2所示:

请大家务必驻足停留片刻,因为搞清楚图2的内容对后续的学习非常关键。图2的ClassFile这个数据结构真得是太容易理解了。相比那些native的二进制程序而言,ClassFile的组织结构和Java源码的组织结构匹配度非常高,以致于我第一眼看到这个结构体时,我觉得自己差不多就理解了它:

比如,类的是public的还是final的,还是interface,就由access_flags来表示。其具体取值我觉得都不用管,代码中用得是名字诸如ACC_XXX这样得的标志位来表示,一看知道是啥玩意儿。 Java类中定义的域(成员变量),方法等都有对应的数据结构来表达,而且还是个数组。 唯一有点特别之处的是常量池。什么东西会放在常量池呢?最容易想到的就是字符串了。对头,这个Java源码中的类名,方法名,变量名,居然都是以字符串形式存储在常量池中。所以,图2中的this_class和super_class分别指向两个字符串,代表本类的名字和基类的名字。这两个字符串存储在常量池中,所以this_class和super_class的类型都是u2(索引,代表长度为2个字节)。 Class文件用javap工具可以很好得解析成图2那样的格式,我这里替大家解析了一把,结果如图3所示(先显示部分内容):

注意,解析方法为:javap -verbose xxxx.class

# 六、dex文件

Android平台中没有直接使用Class文件格式,因为早期的Anrdroid手机内存,存储都比较小,而Class文件显然有很多可以优化的地方,比如每个Class文件都有一个常量池,里边存储了一些字符串。一串内容完全相同的字符串很有可能在不同的Class文件的常量池中存在,这就是一个可以优化的地方。当然,Dex文件结构和Class文件结构差异的地方还很多,但是从携带的信息上来看,Dex和Class文件是一致的。所以,你了解了Class文件(作为Java VM官方Spec的标准),Dex文件结构只不过是一个变种罢了(从学习到什么程度为止的问题来看,如果不是要自己来解析Dex文件,或者反编译/修改dex文件,我觉得大致了解下Dex文件结构的情况就可以了)。图8所示为Dex文件结构的概貌:

有一点需要说明:传统Class文件是一个Java源码文件会生成一个.Class文件,而Android是把所有Class文件进行合并,优化,然后生成一个最终的class.dex,如此,多个Class文件里如果有重复的字符串,当把它们都放到一个dex文件的时候,只要一份就可以了嘛。

dex头部信息中的magic取值为“dex\n035\0”

proto_ids:描述函数原型信息,包括返回值,参数信息。比如“test:()V”

methods_ids:函数信息,包括所属类及对应的proto信息。比如

"Lcom.test.TestMain. test:()V",.前面是类信息,后面属于proto信息

下面我们将示例TestMain.class转换成dex文件,然后再用dexdump工具看看它的结果,如图9所示:

具体方法:

先将.class文件转换成dex文件,工具是sdk build-tools下的dx命令。dx --dex --debug --verbose-dump --output=test.dex com/test/TestMain.class,生成test.dex文件。 同样,利用build-tools下的dexdump命令查看,dexdump -d -l plain test.dex,得到图9的结果 图9中的dexdump结果其实比图3还要清晰易懂。我们重点关注code段的内容(图中红框的部分):

registers:Dalvik最初目标是运行在以ARM做CPU的机器上的,ARM芯片的一个主要特点是寄存器多。寄存器多的话有好处,就是可以把操作数放在寄存器里,而不是像传统VM一样放在栈中。自然,操作寄存器是比操作内存(栈嘛,其实就是一块内存区域)快。registers变量表示该方法运行过程中会使用多少个寄存器。 ins:输入参数对应的个数,outs:此函数内部调用其他函数,需要的参数个数。 insns:size:以4字节为单位,代表该函数字节码的长度(类似Class文件的code[]数组) Android官方文档:https://source.android.com/devices/tech/dalvik/dex-format.html

# 六、什么是Smail?破解的重点

Smail相比Dex文件更接近于机器语言。常规的我们使用apktool进行反编译之后的classes.dex文件都被转换成了smali文件。最好是直接能看懂Smail文件是最方便的。

Last Updated: 2022/1/8 04:00:18