首先,我们可以看到一张说明从apk到java的过程的图片(图1)。为了达到反编译apk的最终目的,我们可以使用apktool、dex2jar、enjarify、jd-core( jd-gui )、cfr、procyon等工具。实际上,Apk可以看作是一个zip文件,其中的**DEX**是根据android系统中Dalvik或ART虚拟机优化后的Java字节码。在获取Java源代码之前,我们需要将DEX转换成等价的JAR。值得一提的是,我们可以认为Jar文件是封装一系列Java classes的包。最后,我们可以使用java反编译器:cfr、jd-core和procyon,三者中的任何一个都可以将JAR反编译成非常接近源项目的java文件。
由于反编译可能会出现错误,我们可以让三种java反编译器分别进行工作,结合三者的反编译结果来降低错误率。
最后,不论如何**我们也不能将APK文件完全恢复成java的源代码**,还需要用我们的智慧手动地调整代码的细节,才能够完全恢复成原来项目的模样。更不要提,我们可能还会遇到混淆或者加固后的代码,这更加会增加我们恢复源码的难度。换句话说,这也是开发一个实用的反编译器的核心点和难点。
:-: ![apk2java][1]
:-: 图1.从Apk到java文件的流程图
图2显示了Jar文件和Apk文件之间的区别。类文件本质上与dex文件相同,都是字节流的代码文件。换句话说,dex源自class文件,因为DVM或ART-VM是基于JVM开发的。我们可以使用JDK工具中的javap来反编译类文件,同样地,我们可以使用apktool来反编译dex文件。
:-: ![jar-apk-compare][2]
:-: 图2.Jar文件和Apk文件的对比图
## 1 从apk中获取资源文件和smali代码
### apktool
https://ibotpeaches.github.io/Apktool/
一个用于逆向工程的第三方工具,可以用来逆向封闭的、二进制的Android应用程序。它可以将资源解码成几乎原始的形式,并在进行一些修改后重新构建它们。它还让应用程序使用起来变得更容易,因为APK项目本质上就是一个文件结构,我们可以将一些重复性的任务自动化,如构建apk等。
java -jar apktool.jar d yourapp.apk
## 2 从apk/dex中获取jar文件
### 2.1 dex2jar
https://github.com/pxb1988/dex2jar
使用dex2jar 处理`.dex` 和java `.class`文件
./d2j-dex2jar.sh <your-classes.dex> -o <out-jar-file>
### 2.2 enjarify
https://github.com/google/enjarify
### 简介
Enjarify是一个工具,用于将Dalvik字节码转换为等价的Java字节码。这允许Java分析工具分析Android应用程序。
### 为什么不用dex2jar?
Dex2jar是一个较老的工具,它尝试将Dalvik转换为Java字节码。在大多数情况下,它都运行得很好,但是很多模糊的特性或边缘情况会导致它失败,甚至无声地产生不正确的结果。相比之下,Enjarify被设计用于尽可能多的情况,即使对于Dex2jar可能失败的代码也是如此。在其他方面,Enjarify能正确地处理unicode类名、多种类型的常量,进行隐式的强制转换,能将异常处理程序跳转到正常控制流,能处理引用太多常量的类,解析非常长的方法,甚至在应对catchall处理程序之后的异常以及错误类型的静态初始值时,都能够正常工作。
### 使用Python 3来运行它
Enjarify是一个纯**python 3**应用程序,所以你可以直接运行它,你需要在命令行中进入到项目的根目录中,然后运行:
python3 -O -m enjarify.main yourapp.apk
一般情况下,你可能希望使用脚本并将其配置在你的环境变量中。
为了方便起见,我们提供了一个编写好的shell脚本`enjarify.sh`。如果可以的话,你可以尝试使用Pypy,因为它比CPython更快。如果希望能够在任何位置调用Enjarify,可以在路径上的某个位置(比如~/bin)创建符号链接。为此,假设你位于项目的根目录,
ln -s "$PWD/enjarify.sh" ~/bin/enjarify
### 在Windows操作系统中
我们提供了一个批处理脚本文件`enjarify.bat`。要从任何地方调用它,只需将该文件所处的目录(也就是enjarify项目的根目录)添加至系统的环境变量即可。批处理脚本将始终调用python3作为解释器。如果您想使用pypy,请编辑该脚本文件。
### 使用方法
假设你正确地设置了路径上的脚本,您可以通过键入enjarify从任何地方调用它。
enjarify yourapp.apk
最基本的使用方法是指定apk文件或dex文件作为输入。如果apk中多个dex文件, Enjarify将自动转换所有dex文件,并将结果输出整合到一个jar中。如果指定一个dex文件,则只转换该dex文件。例如,假设您可以手动提取dex文件:
enjarify classes2.dex
当前目录中的默认输出文件是`[inputname]-enjarify.jar`。如果要要指定输出的文件名,请使用`-o`或`--output`选项。
enjarify yourapp.apk -o yourapp.jar
默认情况下,如果输出文件已经存在,Enjarify将不会覆盖它。若要覆盖输出,请传递`-f`或`--force`选项。
## 3 从Jar中获取java代码
### 3.1 jd-core
https://github.com/nviennot/jd-core-java
JD-Core是jd-gui使用的java反编译器,但是它常常被忽视,人们往往会使用jd-gui,却不知道它的反编译引擎是什么。jd-core是开源的,我们可以用它快速完成反编译工作。
JD-Core-Java是Java反编译器的一个小部件。
这是通过破解IntelliJ IDE插件而获得的。我们通过伪造IDE的接口,来提供对JD-Core的访问。
java -jar jd-core.jar <compiled.jar> <out-dir>
### 3.2 cfr
http://www.benf.org/other/cfr/
CFR将对现代Java特性进行反编译——包括大部分Java 9、10和更高版本,但完全是用Java 6编写的,所以可以在任何地方使用——它甚至可以很好地将其他JVM语言的class文件转换回java。
java -jar cfr.jar <compiled.jar> --outputdir <dir>
### 3.3 procyon
![procyon][3]
https://bitbucket.org/mstrobel/procyon/wiki/Java%20Decompiler
Procyon是一套专注于代码生成和分析的Java元编程工具。它包括下列的库:
1. 核心框架
2. 反射框架
3. 表达式框架
4. 编译器工具箱(实验功能)
5. Java反编译器
procyon反编译器是Java反编译器的独立前端,是procyon编译器工具的一部分。
procyon的作者说:
>作为一名在.NET平台和Java平台之间来回奔波的开发人员,我对Java生态系统中能够选择的反编译器感到惊讶和沮丧。Jad(不再维护,封闭源代码)和JD-GUI (GPL3)是相当不错的选择,但是前者不支持Java 5+语言特性,而后者并不兼容我的LINQ/DLR树编译器。
>为了解决这个问题,我最近开始自己开发一个反编译器,灵感来自(并大量借鉴)*ILSpy*和*Mono.Cecil*
java -jar procyon.jar <compiled.jar> -o <dir>
## 4 其他
### 4.1 Jeb (Android java反编译工具,提供可视化的窗口)
https://www.pnfsoftware.com/
为专业人员提供的逆向工程的工具,能够反编译和调试二进制代码,破解和分析文档文件。
Dalvik, MIPS, ARM, Intel, WebAssembly & Ethereum反编译器。
![jeb-gui][4]
当你第一次打开JEB时,可能会提示你没有安装相应的库,你可以使用`sudo apt-get install`命令来修复它。
# sudo apt-get install libcarberra-gtk-module
### 4.2 IDA_Pro (C/.so 反汇编器)
https://www.hex-rays.com/
IDA是一款交互式的反汇编软件:世界上最聪明、功能最全面的反汇编软件,许多软件安全专家都熟悉它。
IDA完全用C++编写,可运行在三大操作系统上:Microsoft Windows、Mac OS X和Linux。
IDA也是我们的第二个产品Hex-Rays反编译器的坚实基础。
独特的Hex-Rays反编译器提供了二进制可执行程序的高级表示。它可以处理真实世界的代码。它是真的。
![ida-gui][5]
当你第一次运行IDA时,可能会提示你有一些`missing libraries`,你可以运行下面的命令来安装丢失的库。在Linux系统上,IDA只支持32位(我的操作系统是Ubuntu x64),所以我们需要安装相应的32位的库才行。
```
$ sudo apt-get install multiarch-support
###安装x86的支持库
###libgthread-2.0.so.0
###libfreetype.so.6
###libSM.so.6
###libXrender.so.1
###libfontconfig.so.1
###libXext.so.6
$ sudo apt-get install libc6:i386 libncurses5:i386 libstdc++6:i386 libglib2.0-0:i386 libfreetype6:i386 libsm6:i386 libxrender1:i386 libfontconfig1:i386 libxext6:i386
```
[1]: https://blog-1252789527.cos.ap-shanghai.myqcloud.com/article/Android%20decompiled%20process%20and%20tools/apk2java.png
[2]: https://blog-1252789527.cos.ap-shanghai.myqcloud.com/article/Android%20decompiled%20process%20and%20tools/jar-apk-compare.png
[3]: https://blog-1252789527.cos.ap-shanghai.myqcloud.com/article/Android%20decompiled%20process%20and%20tools/procyon.png
[4]: https://blog-1252789527.cos.ap-shanghai.myqcloud.com/article/Android%20decompiled%20process%20and%20tools/jeb-gui.png
[5]: https://blog-1252789527.cos.ap-shanghai.myqcloud.com/article/Android%20decompiled%20process%20and%20tools/ida-gui.png