×

Android APK 反编译实践

96
隋胖胖LoveFat
2017.05.22 13:44* 字数 2651

apk是安卓工程打包的最终形式,将apk安装到手机或者模拟器上就可以使用APP。反编译apk则是将该安卓工程的源码、资源文件等内容破解出来进行分析。客户端QA可能会遇到的问题是,本地测试包与正式发布的apk包之间可能存在差异(debug与release)。如果能够进行最终上线前的apk反编译,一方面可以校验apk是否有遗漏的Jar包或者资源文件,另一方面也可以简要核对本版本apk的基本信息是否正确。可加入产品上线前最终上线清单确认的环节中。本文主要介绍了apk反编译的基本原理和主要方法,最后介绍了目前比较成熟的反编译工具。

一、APK反编译基本原理

1.APK分析

apk文件的本质是压缩文件,我们将apk文件修改后缀名为zip或者rar等,可以直接解压缩查看apk文件夹。下图即为一个基本的apk文件夹结构图。


我们简要看下每个文件夹和文件里都有什么内容:

  • assets文件夹:原始资源文件夹,对应着Android工程的assets文件夹,一般用于存放原始的图片、txt、css等资源文件。
  • lib:存放应用需要的引用第三方SDK的so库。比如一些底层实现的图片处理、音视频处理、数据加密的库等。而该文件夹下有时会多一个层级,这是根据不同CPU 型号而划分的,如 ARM,ARM-v7a,x86等。
  • META-INF:保存apk签名信息,保证apk的完整性和安全性。
  • res:资源文件夹,其中的资源文件包括了布局(layout),常量值(values),颜色值(colors),尺寸值(dimens),字符串(strings),自定义样式(styles)等。
  • AndroidManifest.xml文件:全局配置文件,里面包含了版本信息、activity、broadcasts等基本配置。不过这里的是二进制的xml文件,无法直接查看,需要反编译后才能查看。
  • classes.dex文件:这是安卓代码的核心部分,,dex是在Dalvik虚拟机上可以执行的文件。这里有classes.dex和classes2.dex两个文件,说明工程的方法数较多,进行了dex拆分。
  • resources.arsc文件:记录资源文件和资源id的映射关系。

直接查看apk压缩文件,只有assets可以直接查看,我们可以校验其中是否已加入必需的资源文件。但是对于版本的基本情况、所需的JAR包等都是无法直接查看的,需要进行apk反编译处理。了解apk的反编译原理,需要从apk打包原理讲起。

2.从APK打包讲起

使用IDE进行安卓开发,便捷的打包调试使得打包的很多细节都忽略了,安卓官网给出了apk打包的基本流程图,图中红框是我对打包流程几个主要模块的划分:

我们从中梳理出apk打包的基本流程模块如下:

  1. 资源处理
    这一过程中主要使用appt工具进行资源文件的处理,分析AndroidManifest.xml中的资源文件,生成R.java和resources.arsc文件;aidl工具负责处理aidl文件,生成对应的java接口文件。
  2. 代码编译
    将上一过程中产生的R.java、java接口文件以及工程源代码一起通过Java Compiler编译成.class文件,打成Jar包(这部分可以加入代码混淆),然后与第三方库的Jar包一起通过dx工具转换成.dex文件。
    通过apkbuilder工具将aapt生成的resources.arsc、classes.dex(可能多个)、其他的资源一块打包生成未经签名的apk文件。
  3. 添加签名
    通过Jarsigner对生成的未签名的apk进行签名。
    再通过zipalign对签名后的apk进行对其处理,使apk中所有资源文件距离文件起始偏移为4字节的整数倍,从而在通过内存映射访问apk文件时会更快。

3.APK反编译原理

通过回顾apk的打包原理,反编译要做的事情也就明了了。反编译要做的,一是要将apk里的dex文件转换成Jar包,再通过工具查看编译前的java源文件。二是通过工具查看apk里对应的AndroidManifest.xml、resources.arsc、res各布局文件等二进制文件。反编译所需要的工具主要有以下几个:

二、APK反编译实践

1.使用dex2jar将dex文件转换成Jar包

在Mac上下载的dex2jar-2.0.zip包直接解压缩即可,关键需要用到的文件是d2j-dex2jar.sh和d2j-dex2jar_invoke.sh,需要对这两个文件先添加可执行权限。然后将目标apk改为zip后缀,解压缩直接拿到其中的dex文件。在终端输入命令:

./d2j-dex2jar/d2j-dex2jar.sh classes.dex

注意要输入classes.dex的正确路径。
命令结束后会在当前目录下生成classed-dex2jar.jar文件。如下图所示:



ps:如果apk的方法数超过了65535,会生成多个dex文件,反编译的话需要对这多个dex文件均进行转换Jar包处理。

2.使用jd-gui将Jar包文件反编译成java源文件
jd-gui下载解压后,直接打开文件夹里面的JD-GUI,即可打开图形化界面。将我们上一个步骤生成的classes-dex2jar.jar直接拖动进入界面中,就可以看到反编译之后的源码结构了。


ps:这里有时候会看到诸如a.a.a、b等字母标示的包名、类名或者方法名,这是由于在某些apk打包的时候进行代码混淆导致的。使用反编译工具只能看到混淆之后的代码结构,真正未混淆前的源码还需要结合mapping.txt文件进行分析。mapping.txt文件里即标注出了代码混淆前后的文件名称对应关系。

3.使用apktool工具查看apk里的二进制文件
下载下来apktool并解压缩后,调用java命令执行,命令如下:

java -jar apktool.jar d yourApkName.apk

命令执行完后,会在当前目录下新增yourApkName文件夹,其中可以看到可读的AndroidManifest.xml、res目录下的各布局文件、assets文件夹等。



original文件夹是原始的AndroidManifest.xml文件,res文件夹是反编译出来的资源,smali文件夹是反编译出来的代码。注意,smali是有点类似于汇编的语法,是Android虚拟机所使用的寄存器语言。

三、其他APK反编译工具

以上是apk反编译常用的主要工具和方法,现在也有一些工具可以将这些反编译步骤全部集成起来,常用的有:

1.Android-classyshark
下载地址:https://github.com/google/android-classyshark/releases,下载下来之后是一个可执行的jar文件,在终端执行java -jar classyshark.jar即可打开图形化界面。在打开的图形操作界面中拖入待目标apk,即可展示出反编译之后的结果。

点击上方的“Methods count”还能看到各个类中具体的方法数。


2.Android Studio 2.2的APK Analyzer
Android Studio 2.2版本新增了APK Analyzer功能,使用方法很简单,只需要将目标apk拖入到Android Studio 2.2中即可。


功能十分强大,可以直接将APK全部反编译出来,在Android Studio界面上可以直接看到apk版本的信息,直接查看AndroidManifest.xml、R.java等文件。点击classes.dex可以直接查看反编译之后的代码结构。可以说是集合了apktool、dex2jar、jd-gui等反编译工具的全部功能,十分便捷。

上述是比较常见且较为成熟的apk反编译工具,但是稍有遗憾的是,以上工具均只能反编译至混淆后的代码,如何结合mapping.txt恢复成源代码,还没有发现比较好的工具。

四、结语

在日常安卓端产品测试过程中,曾经出现过的问题是本地测试打包与上线打包有差异,原因可能是开发误以为某些jar包和资源文件只是本地测试需要,上线不需要,也可能是本地测试打包与上线打包的build types不同,导致本地测试通过,而上线后出现了异常情况。这类问题测试的难点在于,待上线的apk包对于某些情况无法经过QA实时校验、缺少的jar包和资源文件并不会导致回归测试的功能异常等。为了避免这种问题,对于apk正式上线前的上线清单,可考虑加入待发布apk的反编译资源包确认。QA可仔细核验最终待发布的apk,可以通过反编译的手段进一步对apk进行分析,查看是否新增的jar包和资源文件、so文件等均没有遗漏,回归测试功能点也没有异常,才能正式上线。

总之,产品发布是一件需谨慎对待的事情,增加对待上线apk的反编译分析,一定程度上可以对产品质量做最后一道把关。

安卓测试的那些事儿
Web note ad 1