在使用逆向工具(比如 jdax 等)反编译某些系统 App 的时候,会发现其代码其实是不全的,其实是因为系统应用的 APK 已经经过 odex
和 vdex
化,导致代码分离。
比如在之前的文章(Android 拆包,提取 APK 或 Framework 文件)中,拆了 MIUI 的 Rom,其中小米系统界面(MiuiSystemUI
)拆开后大致是这样的:
1 | tree -s priv-app/MiuiSystemUI/ |
解压 MiuiSystemUI.apk
之后:
1 | AndroidManifest.xml assets/ META-INF/ res/ resources.arsc |
可以看到 Apk 压缩文件中未包含 .dex
文件,而 priv-app/MiuiSystemUI/oat/arm64/
路径下存在 .odex
和 .vdex
的文件,我们要方便的查看其代码,就需要进行反编译(deodex
)。
odex 和 vdex 是什么?
我们可以看 Google 官方文档中的 ART 的运作方式
在 Android 7.0 之后,Android 修改了其 ART 虚拟机的运行模式。在普通用户App安装过程中,不会触发 AOT
编译。在应用最初几次运行,系统会根据 App 经常使用的方法进行 JIT 编译(Just in time - 实时编译 - 解释执行) 。在系统空闲时,会把之前几次运行过程中经常使用的方法代码进行 AOT 编译(Ahead of time - 提前预编译为机器码 - 直接执行)。后续的 App 运行则是 JIT 和 AOT 的混合模式。
在 Android O 版本中在 App 编译过程中,会生成以下文件:
.vdex
:其中包含 APK 的未压缩 DEX 代码,另外还有一些旨在加快验证速度的元数据。.odex
:其中包含 APK 中已经过 AOT 编译的方法代码。.art
(可选的):其中包含 APK 中列出的某些字符串和类的 ART 内部表示,用于加快应用启动速度。
其中 .vdex
+ .odex
就是完整的 Apk class 代码了 (不包括资源文件等)。
反编译 vdex
准备工作
反编译 vdex
需要依赖工具 vdexExtractor
- 系统: Windows 10
- 依赖: 需要下载 cygwin (
cygwin
可以在 Windows 上运行原生的 Linux 命令,可以提供一定程度上的 Linux 环境) 并安装zlib-level
和zip/uzip
库。 - 编译:
- clone 仓库 vdex extractor
- 安装 Android NDK
./make.sh
进行编译
最终正确编译之后会在 bin/
目录下生成可执行文件 (比如 vdexExtractor.exe
)
vdexExtractor
在反编译 Android 9.0 P 中的 vdex
时,会生成 cdex
(CompatDex) 文件而不是 dex
文件, cdex
只能在 GNU/Linux 系统 或者 MacOS 系统中才能转换为 dex
。即 Windows 系统中,没办法反编译 Android P 中的 vdex
。
反编译系统App中的vdex
这里以前面提到的 MiuiSystemUI
这个系统 App 为例。当前目录结构如下:
1 | drwxrwx---+ 1 Tianma None 0 6月 11 18:21 priv-app |
其中的 MiuiSystemUI
就在 priv-app/MiuiSystemUI/
路径下。
复制
MiuiSystemUI.apk
到当前路径下:1
cp priv-app/MiuiSystemUI/MiuiSystemUI.apk MiuiSystemUI.apk
使用
vdexExtractor
将MiuiSystemUI
中的vdex
反编译成dex
,并生成在当前路径下:1
./vdexExtractor.exe -i priv-app/MiuiSystemUI/oat/[arch]/MiuiSystemUI.vdex -o ./ --ignore-crc-error
其中
[arch]
代表 CPU 架构(比如arm
arm64
等),后面不再赘述。成功之后当前路径如下:1
2
3
4
5drwxrwx---+ 1 Tianma None 0 6月 11 18:21 framework
-rwxrwx---+ 1 Tianma None 17525476 6月 17 18:49 MiuiSystemUI.apk
-rw-r--r--+ 1 Tianma None 6229928 6月 17 18:54 MiuiSystemUI_classes.dex
drwxrwx---+ 1 Tianma None 0 6月 11 18:21 priv-app
-rwxrwx---+ 1 Tianma None 458972 6月 17 20:16 vdexExtractor.exe多了一个
MiuiSystemUI_classes.dex
。这个时候就已经可以使用jadx
等工具查看其代码了。将生成的
.dex
打包到.apk
中:1
2mv MiuiSystemUI_classes.dex classes.dex
zip MiuiSystemUI.apk classes*.dex需要注意的是,如果步骤 2 中反编译出来的
dex
文件是多个(>= 2)的话,需要按照classes1.dex
,classes2.dex
等方式重命名之后,再将所有的.dex
打包进.apk
中
反编译 framework 下的 vdex
这里以 services.jar
为例,其中 services.jar
包含各种系统服务(AMS PMS 等等),是很值得对其进行研究的 jar 包。由于反编译 framework
下的 jar
包 framework
相关环境(主要是用作 ClassLoader 的路径),所以需要的目录结构如下:
1 | drwxrwx---+ 1 Tianma None 0 6月 11 18:21 framework |
复制
services.jar
到当前目录下:1
cp framework/services.jar services.jar
使用
vdexExtractor
将/framework/oat/[arch]/services.vdex
反编译成dex
,并生成在当前目录下:1
./vdexExtractor.exe -i framework/oat/[arch]/services.vdex -o ./ --ignore-crc-error
会在当前路径生成
services_classes.dex
文件:1
2
3
4drwxrwx---+ 1 Tianma None 0 6月 11 18:21 framework
-rwxrwx---+ 1 Tianma None 318 6月 17 19:58 services.jar
-rw-r--r--+ 1 Tianma None 9455876 6月 17 20:01 services_classes.dex
-rwxrwx---+ 1 Tianma None 458972 6月 11 20:16 vdexExtractor.exe此时就已经可以使用
jadx
等工具查看其代码了。将生成的
.dex
打包到.jar
中去:1
2mv services_classes.dex classes.dex
zip services.jar classes*.dex最终生成的
services.jar
会包含.dex
。
反编译 odex
准备工作
这里下载的是 2.2.7
版本。
反编译系统App中的odex
仍然以 MiuiSystemUI
这个系统 App 为例,需要 framework
环境,故当前目录结构如下:
1 | -rwxrwx---+ 1 Tianma None 1367549 6月 11 11:48 baksmali-2.2.7.jar |
复制
MiuiSystemUI.apk
到当前目录:1
cp priv-app/MiuiSystemUI/MiuiSystemUI.apk MiuiSystemUI.apk
使用
baksmali
将odex
反编译成.smali
文件,再用smali
将.smali
转换成dex
:1
2java -jar baksmali-2.2.7.jar x priv-app/MiuiSystemUI/oat/[arch]/MiuiSystemUI.odex -d framework/[arch]/ -d framework/ -o MiuiSystemUI
java -jar smali-2.2.7.jar a MiuiSystemUI -o classes.dex最终会在当前路径下生成
classes.dex
:1
2
3
4
5
6
7-rwxrwx---+ 1 Tianma None 1367549 6月 11 11:48 baksmali-2.2.7.jar
-rwxrwx---+ 1 Tianma None 6234640 6月 17 20:57 classes.dex
drwxrwx---+ 1 Tianma None 0 6月 11 18:21 framework
drwxrwx---+ 1 Tianma None 0 6月 17 20:56 MiuiSystemUI
-rwxrwx---+ 1 Tianma None 17525476 6月 17 20:55 MiuiSystemUI.apk
drwxrwx---+ 1 Tianma None 0 6月 17 20:50 priv-app
-rwxrwx---+ 1 Tianma None 1120101 6月 11 11:48 smali-2.2.7.jar将
.dex
打包进.apk
中:1
zip MiuiSystemUI.apk classes*.dex
最终
.apk
会包含.dex
反编译 framework 下的 odex
仍然以 services.jar
为例,当前目录结构:
1 | -rwxrwx---+ 1 Tianma None 1367549 6月 11 11:48 baksmali-2.2.7.jar |
复制
services.jar
到当前目录:1
cp framework/services.jar services.jar
使用
baksmali
将odex
反编译成.smali
文件,再用smali
将.smali
转换成dex
:1
2java -jar baksmali-2.2.7.jar x framework/oat/[arch]/services.odex -d framework/[arch]/ -d framework/ -o services
java -jar smali-2.2.7.jar a services -o classes.dex最终会在当前路径下生成
classes.dex
:1
2
3
4
5
6-rwxrwx---+ 1 Tianma None 1367549 6月 11 11:48 baksmali-2.2.7.jar
-rwxrwx---+ 1 Tianma None 9447036 6月 17 20:44 classes.dex
drwxrwx---+ 1 Tianma None 0 6月 11 18:21 framework
drwxrwx---+ 1 Tianma None 0 6月 17 20:42 services
-rwxrwx---+ 1 Tianma None 318 6月 17 20:38 services.jar
-rwxrwx---+ 1 Tianma None 1120101 6月 11 11:48 smali-2.2.7.jar将生成的
.dex
打包到.jar
中去:1
zip services.jar classes*.dex
最终生成的
services.jar
会包含.dex
。
总结
- 本质上
deodex
系统 App 和framework/xxx.jar
没有区别。 - 在 Windows 上暂时不能对 Android P 中的
odex
和vdex
进行反编译