乐于分享
好东西不私藏

安卓逆向系列 10:实战综合——某出行 App 接口逆向全流程

安卓逆向系列 10:实战综合——某出行 App 接口逆向全流程

前九篇学了所有单项技能,本篇把它们串起来,完整还原一次真实逆向过程。目标:某出行类 App(授权测试环境),任务:还原其航班查询接口的签名算法。


⚠️ 郑重声明: 本文所有操作均在授权测试环境中完成,使用自有测试账号,不涉及任何真实用户数据。本系列内容仅供安全研究与学习,请遵守相关法律法规。



第一阶段:侦察收集

1.1 获取 APK

# 方式一:从已安装的手机提取
adb shell pm path com.example.travel
# output: package:/data/app/~~xxx/com.example.travel-xxx/base.apk
adb pull /data/app/~~xxx/com.example.travel-xxx/base.apk ./target.apk

# 方式二:apkpure.com 下载

1.2 识别加固类型

apkid target.apk
[RESULT] target.apk!classes.dex
  compiler : dex compiler (Android Studio)
  packer   : Bangbang Enterprise - Shanghai (梆梆加固)

结论: 梆梆加固,整体加密型,可用 frida-dexdump 脱壳。

1.3 抓包初探

配置好 Burp 代理,打开 App 搜索航班,抓到以下请求:

POST /api/v3/flights/search HTTP/1.1
Host: api.example-travel.com
Content-Type: application/json
X-App-Token: eyJhbGc...(JWT 格式)
X-Timestamp: 1713661234
X-Sign: 8f4a2b9c...(64位hex,疑似 HMAC-SHA256)

{"from":"SHA","to":"PEK","date":"2024-04-21","adults":1}

关注点:

  • X-Sign:64位hex → HMAC-SHA256 可能性大

  • X-Timestamp:Unix 时间戳,防重放

  • X-App-Token:JWT,需要分析生成逻辑


第二阶段:砸壳 + 静态分析

2.1 脱壳

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

# 打开 App,然后执行脱壳
frida-dexdump -U-f com.example.travel

# 输出(示例)
[*] Scanning for classes...
[+] Dump ./com.example.travel_0x12345678.dex (2.8 MB)
[+] Dump ./com.example.travel_0x23456789.dex (1.2 MB)
[+] Dump ./com.example.travel_0x34567890.dex (0.9 MB)

2.2 jadx 静态分析

jadx-gui com.example.travel_0x12345678.dex

搜索策略:

① 全局搜索 "X-Sign"
→ 找到: headers.put("X-Sign", RequestSigner.sign(body, timestamp))

② 进入 RequestSigner.sign()
→ 找到核心逻辑

还原的代码:

publicclassRequestSigner {
privatestaticfinalStringAPP_SECRET="tr4vel_s3cret_2024";

publicstaticStringsign(Stringbody, longtimestamp) {
// 拼接原始字符串
Stringraw=body+"|"+timestamp+"|"+APP_SECRET;
// HMAC-SHA256
try {
Macmac=Mac.getInstance("HmacSHA256");
SecretKeySpeckeySpec=newSecretKeySpec(
APP_SECRET.getBytes("UTF-8"), "HmacSHA256"
            );
mac.init(keySpec);
byte[] result=mac.doFinal(raw.getBytes("UTF-8"));
returnbytesToHex(result);
        } catch (Exceptione) {
return"";
        }
    }
}

关键发现:

  • 签名格式:body + "|" + timestamp + "|" + APP_SECRET

  • 算法:HMAC-SHA256

  • 密钥:tr4vel_s3cret_2024(硬编码在代码中!)


第三阶段:动态验证

3.1 Frida Hook 确认

// verify_sign.js
Java.perform(function() {
varRequestSigner=Java.use("com.example.travel.http.RequestSigner");

RequestSigner.sign.implementation=function(body, timestamp) {
console.log("=== RequestSigner.sign() ===");
console.log("body:      "+body);
console.log("timestamp: "+timestamp);

varresult=this.sign(body, timestamp);
console.log("sign:      "+result);
console.log("===========================");

returnresult;
    };
});
frida -U-f com.example.travel -l verify_sign.js

输出(触发搜索后):

=== RequestSigner.sign() ===
body:      {"from":"SHA","to":"PEK","date":"2024-04-21","adults":1}
timestamp: 1713661234
sign:      8f4a2b9c3e1d7a5f...(与抓包一致 ✅)
===========================

3.2 绕过 SSL Pinning

# App 有证书固定,先用 objection 绕过
objection -g com.example.travel explore
# 进入 shell 后:
android sslpinning disable

第四阶段:Python 复现

4.1 完整签名代码

importhmac
importhashlib
importtime
importjson
importrequests

APP_SECRET = "tr4vel_s3cret_2024"
BASE_URL   = "https://api.example-travel.com"

defsign(body: str, timestamp: int) ->str:
"""生成请求签名"""
raw = f"{body}|{timestamp}|{APP_SECRET}"
h = hmac.new(
APP_SECRET.encode("utf-8"),
raw.encode("utf-8"),
hashlib.sha256
    )
returnh.hexdigest()

defsearch_flights(from_city: str, to_city: str, date: str):
"""查询航班"""
timestamp = int(time.time())
body = json.dumps({
"from": from_city,
"to": to_city,
"date": date,
"adults": 1
    }, separators=(',', ':'))

headers = {
"Content-Type": "application/json",
"X-Timestamp": str(timestamp),
"X-Sign":      sign(body, timestamp),
    }

resp = requests.post(
f"{BASE_URL}/api/v3/flights/search",
data=body,
headers=headers,
timeout=10
    )
returnresp.json()

# 调用测试
result = search_flights("SHA", "PEK", "2024-04-21")
print(json.dumps(result, ensure_ascii=False, indent=2))

五、踩过的坑与经验总结

坑现象解决方案
frida-dexdump 脚本执行到一半 App 崩溃加固有心跳检测加快 dump 速度,减少停留时间
jadx 反编译结果缺少关键方法函数被内联或混淆配合 Frida 动态追踪调用链
时间戳校验失败服务端有 ±5 分钟窗口同步手机时间或调整 ts
请求成功但数据为空需要登录态 Token先 Hook 登录接口拿 Token

六、安卓逆向学习路线图

入门阶段(1-2 周)
├── 理解 APK 结构
├── jadx 基本使用
└── ADB 常用命令

进阶阶段(2-4 周)
├── Frida Java Hook 实战
├── SSL Pinning 绕过
└── 基础抓包分析

高级阶段(1-3 月)
├── Native 层 Hook
├── 砸壳与加固对抗
├── 算法逆向
└── 反检测对抗

专家阶段(持续积累)
├── IDA Pro / Ghidra 静态分析
├── ARM 汇编调试
├── VMP/定制虚拟机分析
└── 漏洞挖掘与利用

七、工具链汇总

分类工具用途
静态分析jadx、apktool反编译、资源提取
动态分析Frida、objectionHook、运行时分析
脱壳frida-dexdump、BlackDexAPK 脱壳
抓包Burp Suite、r0capture流量分析
加固识别APKiD快速识别加固类型
反编译辅助IDA Pro、GhidraNative 层分析

八、推荐学习资源

  • Frida 官方文档

  • jadx GitHub

  • Android 逆向工程 Wiki

  • 看雪论坛(国内最活跃的逆向社区)

  • CTF Wiki Android 章节

  • 移动安全框架 MobSF


感谢阅读完整个系列! 从工具链到实战,从 Java Hook 到 Native 分析,希望这 10 篇文章能成为你安卓逆向路上的可靠参考。

系列完结 · 仅供安全研究与授权测试使用

相关学习资料