边界说明:本文只面向自研 Demo、开源靶场或已获得书面授权的 App。所有操作目标都是理解 Android 应用结构、验证安全风险、建设防护能力,不用于未授权破解、盗号、绕过付费或攻击第三方服务。
1. 本章目标
学完本章后,应能完成四件事:
| 能力 | 说明 | 验收方式 |
|---|---|---|
| 理解 APK 构成 | 知道 Manifest、DEX、资源、Native 库、签名各自负责什么 | 能解压 APK 并标注每类文件用途 |
| 搭建工具链 | 准备 Android Studio、adb、jadx、apktool、apksigner、Frida、Burp/mitmproxy | 每个工具能输出版本或完成一次最小操作 |
| 创建授权 Demo | 自己写一个包含登录、会员判断、HTTPS 请求、Native 方法的测试 App | 能安装运行 debug 和 release APK |
| 建立实验记录 | 每次分析都有命令、截图、日志、结论和限制 | 输出 case-notes.md |
安卓逆向学习最常见的问题是直接上工具,但不知道工具结果说明什么。本章先把 Android 应用的运行模型、工程产物和实验环境讲清楚,后续静态、动态、Native、防护章节都围绕同一个 Demo 进行。
2. Android 逆向必须先懂的基础
2.1 APK 是什么
APK 本质上是一个带签名的 ZIP 包。它不是单个可执行文件,而是由多个层次组成:
| 文件或目录 | 作用 | 逆向关注点 |
|---|---|---|
AndroidManifest.xml |
声明包名、权限、组件、入口、导出状态 | 组件暴露、调试开关、备份开关、Deep Link |
classes.dex |
Java/Kotlin 编译后的 Dalvik 字节码 | 业务逻辑、加密逻辑、风控判断、接口调用 |
resources.arsc |
编译后的资源索引 | 字符串、布局、资源 ID 映射 |
res/ |
布局、图片、字符串等资源 | 页面结构、隐藏入口、硬编码文案 |
assets/ |
原样打包的资源文件 | 配置、证书、模型文件、脚本 |
lib/<abi>/*.so |
Native 动态库 | JNI、加密、反调试、完整性校验 |
META-INF/ 或签名块 |
APK 签名信息 | 是否被重签名、签名方案版本 |
逆向时不要只看 Java 反编译结果。很多关键逻辑会拆散在 Manifest、资源、Java/Kotlin、Native、网络请求和服务端校验之间。
2.2 Android 安全边界
Android 的基础安全模型包括:
- 应用沙箱:每个 App 默认拥有独立 UID,私有目录通常在
/data/data/<package>。 - 权限模型:危险权限需要运行时申请,组件导出需要额外权限或身份校验。
- 签名模型:同签名 App 可共享能力,升级安装依赖签名一致。
- 进程模型:Java 层、Native 层、系统服务通过 Binder、JNI、系统 API 协作。
- 网络模型:App 通过 OkHttp、Retrofit、HttpURLConnection、WebView 等发起请求。
逆向分析就是在这些边界上找证据:哪里把秘密放在客户端,哪里只做本地判断,哪里能被抓包重放,哪里缺少签名或完整性验证。
3. 工具链安装与验证
3.1 基础工具清单
| 工具 | 用途 | 验证命令或方法 |
|---|---|---|
| Android Studio | 创建 Demo、编译 APK、调试源码 | 能打开项目并运行模拟器 |
| Android SDK / adb | 安装、启动、日志、shell、文件操作 | adb devices |
| jadx / jadx-gui | APK 转近似 Java/Kotlin 源码 | jadx --version 或打开 GUI |
| apktool | 反编译资源和 Smali,重打包 APK | apktool --version |
| apksigner | APK 签名、签名验证 | apksigner verify --verbose app.apk |
| keytool | 生成测试证书 | keytool -help |
| Frida / frida-tools | Java/Native Hook | frida --version、frida-ps -Uai |
| Burp Suite / mitmproxy | 抓包、改包、重放请求 | 能抓到 Demo 的 HTTP/HTTPS 请求 |
| Ghidra / IDA Free | Native 反编译 | 能打开 .so 并查看函数 |
3.2 adb 基础命令
bash
adb devices
adb install app-debug.apk
adb shell pm list packages | grep reverse
adb shell dumpsys package com.example.reversedemo
adb shell am start -n com.example.reversedemo/.MainActivity
adb logcat | grep ReverseDemo
adb shell run-as com.example.reversedemo ls files
关键理解:
adb install用于安装未上架测试包。dumpsys package能看到 Activity、Service、Receiver、Provider、权限和签名摘要。logcat是动态分析的第一手证据,但正式包不应输出敏感日志。run-as只对 debuggable 应用可用,正式包不能依赖这个能力。
3.3 Frida 设备验证
Frida 需要电脑端版本和设备端 frida-server 主版本一致。
bash
frida --version
adb shell getprop ro.product.cpu.abi
adb push frida-server /data/local/tmp/frida-server
adb shell chmod 755 /data/local/tmp/frida-server
adb shell /data/local/tmp/frida-server
frida-ps -Uai
验证标准:
| 检查项 | 通过标准 |
|---|---|
| USB 连接 | adb devices 显示 device |
| Frida 服务 | 设备端 frida-server 正常运行 |
| 进程枚举 | frida-ps -Uai 能列出 App |
| 版本一致 | 无 protocol mismatch 报错 |
4. 授权 Demo 工程设计
建议创建一个 ReverseDemo,故意包含学习用的风险点和后续修复点。不要直接拿第三方商业 App 当练习目标。
4.1 Demo 功能清单
| 功能 | 初始实现 | 用于练习 |
|---|---|---|
| 登录页 | 用户名密码写死为 demo/123456 |
静态字符串定位、日志检查 |
| 会员判断 | isVip() 本地返回布尔值 |
Smali 修改、Frida Hook |
| 接口请求 | 请求本地测试服务 /api/profile |
抓包、参数篡改、重放 |
| 请求签名 | 客户端生成 timestamp + nonce + hmac |
静态定位签名函数、动态打印明文 |
| Native 方法 | nativeCheck() 返回环境检测结果 |
JNI 定位、Native Hook |
| Root/代理检测 | 简单检测 su、代理端口 |
绕过检测与防护复测 |
| 防护开关 | release 开启混淆、签名校验 | 对比加固前后分析成本 |
4.2 Kotlin 示例:本地会员判断
kotlin
package com.example.reversedemo
object UserCenter {
private const val LOCAL_USER = "demo"
private const val LOCAL_PASSWORD = "123456"
fun login(user: String, password: String): Boolean {
return user == LOCAL_USER && password == LOCAL_PASSWORD
}
fun isVip(userId: String): Boolean {
return userId == "10001"
}
fun featureName(): String {
return if (isVip("10002")) "vip-video" else "free-video"
}
}
这个 Demo 故意把账号、密码和会员判断放在客户端。后续章节会证明:只要关键权益依赖客户端判断,就可以被静态修改或动态 Hook 影响。
4.3 Kotlin 示例:网络签名函数
kotlin
object Signer {
private const val CLIENT_SECRET = "demo-client-secret-change-me"
fun sign(path: String, timestamp: String, nonce: String, body: String): String {
val raw = "$path|$timestamp|$nonce|$body|$CLIENT_SECRET"
return sha256(raw)
}
private fun sha256(value: String): String {
val digest = java.security.MessageDigest.getInstance("SHA-256")
return digest.digest(value.toByteArray())
.joinToString("") { "%02x".format(it) }
}
}
这个写法也故意不安全:只要密钥在客户端,就可能被静态搜索、动态打印或从内存里定位。真正的核心鉴权应由服务端掌握,客户端只能持有短期凭证。
4.4 Native 示例:JNI 检测
cpp
#include <jni.h>
#include <unistd.h>
extern "C"
JNIEXPORT jboolean JNICALL
Java_com_example_reversedemo_NativeGuard_nativeCheck(JNIEnv *, jobject) {
return access("/system/bin/su", F_OK) != 0;
}
这个 Native 方法用于练习:
- 用 jadx 找到
System.loadLibrary。 - 用
readelf、nm或 Ghidra 找 JNI 函数。 - 用 Frida Hook Java 层或 Native 层返回值。
- 把检测结果从"可绕过"改造成"只作为风险信号,不作为唯一安全判断"。
5. Demo 构建与运行
5.1 Debug 包
bash
./gradlew assembleDebug
adb install -r app/build/outputs/apk/debug/app-debug.apk
adb shell am start -n com.example.reversedemo/.MainActivity
adb logcat | grep ReverseDemo
Debug 包适合学习调试,但不代表真实防护状态。它通常包含调试符号、日志、未混淆类名,攻击成本很低。
5.2 Release 包
bash
./gradlew assembleRelease
apksigner verify --verbose app/build/outputs/apk/release/app-release.apk
adb install -r app/build/outputs/apk/release/app-release.apk
Release 包要重点检查:
- 是否关闭
debuggable。 - 是否启用 R8/ProGuard 混淆。
- 是否删除敏感日志。
- 是否启用签名校验和完整性校验。
- 是否启用 Network Security Config。
6. 本章 Demo:环境验收实验
6.1 实验任务
- 编译并安装
ReverseDemodebug 包。 - 用
adb shell dumpsys package记录包名、版本、Activity 和签名摘要。 - 用 jadx 打开 APK,找到
UserCenter.isVip()。 - 用 apktool 反编译 APK,找到 Manifest 和 Smali 目录。
- 用 Burp/mitmproxy 抓到 Demo 的一次接口请求。
- 用
frida-ps -Uai确认能看到 Demo 进程。
6.2 验证表
| 步骤 | 命令或工具 | 通过标准 | 证据文件 |
|---|---|---|---|
| 安装 APK | adb install -r app-debug.apk |
显示 Success |
01-install.txt |
| 查看包信息 | adb shell dumpsys package |
能看到 Activity 和签名 | 02-package.txt |
| 静态查看 | jadx-gui | 能定位 isVip() |
03-jadx-screenshot.png |
| 资源反编译 | apktool | 生成 AndroidManifest.xml 和 smali/ |
04-apktool-log.txt |
| 抓包 | Burp/mitmproxy | 能看到 Demo 请求 | 05-http-sample.txt |
| Frida 枚举 | frida-ps -Uai |
能看到进程 | 06-frida-list.txt |
6.3 常见问题
| 问题 | 原因 | 处理 |
|---|---|---|
adb devices 显示 unauthorized |
设备未授权电脑 | 手机弹窗允许 USB 调试 |
INSTALL_FAILED_UPDATE_INCOMPATIBLE |
已安装不同签名包 | 卸载旧包后重装测试包 |
| jadx 打不开 APK | APK 损坏或路径含特殊字符 | 换短路径,先用 unzip -t 检查 |
| apktool 重打包失败 | 资源解码异常或版本旧 | 升级 apktool,保留错误日志 |
| Frida 连接失败 | server 架构或版本不一致 | 按 ABI 下载同版本 server |
| HTTPS 看不到明文 | App 启用证书绑定或未信任用户证书 | 本章只记录现象,后续章节专门处理 |
7. 本章交付物
完成本章后,建议产出:
text
case-reversedemo/
01-env/
01-install.txt
02-package.txt
03-jadx-screenshot.png
04-apktool-log.txt
05-http-sample.txt
06-frida-list.txt
case-notes.md
case-notes.md 至少包含:实验环境、工具版本、APK 信息、已完成步骤、未完成原因、下一步计划。
8. Android 运行模型
8.1 从源码到 APK 的完整链路
Android 逆向要先理解"源码不是 APK 的最终形态"。一个普通 Kotlin/Java 项目从源码到安装包大致经历:
| 阶段 | 输入 | 输出 | 逆向关注点 |
|---|---|---|---|
| Kotlin/Java 编译 | .kt、.java |
.class |
语法糖会被展开,例如 Kotlin object、默认参数、协程状态机 |
| DEX 转换 | .class |
classes.dex |
方法数、字符串池、类结构、调用引用 |
| 资源编译 | res/、AndroidManifest.xml |
resources.arsc、二进制 XML |
资源 ID、组件声明、字符串 |
| Native 编译 | C/C++ | .so |
JNI、符号、导入函数、架构 ABI |
| 打包 | DEX、资源、so、assets | 未签名 APK | 目录结构、压缩内容 |
| 签名 | 未签名 APK、证书 | 可安装 APK | V1/V2/V3/V4 签名、证书摘要 |
| 安装 | APK | /data/app/...、应用沙箱 |
包名、UID、私有目录、权限 |
学习时要把 jadx、apktool、adb、Frida 分别放在这条链路里理解。jadx 更接近 DEX 反编译,apktool 更接近资源和 Smali,adb 更接近运行环境,Frida 更接近运行时行为。
8.2 Android 进程和沙箱
每个 Android App 默认运行在自己的 Linux UID 下。这个 UID 决定了它能访问哪些文件、能否读写其他应用目录、能否通过 Binder 调用系统服务。
| 概念 | 解释 | 实操观察 |
|---|---|---|
| UID | 应用安装后分配的 Linux 用户 ID | `adb shell dumpsys package |
| 私有目录 | /data/data/<pkg> 或 /data/user/0/<pkg> |
debug 包可尝试 run-as <pkg> |
| 进程名 | 默认是包名,也可为组件单独配置进程 | `adb shell ps -A |
| 权限 | Manifest 申请,运行时授权 | adb shell dumpsys package <pkg> |
| SELinux | 限制系统资源访问 | adb shell getenforce |
逆向时常见误判是:在 root 设备上能看到的文件,不代表普通设备也能看到;debug 包能 run-as,不代表 release 包也能。
8.3 Activity、Service、Receiver、Provider 的逆向意义
| 组件 | 正常用途 | 逆向分析点 | Demo 设计 |
|---|---|---|---|
| Activity | 页面展示和交互 | 是否可被外部启动、是否绕过登录态 | DebugPanelActivity |
| Service | 后台任务、长连接、播放、同步 | 是否导出、是否接受外部 Intent | SyncService |
| BroadcastReceiver | 接收系统或应用广播 | 是否可被伪造广播触发 | DebugReceiver |
| ContentProvider | 跨进程数据访问 | 是否暴露敏感数据 | DemoProvider |
Demo 中可以故意放一个导出 Activity,再在后续章节验证:外部命令能否直接启动,页面是否校验登录态。
bash
adb shell am start -n com.example.reversedemo/.DebugPanelActivity
adb shell am broadcast -a com.example.reversedemo.DEBUG_ACTION
adb shell content query --uri content://com.example.reversedemo.provider/user
8.4 Intent 与 Deep Link
Deep Link 风险不是"能打开页面"本身,而是打开后是否能执行敏感操作。
xml
<activity
android:name=".DeepLinkActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="reversedemo" android:host="open" />
</intent-filter>
</activity>
验证命令:
bash
adb shell am start -a android.intent.action.VIEW -d "reversedemo://open/vip?userId=10002"
检查点:
- 页面是否要求登录。
- 参数是否做白名单校验。
- 是否允许跳转到任意 URL。
- 是否触发支付、提现、绑定账号等敏感动作。
- 错误参数是否导致崩溃或信息泄露。
9. Demo 工程细化
9.1 推荐 Demo 模块划分
text
ReverseDemo/
app/
src/main/java/com/example/reversedemo/
MainActivity.kt
LoginActivity.kt
DebugPanelActivity.kt
UserCenter.kt
Signer.kt
ApiClient.kt
NativeGuard.kt
RiskDetector.kt
StorageLab.kt
src/main/cpp/
native_guard.cpp
src/main/res/xml/
network_security_config.xml
每个类负责一个学习主题:
| 文件 | 学习主题 | 后续章节对应 |
|---|---|---|
UserCenter.kt |
登录和会员判断 | 静态分析、Smali、Frida |
Signer.kt |
请求签名和硬编码密钥 | jadx 搜索、Hook 参数 |
ApiClient.kt |
OkHttp/Retrofit 请求 | 抓包、重放、篡改 |
NativeGuard.kt |
JNI 声明 | Native 分析 |
RiskDetector.kt |
root、debug、proxy 检测 | Hook 和防护复测 |
StorageLab.kt |
SharedPreferences、SQLite、文件 | 本地数据风险 |
9.2 Demo 风险开关设计
为了方便对比,可以把风险点做成可切换模式:
kotlin
object LabSwitch {
const val USE_LOCAL_VIP_CHECK = true
const val USE_CLIENT_SIDE_SECRET = true
const val PRINT_SENSITIVE_LOG = true
const val ENABLE_EXPORTED_DEBUG_PAGE = true
const val ENABLE_NATIVE_ROOT_CHECK = true
}
实验方式:
| 开关 | 打开时验证 | 关闭或修复后复测 |
|---|---|---|
USE_LOCAL_VIP_CHECK |
Hook/Smali 可影响会员页 | 服务端接口拒绝核心权益 |
USE_CLIENT_SIDE_SECRET |
jadx/Frida 能定位签名材料 | 服务端不再依赖客户端长期密钥 |
PRINT_SENSITIVE_LOG |
logcat 可看到敏感字段 | release 无敏感日志 |
ENABLE_EXPORTED_DEBUG_PAGE |
adb 可直接启动 | 导出关闭或入口鉴权 |
ENABLE_NATIVE_ROOT_CHECK |
Native 方法可被 Hook | 检测仅作为风险信号 |
9.3 Demo 后端最小设计
即使是 Android 逆向学习,也建议准备一个最小后端。否则只能验证客户端现象,不能证明服务端是否安全。
接口建议:
| 接口 | 用途 | 风险验证 |
|---|---|---|
POST /login |
返回测试 token | token 存储、日志泄露 |
GET /profile |
查询用户资料 | 越权访问 |
POST /vip/resource |
访问会员资源 | 本地会员判断是否影响服务端 |
POST /order/pay |
模拟下单支付 | 金额篡改、订单归属 |
POST /risk/report |
上报环境检测结果 | 风险信号设计 |
服务端最小校验:
- token 必须有效。
userId由 token 推导,不能信任客户端传入。- 签名必须覆盖 path、method、timestamp、nonce、body hash。
- nonce 只能使用一次。
- 高风险操作需要服务端二次校验。
10. 工具验证深水区
10.1 adb 深入命令
| 任务 | 命令 | 用途 |
|---|---|---|
| 查看安装路径 | adb shell pm path com.example.reversedemo |
定位 base.apk |
| 拉取 APK | adb pull /data/app/.../base.apk |
分析已安装包 |
| 查看应用 UID | `adb shell dumpsys package | grep userId` |
| 查看权限 | `adb shell dumpsys package | grep permission -n` |
| 启动 Activity | adb shell am start -n <pkg>/<activity> |
验证导出页面 |
| 发送广播 | adb shell am broadcast -a <action> |
验证 Receiver |
| 查看崩溃 | adb logcat -b crash |
定位异常 |
| 查看网络代理 | adb shell settings get global http_proxy |
抓包排错 |
| 清除数据 | adb shell pm clear <pkg> |
复现实验初始状态 |
| 卸载应用 | adb uninstall <pkg> |
解决签名冲突 |
10.2 jadx 使用细节
| 操作 | 目的 | 注意 |
|---|---|---|
| 全局搜索字符串 | 找 URL、密钥、错误文案 | 混淆后字符串仍常保留 |
| 搜索方法名 | 找业务入口 | 混淆后方法名可能不可用 |
| 查看调用者 | 建立调用链 | 反射和动态加载可能断链 |
| 导出 Gradle 项目 | 方便全文搜索 | 不能当源码直接运行 |
| 对比 debug/release | 看混淆和日志差异 | release 更接近真实环境 |
10.3 apktool 使用细节
bash
apktool d -f app-debug.apk -o decoded-debug
apktool b decoded-debug -o rebuilt.apk
常见参数:
| 参数 | 用途 |
|---|---|
-f |
覆盖输出目录 |
-o |
指定输出目录或文件 |
--use-aapt2 |
使用 aapt2 构建资源 |
--no-res |
不反编译资源,适合资源异常时 |
--no-src |
不反编译 Smali,只看资源 |
apktool 成功反编译不代表能成功重打包。资源异常、签名差异、版本差异都可能影响安装。
10.4 Frida 环境排错清单
| 现象 | 排查方向 | 处理 |
|---|---|---|
unable to connect |
USB、frida-server 未运行 | 检查 adb devices 和 server |
protocol error |
电脑端和设备端版本不一致 | 下载同版本 frida-server |
permission denied |
server 无执行权限 | chmod 755 |
| 只看到系统进程 | 权限或设备连接异常 | 用 root 环境或调试设备 |
| spawn 后黑屏 | Hook 脚本异常阻塞 | 先注释修改逻辑,只打印 |
| 类找不到 | 类未加载或包名错误 | 先触发页面或枚举 ClassLoader |
11. 实验记录规范
11.1 每次实验必须记录的字段
markdown
# 实验记录
## 基本信息
- 实验名称:
- 实验日期:
- 操作人:
- App 包名:
- App 版本:
- APK 哈希:
- 设备型号:
- Android 版本:
- 是否 root:
## 工具版本
| 工具 | 版本 | 用途 |
## 操作步骤
1.
2.
3.
## 证据
| 证据 | 文件 | 说明 |
## 结论
- 已验证:
- 未验证:
- 限制:
- 下一步:
11.2 APK 哈希记录
bash
shasum -a 256 app-debug.apk
shasum -a 256 app-release.apk
为什么要记录哈希:
- 保证报告和样本对应。
- 避免 debug/release 混用。
- 复测时确认是否同一版本。
- 多人协作时减少证据争议。
11.3 证据命名规范
| 类型 | 命名示例 |
|---|---|
| 命令输出 | 01-adb-devices.txt |
| 截图 | 02-jadx-isvip.png |
| Hook 脚本 | 03-hook-isvip.js |
| Hook 日志 | 04-hook-isvip.log |
| 抓包样本 | 05-profile-request.http |
| 修改前代码 | 06-before.smali |
| 修改后代码 | 07-after.smali |
| 复测矩阵 | 08-retest-matrix.md |
12. 阶段练习
12.1 入门练习
| 练习 | 操作 | 通过标准 |
|---|---|---|
| APK 解压 | unzip -l app.apk |
能解释主要目录 |
| 包名识别 | apkanalyzer 或 Manifest |
能写出包名和版本 |
| 设备安装 | adb install |
App 可启动 |
| 日志查看 | adb logcat |
能过滤 Demo 日志 |
| jadx 查看 | 打开 APK | 能定位 MainActivity |
12.2 进阶练习
| 练习 | 操作 | 通过标准 |
|---|---|---|
| 导出组件验证 | adb shell am start |
能证明是否可外部启动 |
| 本地存储查看 | debug 包 run-as |
能找到测试数据 |
| 网络代理配置 | Burp/mitmproxy | 能抓到 Demo 请求 |
| Frida 枚举 | frida-ps -Uai |
能看到 Demo 进程 |
| Native 提取 | unzip -p |
能提取目标 ABI so |
12.3 专项练习
| 主题 | 任务 | 输出 |
|---|---|---|
| Manifest | 列出所有组件和导出状态 | manifest-audit.md |
| DEX | 找登录、会员、签名方法 | dex-map.md |
| 网络 | 抓 3 个关键接口 | api-flow.md |
| Native | 找 nativeCheck |
jni-map.md |
| 防护 | 对比 debug 和 release | build-compare.md |
13. 验收考试
最终验收要求:
- 在本机完成 Demo 编译和安装。
- 用不少于 8 条 adb 命令完成设备、包、组件、日志、代理检查。
- 用 jadx 定位 3 个关键类:登录、签名、Native 声明。
- 用 apktool 反编译并找到 Manifest 和 Smali。
- 用 Frida 完成进程枚举。
- 用 Burp/mitmproxy 完成至少一次授权 Demo 抓包。
- 输出完整
case-notes.md。
评分表:
| 项目 | 分值 | 扣分点 |
|---|---|---|
| 环境可用 | 20 | 工具版本未记录、设备不可连接 |
| Demo 可运行 | 20 | debug/release 混淆、包名不清 |
| 工具验证 | 20 | jadx/apktool/Frida/Burp 任一缺证据 |
| 记录规范 | 20 | 没有命令输出和截图 |
| 安全边界 | 20 | 未写授权范围或使用真实敏感数据 |
14. 基础、环境与 Demo 工程
本节补充真正的知识点说明。每个知识点都包含需要理解的核心、Demo 中的验证方式和常见误区。
Android 应用基础
| 知识点 | 核心理解 | Demo/验证 | 常见误区 |
|---|---|---|---|
| APK 文件结构 | APK 是带签名的压缩包,核心由 Manifest、DEX、资源、Native 库、assets 和签名信息组成。 | 解压 ReverseDemo,标注 AndroidManifest.xml、classes.dex、lib/arm64-v8a/libreversedemo.so。 |
只看 jadx 代码,忽略 Manifest、资源和 so。 |
| DEX 字节码 | Java/Kotlin 最终会进入 DEX,ART 执行的是 DEX 而不是源码。 | 在 jadx 中对比 Kotlin object 和反编译后的类结构。 |
把反编译代码当作原始源码逐行理解。 |
| Kotlin 编译痕迹 | 空安全、伴生对象、默认参数、协程会生成额外类和辅助方法。 | 搜索 Intrinsics、Companion、DefaultImpls。 |
看到代码复杂就误以为有安全防护。 |
| 应用 UID | Android 用 Linux UID 隔离应用,私有目录权限由 UID 控制。 | 用 dumpsys package 查看 userId,debug 包尝试 run-as。 |
把 root 设备能读到的数据当作普通设备也可读。 |
| 四大组件 | Activity、Service、Receiver、Provider 是外部入口和业务承载点。 | 分别用 am start、am broadcast、content query 验证 Demo 入口。 |
只测试页面,不测试后台组件和 Provider。 |
| Intent 参数 | Intent 的 extras、data、action 都可能由外部构造,不能默认可信。 | 构造 Deep Link 参数打开会员页。 | 把客户端传入的 userId 当作服务端可信身份。 |
| 签名机制 | 签名证明 APK 来源和升级一致性,不加密代码。 | 用 apksigner verify --print-certs 查看证书摘要。 |
认为 APK 签名能阻止反编译。 |
| Debug 与 Release | debug 包偏调试,release 包才接近真实上线状态。 | 分别构建两个包并用 jadx 对比混淆、日志和 Manifest。 | 只分析 debug 包后直接给出正式安全结论。 |
工具与环境
| 知识点 | 核心理解 | Demo/验证 | 常见误区 |
|---|---|---|---|
| adb 设备通道 | adb 提供安装、shell、日志、组件触发和数据清理能力。 | 完成 adb devices、install、logcat、am start。 |
把 adb 能触发当作漏洞结论,不看触发后的业务影响。 |
| jadx 角色 | jadx 适合读 DEX 近似源码和调用关系。 | 定位 UserCenter.isVip()、Signer.sign()。 |
认为 jadx 看不到就代表不存在。 |
| apktool 角色 | apktool 适合资源、Manifest、Smali 和重打包验证。 | 反编译 Demo 并找到 Smali 目录。 | 用 apktool 输出的资源名直接推断业务风险。 |
| apksigner 角色 | apksigner 验证签名方案、证书和重签名结果。 | 对原包和重签名包分别验证。 | 只要能重签名就认为完整性防护失效,还需结合服务端。 |
| Frida 前置条件 | Frida 需要设备连接、server 版本、目标进程和注入时机匹配。 | 用 frida-ps -Uai 枚举 Demo。 |
Hook 成功就直接判业务高危。 |
| Burp/mitmproxy | 抓包工具用于观察和篡改授权测试流量。 | 抓 Demo 的 /api/profile 请求。 |
抓不到包就认为接口一定安全。 |
| Ghidra 角色 | Ghidra 用于 so 反汇编、字符串引用、函数重命名和控制流理解。 | 导入 libreversedemo.so 并搜索 nativeCheck。 |
只看 Java external 方法,不分析 so。 |
| 工具版本记录 | 逆向结果和工具版本强相关,报告必须记录版本。 | 输出 tool-version.md。 |
不记录版本导致复现困难。 |
Demo 工程设计
| 知识点 | 核心理解 | Demo/验证 | 常见误区 |
|---|---|---|---|
| 可控授权样本 | 学习逆向必须使用自建 Demo、开源靶场或授权测试包。 | 在 ReverseDemo 中内置测试账号和测试接口。 |
用第三方未授权 App 练习。 |
| 本地会员判断 | 客户端布尔值可被 Smali 或 Hook 影响。 | 设计 UserCenter.isVip()。 |
把本地判断当作核心权益保护。 |
| 请求签名函数 | 签名函数用于学习参数覆盖范围和密钥边界。 | 设计 Signer.sign(path,timestamp,nonce,body)。 |
认为客户端签名必然安全。 |
| 测试后端 | 没有后端就无法验证核心业务是否真的越权。 | 提供 /login、/profile、/vip/resource。 |
只看客户端 UI 变化,不测接口结果。 |
| Native 检测点 | Native 适合学习 JNI 和环境检测,但不是绝对安全。 | 设计 NativeGuard.nativeCheck()。 |
把逻辑放进 so 就认为不可分析。 |
| 证据目录 | 证据必须按阶段归档,便于复现和交付。 | 建立 01-env、02-static、03-dynamic。 |
截图和命令输出散落,最后无法写报告。 |
使用方式
每个知识点都要落到三件事:能解释原理,能在 ReverseDemo 或授权样本里找到证据,能写出验证结果和修复边界。