最近由于机缘巧合接触到了 Android 逆向相关的事情,经过一番探索,对其有了更深刻地认识,过程中遇到了了一些坑,或者一些有用的经验,分享并记录分析一下。在整个过程中使用的工具有:

反编译:dex2jar、CFR、jd-gui、

脱壳:VirtualApp、Xposed installer、FDex2

其他:IDA、VSCode、Total commander

接下来咱们以两个具体情景,讲解整个逆向(静态代码分析)的流程,去分析两个 Apk 中相关页面的加密算法。

在开发安卓应用的过程中,我们平时写得最多的代码就是 Java(以及Kotlin),我们的逻辑也都在这一块,如果我们需要对应 apk 中代码逻辑,能直接看到这样的代码当然是最好不过的。要对相关 apk 中的代码逻辑进行分析,那么第一步便是需要对 apk 进行反编译,从而得到可以进行阅读理解的代码。

Apk的打包流程

我们先对 安卓的打包流程进行一个简单的了解,从而明白.java文件 是一步步成为 apk中的一部分的,在生成 apk 的过程中主要包含以下流程,括号中代表使用的工具:

1、打包资源文件,生成R.java文件 (aapt)

2、处理aidl文件,生成相应的.java文件 (aidl)

3、编译项目源代码,生成class文件 (javac)

4、转换所有的class文件,生成classes.dex文件 (dx)

5、编译过的资源和.dex文件都会被apkbuilder工具打包到最终的.apk文件中。 (apkbuilder)

6、对APK文件进行签名 (jarsigner)

7、对签名后的APK文件进行对齐处理 (zipalign)

主要流程参考这两张图:
https://developer.android.com/images/tools/studio/build-process_2x.png

反编译流程

在 apk的打包流程的步骤为:*(资源/aidl等)-> .java->.calss->.dex->.apk,反编译只需要对每个步骤反向进行。

.apk->.dex

安卓安装包本质上是一个压缩文件,只需要对齐进行解压即可(Mac默认解压apk是)
解压获得以下文件:

1
2
3
4
5
6
7
8
9
10
├── AndroidManifest.xml
├── META-INF
├── assets
├── classes.dex
├── classes2.dex
├── lib
├── okhttp3
├── org
├── r
└── resources.arsc

从目录结构得到两个.dex文件,这是由于在单个dex文件引用的方法总数不能超过65536(为什么?因为dex文件中的方法个数采用原生类型short来索引,而short是4个字节,4个字节最大数据存储量是65536),多数 app 超过了这一限制。

.dex->.class

这里我们需要利用工具 dex2jar

d2j-dex2jar: Convert .dex file to .class files (zipped as jar)

执行:

1
sh /XXX/dex2jar-2.0/d2j-dex2jar.sh classes.dex 

生成 classes-dex2jar.jar, 这个 jar 就是从classes.dex反编译出来的 .class集合。得到了这份 .jar我们已经可以开始使用 jd-gui进行查看了,这里吐槽一下jd-gui的搜索功能,搜索功能有限,纯字符串搜索是有问题的(或许是我版本不对),可以在 File/Save all sources 将所有反编译好的文件进行保存,然后利用其他工具(例如VsCode)进行搜索。

再看上面的代码,有一部分是 字节码,工具未能将它正常反编译,为什么呢?相关解释在
https://www.zhihu.com/question/50140866

这里推荐使用 CFR,执行:

1
java -jar /xxx/cfr-0.151.jar /xxx/classes-dex2jar.jar --outputdir /xxx/java

CFR对于 jd-gui 有更好的支持,那还要 jd-gui 干什么呢?在我看来 jd-gui 有一个最大的好处就是能像IDE那样可以点进进入方法内部,所以推荐两则结合起来使用。

.so 反编译

在追溯逻辑的过程中,可能会遇到有 native 方法,如下:

1
public native int dataFromNative(byte[] param, int paramInt1, int paramInt2);

相关逻辑写在 c/c++文件中,最终把打在.so库中,这时候就需要宇宙第一反汇编分析工具 IDA了,我们在 apk 解压后的 lib 中找到对应的 .so 文件(这里可能需要一点耐心,lib中大多是第三方的,可以很好通过 so 文件名找到开发者的 so文件),利用 IDA F5 插件查看 汇编代码的伪代码。以字节某 SDK中的某段代码为例:

可以看到对应的逻辑,这时候就考验水平的时候了……
当然,IDA 是一个强大的工具,关于IDA的使用绝对不是通过查看一两篇博文就能熟练使用的,可以去查看
《IDA Pro权威指南》

总结

1、当然上述流程只针对”正常App”,但在实际的 App 不会这样轻易的被反编译,App 可能还进行了加固,那我需要对其进行脱壳才能实现正确的反编译,这一内容放在另一章节再进行讲解。
2、反编译整个流程,如果没有加固,一般操作是:解压->class2jar 进行转jar->CFR/jx-gui 反编译class,如果对逆向还有更多的操作还可以使用 apk_tool。相关流程已经在github 有开源的脚本了TTDeDroid,有兴趣的同学可以去看看,但是我感觉有些复杂,我自己也写了一个脚本apk2dex2jar2class2java.sh