DEV Community

chatmay
chatmay

Posted on

Android APK 逆向实战:从 JADX、Apktool 到 Frida、Ghidra,理解 DEX、SO、脱壳与加固

Android APK 逆向实战:从 JADX、Apktool 到 Frida、Ghidra,理解 DEX、SO、脱壳与加固

在 Android 安全研究和 APP 开发过程中,APK 逆向是一个非常重要的技术方向。

很多人刚开始接触 APK 逆向时,通常只知道使用 JADX 打开 APK,然后查看 Java 代码。

但真正深入之后会发现,Android APK 背后涉及的内容远不止 Java 代码:

  • APK 文件结构
  • AndroidManifest.xml
  • DEX
  • Smali
  • SO / ELF
  • JNI
  • ARM64
  • ClassLoader
  • ART
  • Frida
  • DEX 脱壳
  • SO 分析
  • VMP
  • RASP
  • Android 版本适配

如果想真正理解 Android 加固和脱壳,仅仅会使用一个反编译工具是不够的。

本文从一个普通 APK 出发,把 JADX、Apktool、Smali、Frida、Ghidra/IDA、DEX、SO、ART 串起来,建立一套比较完整的 Android APK 逆向分析思路。


一、APK 到底是什么?

APK 本质上是一个 ZIP 格式的 Android 应用程序包。

例如:

app.apk
Enter fullscreen mode Exit fullscreen mode

修改扩展名或者直接使用解压工具打开,可以看到:

AndroidManifest.xml
classes.dex
classes2.dex
resources.arsc
res/
assets/
lib/
META-INF/
Enter fullscreen mode Exit fullscreen mode

如果应用比较简单,可能只有一个:

classes.dex
Enter fullscreen mode Exit fullscreen mode

大型 Android 应用则可能存在:

classes.dex
classes2.dex
classes3.dex
classes4.dex
Enter fullscreen mode Exit fullscreen mode

Native 代码一般位于:

lib/
├── arm64-v8a/
│   ├── libxxx.so
│   └── libyyy.so
└── armeabi-v7a/
    └── libxxx.so
Enter fullscreen mode Exit fullscreen mode

因此可以简单理解:

APK
│
├── Java / Kotlin
│       ↓
│      DEX
│
├── Native
│       ↓
│      SO
│
├── Resources
│
└── Manifest / Signature
Enter fullscreen mode Exit fullscreen mode

二、使用 JADX 进行第一轮静态分析

JADX 是 Android APK 逆向分析中非常常见的工具。

它可以直接加载 APK,并尝试将 DEX 反编译成接近 Java 的代码。

例如:

jadx app.apk
Enter fullscreen mode Exit fullscreen mode

打开之后,可以看到类似:

com.example.app
├── MainActivity
├── LoginActivity
├── MainApplication
├── network
├── utils
└── ...
Enter fullscreen mode Exit fullscreen mode

如果原始代码是:

fun checkLogin(token: String): Boolean {
    return token.isNotEmpty()
}
Enter fullscreen mode Exit fullscreen mode

编译以后会进入 DEX。

JADX 做的事情实际上是:

DEX
 ↓
反编译
 ↓
Java-like Code
Enter fullscreen mode Exit fullscreen mode

所以需要注意:

JADX 显示出来的代码,并不等于原始 Java/Kotlin 源代码。

如果应用使用了:

  • R8
  • ProGuard
  • 混淆
  • Kotlin Coroutine
  • Lambda
  • Native
  • 自定义 ClassLoader
  • DEX 加密
  • VMP

那么最终反编译出来的代码可能和原始源码存在非常大的差异。


三、为什么还需要 Apktool?

JADX 更适合查看代码逻辑。

Apktool 则更适合分析:

  • APK 结构
  • AndroidManifest.xml
  • Resources
  • Smali
  • APK 修改与重新打包

例如:

apktool d app.apk -o app_out
Enter fullscreen mode Exit fullscreen mode

解包之后通常可以看到:

app_out/
├── AndroidManifest.xml
├── smali/
├── smali_classes2/
├── res/
├── assets/
└── unknown/
Enter fullscreen mode Exit fullscreen mode

其中非常重要的一部分就是:

smali/
Enter fullscreen mode Exit fullscreen mode

这里保存的是 Smali 代码。


四、Smali 是什么?

理解 Android 逆向,Smali 是必须掌握的一部分。

可以简单理解成:

Java / Kotlin
      ↓
    D8 / R8
      ↓
     DEX
      ↓
   Smali 表示
Enter fullscreen mode Exit fullscreen mode

Smali 更接近 DEX 指令级别。

例如:

.method public test()I
    .locals 1

    const/4 v0, 0x1

    return v0
.end method
Enter fullscreen mode Exit fullscreen mode

逻辑非常简单:

v0 = 1
return v0
Enter fullscreen mode Exit fullscreen mode

实际逆向过程中:

JADX 负责帮助我们快速理解整体代码逻辑,Smali 则用于进一步确认具体实现。

例如 JADX 中看到:

if (isLogin()) {
    startActivity(...);
}
Enter fullscreen mode Exit fullscreen mode

如果怀疑它存在某种校验逻辑,可以继续定位对应 Smali。


五、从 Java 层进入 Native 层

分析 APK 时,经常会遇到:

public native boolean verify(String data);
Enter fullscreen mode Exit fullscreen mode

或者:

static {
    System.loadLibrary("xxx");
}
Enter fullscreen mode Exit fullscreen mode

这说明部分核心逻辑可能已经进入 Native 层。

对应的文件通常位于:

lib/arm64-v8a/libxxx.so
Enter fullscreen mode Exit fullscreen mode

这时候继续使用 JADX 分析就不够了。

需要进入:

Java / Kotlin
      ↓
JNI
      ↓
C / C++
      ↓
SO
Enter fullscreen mode Exit fullscreen mode

这个阶段通常会使用:

  • Ghidra
  • IDA
  • Binary Ninja

等 Native 分析工具。


六、使用 Ghidra / IDA 分析 SO

Android 的 .so 文件通常属于 ELF 格式。

例如:

libxxx.so
Enter fullscreen mode Exit fullscreen mode

使用 Ghidra 或 IDA 加载之后,可以重点关注:

ELF Header
Sections
Symbols
Strings
Imports
Exports
Functions
Enter fullscreen mode Exit fullscreen mode

特别是 JNI 相关位置。

例如:

JNI_OnLoad
RegisterNatives
Java_xxx_xxx
Enter fullscreen mode Exit fullscreen mode

这些内容可以帮助我们建立:

Java Method
      ↓
JNI
      ↓
Native Function
      ↓
SO
Enter fullscreen mode Exit fullscreen mode

的调用关系。


七、JNI 是 DEX 和 SO 之间的重要桥梁

Android 应用经常存在这样的调用链:

Java / Kotlin
      ↓
     JNI
      ↓
 C / C++
      ↓
     SO
Enter fullscreen mode Exit fullscreen mode

例如:

public native String decrypt(String data);
Enter fullscreen mode Exit fullscreen mode

实际运行过程中可能变成:

Java Method
     ↓
JNI Bridge
     ↓
Native Function
     ↓
libxxx.so
Enter fullscreen mode Exit fullscreen mode

因此在分析 APK 时,如果发现大量:

native
System.loadLibrary()
RegisterNatives()
JNI_OnLoad()
Enter fullscreen mode Exit fullscreen mode

就应该把分析范围扩展到 Native 层。


八、为什么加固 APK 很难直接用 JADX 分析?

普通 APK 的大致结构可以理解为:

classes.dex
    ↓
ClassLoader
    ↓
Class
    ↓
ART
    ↓
执行
Enter fullscreen mode Exit fullscreen mode

但是经过加固之后,结构可能变成:

APK
│
├── 壳代码
├── 加密 DEX
└── Native Loader
        ↓
     Runtime
        ↓
    DEX 解密
        ↓
   ClassLoader
        ↓
       ART
Enter fullscreen mode Exit fullscreen mode

因此静态分析工具拿到的:

classes.dex
Enter fullscreen mode Exit fullscreen mode

可能并不是真正的业务 DEX。

例如一个实际拥有大量业务功能的 APP:

JADX
 ↓
几十个类
Enter fullscreen mode Exit fullscreen mode

但实际运行时:

几千甚至更多业务类
Enter fullscreen mode Exit fullscreen mode

这就是 Android 加固经常出现的情况。


九、什么是 DEX 脱壳?

很多人理解的脱壳是:

找到一个脚本,然后把 DEX 导出来。

但从技术原理来看,脱壳远不止如此。

一个典型的 DEX 加固流程可能是:

原始 DEX
   ↓
加密 / 转换 / 虚拟化
   ↓
保护后的 APK
Enter fullscreen mode Exit fullscreen mode

运行的时候:

保护后的 APK
      ↓
     壳代码
      ↓
运行时恢复
      ↓
真实 DEX / Code
      ↓
ClassLoader
      ↓
ART
      ↓
执行
Enter fullscreen mode Exit fullscreen mode

所以从研究角度来看,真正值得理解的是:

代码什么时候被恢复、以什么形式存在,以及最终如何进入 ART 执行链路。


十、Frida 为什么重要?

JADX、Apktool、Ghidra、IDA 主要属于静态分析工具。

Frida 则属于动态分析工具。

两者最大的区别可以简单理解为:

静态分析

APK
 ↓
DEX / SO
 ↓
分析代码
Enter fullscreen mode Exit fullscreen mode

动态分析:

APK
 ↓
实际运行
 ↓
观察函数
 ↓
观察参数
 ↓
观察返回值
 ↓
分析调用关系
Enter fullscreen mode Exit fullscreen mode

例如:

Java Method
     ↓
参数
     ↓
执行
     ↓
返回值
Enter fullscreen mode Exit fullscreen mode

动态分析能够帮助研究人员确认:

  • 某个函数是否真的执行
  • 函数什么时候执行
  • 参数是什么
  • 返回值是什么
  • Java 和 Native 如何交互

对于复杂的加固应用,这些运行时信息往往比单纯查看反编译代码更加重要。


十一、静态分析 + 动态分析

实际 APK 分析过程中,通常不会只使用一个工具。

比较常见的组合是:

                    APK
                     │
          ┌──────────┴──────────┐
          ↓                     ↓
        JADX                 Apktool
          │                     │
       Java/Kotlin            Smali
          │                     │
          └──────────┬──────────┘
                     ↓
                 定位逻辑
                     │
              ┌──────┴──────┐
              ↓             ↓
            Frida       Ghidra / IDA
              ↓             ↓
          动态分析        Native分析
              │             │
              └──────┬──────┘
                     ↓
                JNI / ART
                     ↓
                 调用链
Enter fullscreen mode Exit fullscreen mode

这样能够形成完整的分析闭环。


十二、ART 是理解 Android 加固的关键

如果只停留在 JADX 和 Smali 层面,很难真正理解现代 Android 加固。

进一步学习 Android 安全之后,就会遇到:

ART —— Android Runtime

可以简单理解为:

DEX
 ↓
ClassLoader
 ↓
DexFile
 ↓
Class
 ↓
Method
 ↓
ART Runtime
 ↓
解释执行 / JIT / AOT
Enter fullscreen mode Exit fullscreen mode

这也是为什么研究 Android 加固时,经常需要阅读 AOSP 中 ART 相关源码。

重点关注的方向包括:

ClassLoader
DexFile
ClassLinker
JNI
JIT
AOT
Method
Class Loading
Enter fullscreen mode Exit fullscreen mode

当一个加固方案深度介入这些运行时机制之后,就不能再简单地把它理解成:

DEX 加密
Enter fullscreen mode Exit fullscreen mode

而应该理解成:

代码保护
+
运行时加载
+
执行环境保护
+
完整性保护
Enter fullscreen mode Exit fullscreen mode

十三、为什么 Android 新版本会影响加固?

Android Runtime 并不是一成不变的。

随着 Android 版本升级:

Framework
ART
Class Loading
JNI
Hidden API
Memory Management
Native Interface
Enter fullscreen mode Exit fullscreen mode

都会发生不同程度的变化。

因此,如果加固方案深度依赖 ART 内部实现,就需要持续进行 Android 版本适配。

可以把 Android 应用的运行环境简单理解为:

Application
     ↓
Java / Kotlin
     ↓
Android Framework
     ↓
ART
     ↓
Native
     ↓
Linux Kernel
Enter fullscreen mode Exit fullscreen mode

越深入底层:

加固方案能够控制的运行时细节通常越多,同时也意味着更高的版本适配成本。

这也是为什么一个加固方案在 Android 10、Android 12、Android 14、Android 15、Android 16 上的表现不能简单认为完全一致。


十四、DEX 加固和 SO 加固有什么区别?

这是理解 Android 加固非常重要的一点。

1. DEX 加固

DEX 主要承载:

Java / Kotlin
业务逻辑
算法
接口逻辑
关键字符串
Enter fullscreen mode Exit fullscreen mode

常见保护思路包括:

DEX Encryption
DEX Packing
Class Encryption
VMP
Runtime Loading
Enter fullscreen mode Exit fullscreen mode

2. SO 加固

SO 主要承载:

Native 算法
核心计算
JNI 接口
底层逻辑
Enter fullscreen mode Exit fullscreen mode

常见保护思路包括:

ELF Protection
Symbol Stripping
.text Protection
Integrity Check
Runtime Decryption
Anti-Debug
Enter fullscreen mode Exit fullscreen mode

因此比较完整的 Android 加固方案通常不是只保护 DEX,而是多个层面共同保护:

DEX
 +
SO
 +
Resources
 +
Runtime
 +
Integrity
 +
RASP
Enter fullscreen mode Exit fullscreen mode

十五、VMP 是什么?

VMP 通常可以理解为:

Virtual Machine Protection,虚拟化保护。

普通代码执行过程可以简单理解成:

Java / Kotlin
      ↓
     DEX
      ↓
     ART
Enter fullscreen mode Exit fullscreen mode

而虚拟化保护可能变成:

原始代码
   ↓
转换成虚拟指令
   ↓
Virtual Machine
   ↓
Interpreter
   ↓
执行
Enter fullscreen mode Exit fullscreen mode

例如原始逻辑:

A + B
Enter fullscreen mode Exit fullscreen mode

经过虚拟化后,不再直接保存成传统形式,而可能转换成一系列虚拟指令:

LOAD
LOAD
ADD
RETURN
Enter fullscreen mode Exit fullscreen mode

然后由自定义解释器负责执行。

复杂的 VMP 可能包含:

Virtual Instruction
Dispatcher
Handler
Interpreter
Control Flow
Data Flow
Enter fullscreen mode Exit fullscreen mode

因此 VMP 的分析难度通常明显高于普通的 DEX 混淆。


十六、Android APK 逆向的完整学习路线

如果从零开始学习 Android APK 逆向,可以按照下面的顺序进行。

第一阶段:APK 基础

先理解:

APK
Manifest
DEX
Resources
SO
Signature
Enter fullscreen mode Exit fullscreen mode

工具:

JADX
Apktool
Enter fullscreen mode Exit fullscreen mode

第二阶段:Smali

重点掌握:

register
invoke
move
const
if
goto
return
new-instance
iget
iput
Enter fullscreen mode Exit fullscreen mode

目标不是机械背诵指令,而是能够:

看到 Smali 后快速还原程序逻辑。


第三阶段:Java / Kotlin → DEX

理解:

Java / Kotlin
      ↓
    D8 / R8
      ↓
     DEX
Enter fullscreen mode Exit fullscreen mode

进一步研究:

classes.dex
classes2.dex
Multidex
R8
ProGuard
Enter fullscreen mode Exit fullscreen mode

第四阶段:Native

学习:

C / C++
   ↓
ARM64
   ↓
ELF
   ↓
SO
Enter fullscreen mode Exit fullscreen mode

工具:

Ghidra
IDA
Enter fullscreen mode Exit fullscreen mode

重点掌握:

JNI
JNI_OnLoad
RegisterNatives
ARM64 Calling Convention
Enter fullscreen mode Exit fullscreen mode

第五阶段:动态分析

学习:

Frida
Enter fullscreen mode Exit fullscreen mode

重点理解:

Java Hook
Native Hook
参数观察
返回值观察
调用链跟踪
Enter fullscreen mode Exit fullscreen mode

第六阶段:ART

最后深入:

ART
ClassLoader
DexFile
ClassLinker
JNI
JIT
AOT
Enter fullscreen mode Exit fullscreen mode

然后再研究:

DEX Encryption
Runtime Loading
DEX Protection
VMP
SO Protection
RASP
Anti-Hook
Integrity
Enter fullscreen mode Exit fullscreen mode

这样学习会比一开始直接研究所谓的“脱壳脚本”更加系统。


十七、从逆向角度理解 Android 加固

当把整个流程串起来之后,会发现:

Android 逆向和 Android 加固实际上是同一条技术链路上的两个方向。

逆向研究关注:

代码在哪里?
     ↓
什么时候加载?
     ↓
如何解密?
     ↓
谁调用?
     ↓
在哪里执行?
Enter fullscreen mode Exit fullscreen mode

而加固则试图提高这些问题的分析成本:

代码不能直接看到
        ↓
代码不能轻易恢复
        ↓
降低运行时暴露
        ↓
增加动态分析成本
        ↓
检测异常运行环境
Enter fullscreen mode Exit fullscreen mode

因此现代 Android 加固并不是简单地:

classes.dex 加密
Enter fullscreen mode Exit fullscreen mode

而更接近:

                    APK
                     │
       ┌─────────────┼─────────────┐
       ↓             ↓             ↓
      DEX            SO         Resources
       │             │             │
     加密/VMP       ELF保护        加密
       │             │             │
       └─────────────┼─────────────┘
                     ↓
                  Runtime
                     ↓
            ClassLoader / ART
                     ↓
             Integrity / RASP
Enter fullscreen mode Exit fullscreen mode

十八、一套实用的 Android 逆向工具组合

如果主要用于学习和安全研究,不需要一开始安装几十个工具。

基础工具链可以使用:

分析目标 工具
Java/Kotlin 代码分析 JADX
APK 解包 Apktool
Smali 分析 Apktool
DEX 分析 JADX / DEX 工具
动态分析 Frida
Native 分析 Ghidra / IDA
ARM64 分析 Ghidra / IDA
Android Runtime AOSP 源码
调试 adb / LLDB

最终可以形成:

                 APK
                  │
         ┌────────┴────────┐
         ↓                 ↓
       JADX             Apktool
         ↓                 ↓
    Java/Kotlin          Smali
         │                 │
         └────────┬────────┘
                  ↓
              静态分析
                  │
         ┌────────┴────────┐
         ↓                 ↓
       Frida          Ghidra / IDA
         ↓                 ↓
     动态分析          SO / ARM64
         │                 │
         └────────┬────────┘
                  ↓
               JNI / ART
                  ↓
             DEX / SO
              加载链
                  ↓
          加固与脱壳研究
Enter fullscreen mode Exit fullscreen mode

十九、总结

Android APK 逆向真正值得学习的,并不是某一个工具或者某一个脱壳脚本,而是理解整个 Android Runtime 链路。

最核心的一条主线可以概括为:

APK
 ↓
DEX
 ↓
ClassLoader
 ↓
ART
 ↓
JNI
 ↓
SO
 ↓
Native
 ↓
Runtime
Enter fullscreen mode Exit fullscreen mode

掌握 JADX + Apktool,可以完成基础静态分析;

掌握 Smali,可以进一步理解 DEX 指令;

加入 Frida,可以观察真实运行过程;

再结合 Ghidra / IDA,就可以进入 Native 和 ARM64 层;

继续研究 ART、DEX 加密、运行时加载、VMP、SO 加固和 RASP,才能真正理解现代 Android 加固的技术体系。

对于 Android 安全研究来说,最终需要建立的并不是“怎么脱壳”的单点知识,而是一套完整的认知:

代码在哪里 → 如何加载 → 什么时候恢复 → 如何执行 → 如何保护。

这条链路基本贯穿了 Android APK 逆向、脱壳以及加固技术的核心内容。

Top comments (0)