
某App 抓包全流程技术文档
对 Android 端 xxx App 进行 HTTPS 抓包,获取其商品列表、商品详情、购买信息等核心业务 API 的请求与响应数据。

对 Android 端 xxx App 进行 HTTPS 抓包,获取其商品列表、商品详情、购买信息等核心业务 API 的请求与响应数据。
对 Android 端 xxx App 进行 HTTPS 抓包,获取其商品列表、商品详情、购买信息等核心业务 API 的请求与响应数据。
xxx App 采用了梆梆安全加固方案(Bangcle),拥有业内顶级的多层防护体系,几乎封堵了所有常规抓包手段:
| 防护层 | 技术实现 | 效果 |
|---|---|---|
| 代理检测 | libbangcle_risk.so 检测系统 HTTP 代理设置 | 检测到代理后弹窗退出 |
| VPN 检测 | 检测 VPN 网络接口(tun0 等) | 检测到 VPN 后弹窗退出 |
| SSL Pinning | 代码级 SSL 证书锁定(非 network_security_config.xml) | HTTPS 请求无法被中间人解密 |
| 注入检测 | 检测 Frida、Xposed 等注入框架的进程特征 | 检测到后 native crash(fault addr 0xdeadcab1) |
| Root 检测 | 检测 su 二进制、Magisk 等 Root 痕迹 | 检测到后弹窗"设备异常"退出 |
| 模拟器检测 | libemulator_check.so + XOX SDK 多层检测 | x86 翻译层/内核特征/硬件特征全覆盖 |
| 完整性校验 | APK 签名校验 + SO 文件完整性校验 | 修改 APK 或 SO 后闪退 |
| 风控 SDK | com.bangcle.everisk 运行时风控引擎 | 采集设备信息并动态判定风险 |
核心挑战:这些防护层相互配合,要成功抓包必须同时绕过所有防护,单独突破任何一层都不够。
| 设备 | 规格 | 说明 |
|---|---|---|
| Mac | Apple Silicon (macOS 15) | 抓包主机 |
| Pixel 4 XL | Android 11, 序列号 99111FFBA00BP3 | 目标设备(必须真机,模拟器无法绕过检测) |
| USB 数据线 | USB-C | 连接 Mac 和手机 |
| 软件 | 版本 | 用途 |
|---|---|---|
| Magisk | v28.1 (28100) | Root 方案 + 模块管理 |
| Zygisk | 内置于 Magisk 28.1 | Shamiko 运行依赖 |
| Shamiko | v1.2.1 (383) | Root 隐藏(blacklist 模式) |
| LSPosed | v1.9.2 | Xposed 框架(Zygisk 版,仅安装未对茅台启用模块) |
| xxx | v1.9.4 | 目标 App |
| 软件 | 版本 | 用途 |
|---|---|---|
| ADB | Android SDK Platform-Tools | 设备通信 |
| mitmproxy / mitmweb | v12.2.1 | HTTPS 中间人代理 + Web 可视化界面 |
| Python | 3.12+ | 脚本工具 & ELF Patch |
Zygisk: 已启用
Enforce DenyList: 已关闭 ← Shamiko 要求必须关闭
DenyList: com.xxx.mall 及所有子进程已加入
Magisk App 包名: 已隐藏(随机化)
为什么用 Shamiko 而不是 DenyList?
Magisk 自带的 DenyList 隐藏能力较弱,梆梆安全的检测能穿透。Shamiko 通过 Zygisk 在更底层实现进程隔离,能有效隐藏 Root 和 Magisk 痕迹。但 Shamiko 要求关闭 Enforce DenyList(由 Shamiko 自己接管)。
在找到最终方案前,经历了大量尝试。记录这些失败对理解 App 的防护强度非常有价值。
| # | 方案 | 失败原因 |
|---|---|---|
| 1 | MuMu 模拟器 + Frida hook | XOX SDK 检测到 x86 翻译层,native crash |
| 2 | MuMu + LSPosed + Device Emulator | XOX native 层检测绕不过 |
| 3 | MuMu + Shamiko | 同上 |
| 4 | AVD ARM64 (API 34, 干净) | 弹窗"非安全场景"(模拟器内核特征被检测) |
| 5 | AVD + Magisk + LSPosed | XOX 检测到 root,crash |
| 6 | AVD + Frida Server | 被检测,crash (state=543) |
| 7 | AVD + Frida Gadget (改名 libhelper.so) | XOX 通过文件内容特征识别 Frida,crash |
| 8 | AVD + resetprop 改属性 | 部分属性改成功,但内核级特征改不了 | | 9 | AVD + patch libemulator_check.so | 绕过完整性校验后,libhaotiansec.so 内部还有检测 | | 10 | AVD + patch 所有安全 so 的 init_array | 加固壳不工作,app 卡住 | | 11 | AVD + 选择性 patch init_array | 每个 init 函数都是加固壳需要的,不能动 |
结论:模拟器路线完全不可行,必须使用真机。
| # | 方案 | 结果 |
|---|---|---|
| 1 | Magisk 23.0 + MagiskHide | 旧版 XOX 检测到 root,crash |
| 2 | Magisk 26.4 + DenyList | 不够强,还是被检测 |
| 3 | Magisk 26.4 + Shamiko v1.0.1 | 还是被检测 |
| 4 | Magisk 28.1 + Shamiko v1.2.1 | 旧版 正常运行 ✓ |
| 5 | 更新apk后 | 新版 everisk 检测到异常,10 秒退出 |
| 方案 | 失败原因 |
|---|---|
| mitmproxy + 系统代理 | App 检测到代理设置 |
| VPN 模式抓包 | App 检测到 VPN |
| Xposed SSL Bypass 模块 | 被 App 检测到 Xposed 注入,直接退出 |
最终的方案是多层协同绕过,每一层解决一个特定的防护问题,且不触发其他防护:
┌─────────────────────────────────────────────────────┐
│ i茅台 App │
├─────────────────────────────────────────────────────┤
│ Layer 5: 风控 Activity 禁用 │ ← pm disable
│ Layer 4: 代理/VPN 检测绕过 │ ← patch libbangcle_risk.so
│ Layer 3: SSL Pinning 绕过 │ ← patch libssl.so
│ Layer 2: Root 隐藏 │ ← Shamiko v1.2.1
│ Layer 1: Root 权限 │ ← Magisk 28.1
├─────────────────────────────────────────────────────┤
│ Android 11 (Pixel 4 XL) │
└─────────────────────────────────────────────────────┘
```###
5.1 Layer 1 & 2:Root + Root 隐藏
**Magisk 28.1 + Shamiko v1.2.1 (blacklist mode)**
- Magisk 提供 root 权限和模块管理
- Shamiko 在 Zygisk 层面对 i茅台进程隐藏所有 Root 痕迹
- DenyList 中加入 `com.xxx.mall` 及其所有子进程
- Magisk App 自身包名也做了隐藏(随机化)
### 5.2 Layer 3:SSL Pinning 绕过 —— Patch libssl.so + Mount Bind
这是最关键的技术环节。app没有使用 `network_security_config.xml`,SSL Pinning 在代码中通过 BoringSSL 的验证函数实现。
#### 原理
Android 11 使用 **conscrypt APEX** 模块提供 SSL/TLS 实现,其中的 `libssl.so` 包含证书验证函数。通过 patch 这些函数,可以让所有 SSL 验证都变成"不验证"模式。
#### 步骤
**① 从手机拉取原始 libssl.so**
```bash
# 找到 conscrypt APEX 中的 libssl.so
adb shell "su -c 'find /apex/com.android.conscrypt -name libssl.so'"
# 输出: /apex/com.android.conscrypt/lib64/libssl.so
# 拉取到本地
adb shell "su -c 'cp /apex/com.android.conscrypt/lib64/libssl.so /data/local/tmp/libssl_orig.so && chmod 644 /data/local/tmp/libssl_orig.so'"
adb pull /data/local/tmp/libssl_orig.so /tmp/libssl_orig.so
② 用 Python 脚本 Patch(patch_libssl.py)
脚本解析 ELF 文件的动态符号表,找到 4 个 SSL 验证函数,将每个函数的第一条 ARM64 指令替换为 MOV W1, #0:
# ARM64 指令: mov w1, #0
# 将 SSL 验证模式参数强制设为 SSL_VERIFY_NONE (0)
MOV_W1_0 = struct.pack('<I', 0x52800001)
# 目标函数
targets = [
'SSL_CTX_set_verify', # 设置 SSL 上下文验证模式
'SSL_set_verify', # 设置 SSL 连接验证模式
'SSL_CTX_set_custom_verify', # 设置自定义验证回调
'SSL_set_custom_verify', # 设置自定义验证回调
]
为什么 patch W1 而不是直接 RET? ARM64 调用约定中 W1 是第二个参数(mode),将其设为 0 即 SSL_VERIFY_NONE。函数仍然正常执行后续逻辑(设置回调指针等),只是验证模式变成了"不验证",这比直接 RET 更稳定。
③ 推送并用 Mount Bind 替换
# 推送 patched 文件到手机
adb push /tmp/libssl_patched.so /data/local/tmp/libssl_patched.so
# 使用 Magisk 的 --mount-master 进行 mount bind
# 这样不修改原始文件,绕过完整性校验
adb shell "su --mount-master -c 'mount --bind /data/local/tmp/libssl_patched.so /apex/com.android.conscrypt/lib64/libssl.so'"
④ 验证 mount bind 生效
# 比较 MD5,应该一致
adb shell "su -c 'md5sum /apex/com.android.conscrypt/lib64/libssl.so /data/local/tmp/libssl_patched.so'"
为什么用 Mount Bind 而不是直接替换文件?
APEX 模块是只读挂载的,无法直接修改文件。Mount Bind 在文件系统层面将一个路径"覆盖"到另一个路径上,读取目标路径时实际读到的是我们的 patched 文件。这完全不影响原始文件,App 的完整性校验检查的是 APK 签名,不会发现 SO 被替换了。
新版增加了 libbangcle_risk.so(梆梆风控 SDK),其中包含代理和 VPN 检测逻辑。
patch_bangcle.py)脚本解析 ELF 的 DYNAMIC 段(因为 section header 被混淆),通过字符串引用搜索找到 JNI_OnLoad 函数入口,patch 为直接返回 JNI_VERSION_1_6:
# 找到 JNI_OnLoad 的函数序言 (STP x29, x30, [sp, #imm]!)
# 替换为:
# movz w0, #6 → 0x528000c0
# movk w0, #1, lsl #16 → 0x72a00020 (w0 = 0x10006 = JNI_VERSION_1_6)
# ret → 0xd65f03c0
同时 patch .init_array 和 DT_INIT 中的初始化函数为 RET,禁止风控 SDK 在库加载时执行任何初始化逻辑。
部署方式同样用 Mount Bind:
adb push /tmp/libbangcle_risk_patched.so /data/local/tmp/libbangcle_risk_patched.so
adb shell "su --mount-master -c 'mount --bind /data/local/tmp/libbangcle_risk_patched.so /data/app/<包路径>/lib/arm64/libbangcle_risk.so'"
```###
5.4 Layer 5:禁用 Everisk 风控 Activity
即使 patch 了 `libbangcle_risk.so`,风控 SDK 仍可能通过 Java 层检测到异常并启动退出页面。解决方案极其巧妙——**直接禁用风控 Activity 组件**:
```bash
adb shell "su -c 'pm disable com.moutai.mall/com.bangcle.everisk.core.c'"
原理:风控检测发现异常后,会尝试启动 com.bangcle.everisk.core.c 这个 Activity 来显示"设备异常"的退出页面。禁用这个组件后,Activity 无法启动,但 App 的主进程不会因此崩溃——它只是无法显示退出弹窗了,于是静默地继续运行。
注意:每次重启手机后需要重新执行此命令。
mitmproxy 的 CA 证书通过 Magisk 模块安装到系统级信任存储:
# 在手机上创建 Magisk 模块目录
mkdir -p /data/adb/modules/mitm_cert/system/etc/security/cacerts/
# 将 mitmproxy CA 证书(~/.mitmproxy/mitmproxy-ca-cert.cer)
# 转换为 Android 系统证书格式并推送到该目录
# 文件名格式: <hash>.0
安装后重启,证书出现在"系统" → “安全” → "信任的凭据"中。
所有绕过措施准备好后,每次抓包的操作流程如下:
# 1. 连接手机(USB)
adb devices -l
# 确认: 99111FFBA00BP3 device usb:0-1 ...
# 2. 禁用风控 Activity(每次重启后需要)
adb shell "su -c 'pm disable com.xxx.mall/com.bangcle.everisk.core.c'"
# 3. 验证 SSL mount bind 是否还在(重启后会失效)
adb shell "su -c 'md5sum /apex/com.android.conscrypt/lib64/libssl.so /data/local/tmp/libssl_patched.so'"
# 如果 MD5 不一致,需要重新 mount bind:
# adb shell "su --mount-master -c 'mount --bind /data/local/tmp/libssl_patched.so /apex/com.android.conscrypt/lib64/libssl.so'"
# 4. 设置 USB 端口转发
adb reverse tcp:8080 tcp:8080
# 5. 设置系统代理
adb shell "settings put global http_proxy 127.0.0.1:8080"
# 6. 启动 mitmweb(带可视化 Web 界面)
mitmweb -p 8080 --web-port 8081 \
--set block_global=false \
--set web_password='你的密码' \
--showhost \
--no-web-open-browser
# 7. 浏览器打开 http://127.0.0.1:8081 查看抓包界面
# 8. 启动 App
adb shell "monkey -p com.xxx.mall -c android.intent.category.LAUNCHER 1"
```###
6.2 代理工作原理
┌──────────────┐ USB (adb reverse) ┌──────────────┐ │ Pixel 4 XL │ ──── 127.0.0.1:8080 ──→ │ Mac │ │ │ │ │ │ App │ │ mitmweb │ │ ↓ 系统代理 │ │ :8080 代理 │ │ 127.0.0.1 │ │ :8081 Web UI │ │ :8080 │ │ │ └──────────────┘ └──────────────┘ ↑ ↑ patched libssl.so 浏览器查看流量 (SSL 验证已禁用) http://127.0.0.1:8081
**关键点**:
- `adb reverse tcp:8080 tcp:8080` 让手机的 `127.0.0.1:8080` 映射到 Mac 的 `8080` 端口
- 系统代理设为 `127.0.0.1:8080`,所有 HTTP(S) 流量都走代理
- 因为 `libssl.so` 已被 patch,App 不会拒绝 mitmproxy 的证书
- 因为 `libbangcle_risk.so` 已被 patch,App 不会检测到代理
### 6.3 停止抓包
```bash
# 关闭系统代理
adb shell "settings put global http_proxy :0"
# 移除端口转发
adb reverse --remove tcp:8080
# 停止 mitmweb (Ctrl+C 或)
kill $(pgrep -f mitmweb)
```##
七、已抓到的关键 API
### 7.1 商品详情(静态 CDN,无需登录)
```GET
https://static.xxxx.com.cn/mt-backend/xhr/front/mall/item/detailV2/{spuId}
```-
返回:商品名称、价格、SKU 信息、图片、评论数据
### 7.2 购买信息(H5 WebView,需登录)
```POST
https://h5.xxx.com.cn/xhr/front/mall/item/purchaseInfoV2
Body: {"hot": true, "spuId": "IMTP1000313", "jt": "anonymous"}
```-
返回:库存数量、开售时间、限购数量、购买资格
- **注意**:此接口使用 H5 WebView 的 Token(`MT-Token-Wap`),与 Native App 的 `MT-Token` 不同
### 7.3 认证方式区别
| API 来源 | Token 类型 | 传递方式 |
| --- | --- | --- |
| Native App API (app.xxx.com.cn) | MT-Token | HTTP Header |
| H5 WebView API (h5.xxx.com.cn) | MT-Token-Wap | Cookie |
Token 需要从抓包中的 Cookie 字段获取。
## 八、自动化脚本
### 8.1 项目文件结构
frida/ ├── patch_libssl.py # Patch libssl.so 脚本 ├── patch_bangcle.py # Patch libbangcle_risk.so 脚本 ├── export_apis.py # mitmproxy 流量导出脚本 ├── captured_apis.json # 抓包导出的 API 数据 ├── PROJECT_STATUS.md # 项目状态文档 ├── TECHNICAL_GUIDE.md # 本文档 └── login/ ├── login.py # 登录 & 签名工具 ├── credentials.json # Native App 登录凭证 ├── h5_token.json # H5 WebView Token ├── item_detail.py # 商品详情 API 调用脚本 ├── get_items.py # 资源配置获取 └── shop_items.py # 门店商品查询
8.2 使用方法
```bash
# 查询商品详情和购买信息
cd frida/login
python3 item_detail.py
# 查询单个商品
python3 item_detail.py product_id
```##
九、注意事项
### 9.1 重启后需要恢复
手机重启后以下设置会失效,需要重新执行:
1. **Mount Bind**:`libssl.so` 和 `libbangcle_risk.so` 的 mount bind 都会丢失
2. **风控 Activity 禁用**:`pm disable` 的状态会被重置
3. **系统代理**:需要重新设置
### 9.2 时间同步
手机没有 SIM 卡时自动时间同步可能不工作,需要手动同步:
```bash
adb shell "su -c 'date $(date +%m%d%H%M%Y.%S)'"
```###
9.3 mitmweb 认证
mitmproxy 12.x 默认对 Web UI 启用认证,启动时需要设置 `--set web_password='密码'`,然后在浏览器中输入密码。
### 9.4 Token 有效期
```-
Native Token (`MT-Token`):有有效期,过期需要重新登录
- H5 Token (`MT-Token-Wap`):每次 App 打开 WebView 时自动获取,需要从抓包中更新
```##
十、技术原理总结
### 为什么这个方案能成功?
1. **真机 + Shamiko**:从进程级别隐藏 Root,梆梆安全无法通过常规检测手段发现
2. **Mount Bind**:在文件系统层面替换 SO,不修改 APK,绕过完整性校验
3. **Patch 验证函数而非直接 RET**:保持函数正常执行,只改变验证模式参数,减少崩溃风险
4. **禁用风控 Activity**:不阻止检测本身,而是阻止检测结果的"执行"——让 App 检测到异常但无法退出
5. **USB + adb reverse**:代理流量走 USB 而非 WiFi,减少网络层面的检测面
### 每一层的不可替代性
- 去掉 Shamiko → Root 被检测 → App 退出
- 去掉 libssl patch → SSL Pinning → 无法解密 HTTPS
- 去掉 bangcle patch → 代理被检测 → App 退出
- 去掉 pm disable → 风控弹窗 → App 强制退出
- 去掉 mitmproxy CA → 证书不被信任 → 连接失败
**五层缺一不可。**