# Performing Dynamic Analysis Of Android App

> 使用 Frida、Objection 和 Android Debug Bridge 对 Android 应用进行运行时动态分析， 在执行过程中观察应用行为、拦截函数调用、修改运行时值，并识别静态分析遗漏的漏洞。 适用于测试 Android 应用的运行时安全缺陷、Hook 敏感方法、绕过客户端保护措施 或分析混淆应用。适合 Android 动态分析、运行时 Hook、Frida Android 插桩或实时应用行为分析相关请求。

- Skill: `killvxk/performing-dynamic-analysis-of-android-app` (Agent Skill, multi-file: 8 files)
- Install (CLI): `npx skillmds@latest add killvxk/performing-dynamic-analysis-of-android-app`
- Raw SKILL.md: https://api.skillmd.com/api/skills/killvxk/performing-dynamic-analysis-of-android-app/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- License: Apache-2.0
- Author: killvxk (https://skillmd.com/u/killvxk)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/killvxk/performing-dynamic-analysis-of-android-app

---

# 执行 Android 应用动态分析

## 适用场景

适用于以下情况：
- 静态分析结果需要在实际 Android 设备上进行运行时验证
- 目标应用使用了混淆技术（DexGuard、自定义打包器）导致静态分析效果有限
- 测试需要观察实际 API 调用、解密数据或运行时生成的值
- 评估 Root 检测、防篡改检测或反调试实现

**不适用场景**：未经授权不得在生产环境中使用——动态插桩可能改变应用行为并触发安全告警。

## 前置条件

- 已 root 的 Android 设备或模拟器（Genymotion、带可写系统的 Android Studio AVD）
- 设备上安装了与架构匹配的 Frida 服务端（arm64、x86_64）
- Python 3.10+ 及 `frida-tools` 和 `objection` 包
- 已配置 ADB 且设备已连接
- 目标 APK 已安装在设备上

## 工作流程

### 步骤 1：在 Android 设备上设置 Frida 服务端

```bash
# 检查设备架构
adb shell getprop ro.product.cpu.abi
# 输出：arm64-v8a

# 从 GitHub releases 下载匹配的 Frida 服务端
# https://github.com/frida/frida/releases
# 推送到设备
adb push frida-server-16.x.x-android-arm64 /data/local/tmp/frida-server
adb shell chmod 755 /data/local/tmp/frida-server
adb shell /data/local/tmp/frida-server &

# 验证 Frida 连接
frida-ps -U
```

### 步骤 2：枚举应用攻击面

```bash
# 列出所有包
frida-ps -U -a

# 附加 Objection 进行高级别探测
objection --gadget com.target.app explore

# 列出活动、服务、广播接收器
android hooking list activities
android hooking list services
android hooking list receivers

# 列出已加载的类
android hooking list classes
android hooking search classes com.target.app
```

### 步骤 3：Hook 敏感方法

```bash
# Hook 类的所有方法
android hooking watch class com.target.app.auth.LoginManager

# Hook 特定方法并转储参数
android hooking watch class_method com.target.app.auth.LoginManager.authenticate --dump-args --dump-return

# Hook 加密操作
android hooking watch class javax.crypto.Cipher --dump-args
android hooking watch class java.security.MessageDigest --dump-args

# Hook 网络调用
android hooking watch class okhttp3.OkHttpClient --dump-args
android hooking watch class java.net.URL --dump-args
```

### 步骤 4：编写自定义 Frida 脚本进行深度分析

```javascript
// hook_crypto.js - 拦截加密/解密操作
Java.perform(function() {
    var Cipher = Java.use("javax.crypto.Cipher");

    Cipher.doFinal.overload("[B").implementation = function(input) {
        var mode = this.getAlgorithm();
        console.log("[Cipher] 算法: " + mode);
        console.log("[Cipher] 输入: " + bytesToHex(input));

        var result = this.doFinal(input);
        console.log("[Cipher] 输出: " + bytesToHex(result));
        return result;
    };

    function bytesToHex(bytes) {
        var hex = [];
        for (var i = 0; i < bytes.length; i++) {
            hex.push(("0" + (bytes[i] & 0xFF).toString(16)).slice(-2));
        }
        return hex.join("");
    }
});
```

```bash
# 执行自定义 Frida 脚本
frida -U -f com.target.app -l hook_crypto.js --no-pause
```

### 步骤 5：绕过 Root 检测

```javascript
// root_bypass.js - 常见 Root 检测绕过
Java.perform(function() {
    // 绕过 RootBeer 库
    var RootBeer = Java.use("com.scottyab.rootbeer.RootBeer");
    RootBeer.isRooted.implementation = function() {
        console.log("[RootBeer] isRooted() 已绕过");
        return false;
    };

    // 绕过基于文件的通用 Root 检测
    var File = Java.use("java.io.File");
    var originalExists = File.exists;
    File.exists.implementation = function() {
        var path = this.getAbsolutePath();
        var rootPaths = ["/system/app/Superuser.apk", "/system/xbin/su",
                         "/sbin/su", "/system/bin/su", "/data/local/bin/su"];
        if (rootPaths.indexOf(path) >= 0) {
            console.log("[Root] 已阻断检测: " + path);
            return false;
        }
        return originalExists.call(this);
    };

    // 绕过 SafetyNet/Play Integrity
    try {
        var SafetyNet = Java.use("com.google.android.gms.safetynet.SafetyNetApi");
        console.log("[SafetyNet] 发现该类 - 可能需要额外绕过");
    } catch(e) {}
});
```

### 步骤 6：运行时分析网络通信

```javascript
// network_monitor.js - 监控所有 HTTP 请求
Java.perform(function() {
    // Hook OkHttp3
    try {
        var OkHttpClient = Java.use("okhttp3.OkHttpClient");
        var Interceptor = Java.use("okhttp3.Interceptor");
        var Chain = Java.use("okhttp3.Interceptor$Chain");

        console.log("[OkHttp] 正在监控网络请求...");

        var Request = Java.use("okhttp3.Request");
        Request.url.implementation = function() {
            var url = this.url();
            console.log("[OkHttp] URL: " + url.toString());
            return url;
        };
    } catch(e) {
        console.log("[OkHttp] 未找到，尝试 HttpURLConnection");
    }

    // Hook HttpURLConnection
    var URL = Java.use("java.net.URL");
    URL.openConnection.overload().implementation = function() {
        console.log("[URL] 打开: " + this.toString());
        return this.openConnection();
    };
});
```

### 步骤 7：提取解密数据和机密

```bash
# 使用 Objection 快速提取
objection --gadget com.target.app explore

# 转储 Android Keystore 条目
android keystore list
android keystore dump

# 在堆中搜索敏感对象
android heap search instances com.target.app.model.User
android heap evaluate <handle> "JSON.stringify(clazz)"

# 内存字符串搜索
memory search "password" --string
memory search "api_key" --string
```

## 核心概念

| 术语 | 定义 |
|------|------|
| **动态插桩** | 通过向运行中的进程注入代码，在运行时修改应用行为 |
| **方法 Hook** | 替换或包装函数实现，以拦截参数和返回值 |
| **Frida 服务端** | 运行在目标设备上的守护进程，接收来自主机的插桩命令 |
| **Dalvik/ART 运行时** | Android 运行时环境；Frida 在 ART 级别 Hook Java/Kotlin 方法 |
| **堆检查** | 检查应用内存堆中的活跃对象，以提取运行时数据 |

## 工具与系统

- **Frida**：动态插桩工具包，用于向原生 Android 进程注入 JavaScript
- **Objection**：高级 Frida 封装，提供预置的 Android 和 iOS 安全测试命令
- **frida-trace**：自动化方法追踪工具，用于快速侦察应用行为
- **Drozer**：Android 安全评估框架，用于测试 IPC 和导出组件
- **Android Studio Profiler**：CPU、内存和网络活动的运行时监控

## 常见问题

- **Frida 版本不匹配**：设备上的 Frida 服务端必须与主机上的 frida-tools 版本匹配，版本不匹配会导致连接失败。
- **反 Frida 检测**：某些应用通过检查 Frida 服务端进程、扫描内存中的 Frida 特征或监控 `/proc/self/maps` 来检测 Frida。使用 Frida Gadget 注入或自定义服务端构建版本。
- **混淆类名**：应用 ProGuard/R8 后，类名和方法名会被缩短（如 `a.b.c.d()`）。使用 `android hooking search classes` 发现实际运行时名称。
- **多 DEX 应用**：跨多个 DEX 文件的大型应用可能在启动时未加载所有类。在应用完全初始化后，Hook 类加载器或使用 `Java.enumerateLoadedClasses()`。

