逆向工程实战手册 第 10 章

第 10 章 Android APK 逆向

Android 逆向是逆向入门最友好的平台:APK 里 Java 层可反编译成可读源码,DEX 结构规范,工具链成熟。但核心逻辑常藏在 native .so 里,本章教会你完整的"解包 → Java 层 → smali → .so → 重打包 → Hook"全链路。

📍 知识点地图 | 主题:Android APK逆向 | 前置:第3-6章 | 后续:第47章 | 核心概念:jadx、apktool、smali、Frida、重打包

10.1 APK 结构

app.apk (ZIP)
├── classes.dex          # Java 字节码(核心逻辑)
├── AndroidManifest.xml  # 二进制 XML(组件/权限/入口)
├── res/                 # 资源(布局、字符串、图片)
├── resources.arsc       # 资源索引表
├── assets/              # 原始资源
├── lib/
│   ├── arm64-v8a/*.so   # 原生库(64 位)
│   └── armeabi-v7a/*.so # 原生库(32 位)
└── META-INF/            # 签名

10.2 完整工作流

Step 1: 解包(Triage)

# Java 反编译(可读源码)
jadx -d jadx_out app.apk
jadx --single-class com.example.LoginActivity -d jadx_out app.apk
jadx --deobf -d jadx_out app.apk        # 去混淆命名

# 解包 smali + 资源
apktool d app.apk -o apktool_out

# 设备/进程侦察
adb devices
frida-ps -U

先看三样东西: 1. AndroidManifest.xml:包名、Application/MainActivity、权限、导出组件 2. lib/ 是否有 .so(有 → 核心逻辑可能 native) 3. 主 package 结构

Step 2: Java 层逻辑

jadx_out 里优先看:

  • MainActivity / Application
  • 登录、网络、加密、风控相关类
  • 第三方 SDK 初始化(加固壳的 SDK 通常在此)

搜索关键词:login sign encrypt cipher token root certificate trust okhttp retrofit webview

Step 3: smali 与资源层

当 jadx 结果不完整、混淆重、或需要实际 patch 时切 smali:

  • smali*/ 目录(DEX 的汇编形式)
  • res/values/strings.xml(字符串常量)

优先 patch 点: - android:exported(组件导出) - 调试标记 - root 检测返回值(const/4 v0, 0x10x0) - 登录验证分支(if-neif-eq) - 证书校验分支

Step 4: 重打包(改完必做)

apktool b apktool_out -o rebuilt.apk
# 然后签名安装(见下)

仓库自带一条龙脚本:

pwsh -File "C:\Users\1\src\reverse-skill\skills\apk-reverse\scripts\rebuild-sign-install.ps1" -ProjectDir "apktool_out" -Install -Reinstall -DeviceSerial "127.0.0.1:7555"

Step 5: 动态 Hook(静态不足时)

# Hook 登录/加密函数
frida -U -f com.example.app -l hook.js

# 自动 trace 证书相关
frida-trace -U -f com.example.app -j '*!*certificate*'

Hook 优先级:Java 层 → smali patch → native Hook,先打印参数返回值,再决定是否改。

Step 6: Native .so 分流(关键决策!)

出现这些信号 → 立刻切 native 分析

□ Java 层只是 JNI 包装(System.loadLibrary 后逻辑消失)
□ 核心签名逻辑不在 Java
□ 证书校验/风控在 .so 中
□ 加固壳:classes.dex 加密,真实 dex 运行时才有
  • 快速侦察:radare2(rabin2 -z/-i
  • 深度分析:IDA / Ghidra 反编译

10.3 工具分工速查

工具 用途 关键命令
jadx Java 反编译 jadx -d out app.apk
apktool smali/资源/重打包 apktool d/b
frida 动态 Hook frida -U -f pkg -l s.js
adb 设备/日志/安装 adb devices/logcat/install
apksigner 签名 重建脚本内置
zipalign 对齐 重建脚本内置
MobSF 自动化安全分析 web 界面

10.4 重打包签名闭环

# 仓库脚本全自动: 重建 → zipalign → apksigner → adb install
pwsh -File "...\apk-reverse\scripts\rebuild-sign-install.ps1" -ProjectDir "C:\work\apktool_out" -Install -Reinstall

手动链路:

apktool b apktool_out -o rebuilt.apk
zipalign -v 4 rebuilt.apk aligned.apk
apksigner sign --ks debug.keystore --ks-pass pass:android aligned.apk
adb install -r aligned.apk

10.5 常见 APK 逆向目标清单

□ 登录/签名算法(MD5/AES/RSA DIY)
□ SSL Pinning 绕过
□ Root/模拟器检测绕过
□ 风控参数(device_id、指纹)
□ WebView 注入点
□ 硬编码密钥/API Key(APKLeaks 扫描)
□ 加固壳脱壳

10.6 加固(加壳)处理

特征 脱壳思路
360/腾讯/梆梆/爱加密 自定义 loader Frida dump dex(内存中完整 dex)
免费壳(简单加密) dex 头部被改 修复 dex magic + FART/Youpk
商业壳 双 dex + 自校验 动态 dump + 修复

通用思路:在 dex 解密完成后、使用前 dump 内存——Frida 脚本找到 DexClassLoader/ClassLoader.loadClass 时机,读取 BaseDexClassLoader 里的 dex 数组 dump 出来,再用 jadx 分析。

10.7 APK 安全测试清单(OWASP MASTG 视角)

□ Manifest: exported 组件、backup 标志、cleartext 流量
□ 权限: 是否过度申请
□ 存储: SharedPreferences/数据库明文敏感数据
□ 网络: 证书校验、TLS 配置
□ 硬编码: 密钥/Token(APKLeaks)
□ 加固: 是否加壳、能否被反编译
□ 动态: SSL Pinning、Root 检测、防调试

动手练习

  1. 找一个开源/测试 APK(frida 官方测试 App 或 GitHub 示例),完整走一遍:解包 → 看 Manifest → 看 MainActivity → 找登录逻辑。
  2. 练习 smali patch:把某个 const/4 v0, 0x1 改成 0x0 改变分支,重打包签名安装验证。
  3. 用 Frida Hook Cipher.init,打印某 App 的加密密钥。
  4. 判断一个 APK 是否加壳:jadx 解出的是壳代码还是业务代码?

深入阅读

  • 仓库:skills/apk-reverse/SKILL.md(CLI 作业规范 + 脚本用法)
  • 仓库:skills/apk-reverse/references/apk-security-checklist.md(MASTG 安全清单)
  • 仓库:skills/apk-reverse/references/frida-cookbook.md / frida-bypass-kit.md(Hook 脚本库)
  • 仓库:skills/mobile-reverse/SKILL.md(Android+iOS 统一方法论)
  • 仓库:skills/reverse-engineering/languages-platforms.md(JNI RegisterNatives 混淆、DEX 运行时 patch、.so 加载绕过)
  • 实战案例:skills/field-journal/seed-008_apk-okhttp-ssl-pin-bypass.md