0%

Android Deodex

在使用逆向工具(比如 jdax 等)反编译某些系统 App 的时候,会发现其代码其实是不全的,其实是因为系统应用的 APK 已经经过 odexvdex 化,导致代码分离。

比如在之前的文章(Android 拆包,提取 APK 或 Framework 文件)中,拆了 MIUI 的 Rom,其中小米系统界面(MiuiSystemUI)拆开后大致是这样的:

1
2
3
4
5
6
7
8
9
$ tree -s priv-app/MiuiSystemUI/
priv-app/MiuiSystemUI/
├── [ 17525476] MiuiSystemUI.apk
└── [ 0] oat
└── [ 0] arm64
├── [ 12669648] MiuiSystemUI.odex
└── [ 6418324] MiuiSystemUI.vdex

2 directories, 3 files

解压 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-levelzip/uzip 库。
  • 编译:

最终正确编译之后会在 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
2
drwxrwx---+ 1 Tianma None      0 6月  11 18:21 priv-app
-rwxrwx---+ 1 Tianma None 458972 6月 11 20:16 vdexExtractor.exe

其中的 MiuiSystemUI 就在 priv-app/MiuiSystemUI/ 路径下。

  1. 复制 MiuiSystemUI.apk 到当前路径下:

    1
    cp priv-app/MiuiSystemUI/MiuiSystemUI.apk MiuiSystemUI.apk
  2. 使用 vdexExtractorMiuiSystemUI 中的 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
    5
    drwxrwx---+ 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 等工具查看其代码了。

  3. 将生成的 .dex 打包到 .apk 中:

    1
    2
    mv 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 下的 jarframework 相关环境(主要是用作 ClassLoader 的路径),所以需要的目录结构如下:

1
2
drwxrwx---+ 1 Tianma None      0 6月  11 18:21 framework
-rwxrwx---+ 1 Tianma None 458972 6月 11 20:16 vdexExtractor.exe
  1. 复制 services.jar 到当前目录下:

    1
    cp framework/services.jar services.jar
  2. 使用 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
    4
    drwxrwx---+ 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 等工具查看其代码了。

  3. 将生成的 .dex 打包到 .jar 中去:

    1
    2
    mv services_classes.dex classes.dex
    zip services.jar classes*.dex

    最终生成的 services.jar 会包含 .dex

反编译 odex

准备工作

  • 系统:Windows 10
  • 下载 smali 提供的 smali-xxx.jarbaksmali-xxx.jar 具体下载地址 -> downloads

这里下载的是 2.2.7 版本。

反编译系统App中的odex

仍然以 MiuiSystemUI 这个系统 App 为例,需要 framework 环境,故当前目录结构如下:

1
2
3
4
-rwxrwx---+ 1 Tianma None 1367549 6月  11 11:48 baksmali-2.2.7.jar
drwxrwx---+ 1 Tianma None 0 6月 11 18:21 framework
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
  1. 复制 MiuiSystemUI.apk 到当前目录:

    1
    cp priv-app/MiuiSystemUI/MiuiSystemUI.apk MiuiSystemUI.apk
  2. 使用 baksmaliodex 反编译成 .smali 文件,再用 smali.smali 转换成 dex:

    1
    2
    java -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
  3. .dex 打包进 .apk 中:

    1
    zip MiuiSystemUI.apk classes*.dex

    最终 .apk 会包含 .dex

反编译 framework 下的 odex

仍然以 services.jar 为例,当前目录结构:

1
2
3
-rwxrwx---+ 1 Tianma None 1367549 6月  11 11:48 baksmali-2.2.7.jar
drwxrwx---+ 1 Tianma None 0 6月 11 18:21 framework
-rwxrwx---+ 1 Tianma None 1120101 6月 11 11:48 smali-2.2.7.jar
  1. 复制 services.jar 到当前目录:

    1
    cp framework/services.jar services.jar
  2. 使用 baksmaliodex 反编译成 .smali 文件,再用 smali.smali 转换成 dex:

    1
    2
    java -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
  3. 将生成的 .dex 打包到 .jar 中去:

    1
    zip services.jar classes*.dex

    最终生成的 services.jar 会包含 .dex

总结

  • 本质上 deodex 系统 App 和 framework/xxx.jar 没有区别。
  • 在 Windows 上暂时不能对 Android P 中的 odexvdex 进行反编译

参考