在对移动端 App 进行数据抓包时,常会遇到以下问题:
-
配置了代理后,App 提示**“网络连接不可用”**,Charles 中出现大量红锁或
SSLHandshake握手失败。 -
配置了代理后,网页能正常抓包,但目标 App 的流量完全不在 Charles 中显示。
-
针对 Flutter 开发的 App,普通的系统证书信任和代理设置完全无效。
本教程将深入剖析这些防御机制的原理,并提供从易到难的终极解决方案。
目录
1. 突破“绕过系统代理/直连”防御
1.1 防御原理
许多 App 在网络请求代码中,显式将代理设置为了 NO_PROXY(直连模式),或者在 iOS 中通过底层 API 绕过了系统全局 Wi-Fi 代理设置。这导致即使你在手机 Wi-Fi 属性中配置了 Charles 的 IP 和端口,App 的流量依然会直接发送到服务器,不经过 Charles。
1.2 解决方案:VPN 虚拟网卡强力劫持
既然 App 能够绕过 Wi-Fi 的 HTTP 代理,我们可以在手机本地建立一个虚拟的 VPN 通道。VPN 通道工作在网络层,会强行接管手机内的所有 TCP/UDP 流量,并将其打包转发给 PC 端的 Charles,使 App 无法通过 NO_PROXY 绕过。
graph TD
App[目标 App 流量] -->|直连或拒绝代理| VPN[手机本地 VPN 软件]
VPN -->|强制接管流量并打包| Charles[PC 端 Charles 8888]
Charles -->|转发请求| Server[业务服务器]
🛠️ iOS 设备配置步骤(推荐 Shadowrocket)
-
在 iPhone 上安装 Shadowrocket(小火箭) 或 Surge / Loon。
-
打开小火箭,点击右上角
+添加服务器。 -
配置参数:
* 类型 (Type):选择 HTTP 或 SOCKS5。
* 服务器 (Address):填写电脑的局域网 IP 地址。
* 端口 (Port):填写 Charles 的端口(默认 8888)。
-
保存配置,在小火箭主页下方将 全局路由 (Global Routing) 修改为
代理 (Proxy)。 -
开启小火箭的连接开关,允许系统创建 VPN。
-
此时,App 的流量就会被强制导入 Charles。
🛠️ Android 设备配置步骤(推荐 Postern)
-
在安卓手机上安装 Postern 软件。
-
打开 Postern,点击
配置代理服务器,添加你的 PC 端 Charles IP 与端口8888,类型选择SOCKS5并保存。 -
点击
配置规则,添加一条规则:类型选择匹配所有,动作选择通过代理连接,代理服务器选择刚刚添加的配置,保存。 -
开启 Postern 的 VPN 代理服务即可。
2. 突破 SSL Pinning(证书绑定)
2.1 防御原理
SSL Pinning(证书绑定) 是一种高强度的安全校验机制。App 在发起 HTTPS 请求时,只信任其二进制包内预埋的特定证书公钥。当它检测到当前连接使用的是 Charles 自签名的根证书时,出于防中间人攻击的目的,会立即切断网络连接。
2.2 解决方案一:使用 Root / 越狱插件(一键全局绕过)
如果你的手机已经具备 Root 权限(Android)或越狱状态(iOS),使用现成的系统级 Hook 插件是最稳妥、快捷的方式。
🛠️ iOS 越狱机配置:
-
打开 Cydia 或 Sileo,添加主流源,搜索并安装插件
SSL Kill Switch 2。 -
安装后,进入 iPhone
设置-> 找到SSL Kill Switch 2-> 开启Disable Certificate Validation开关。 -
该插件会自动 Hook 系统底层的
Security.framework,强制使所有 App 的安全校验逻辑失效。
🛠️ Android Root 机配置:
-
确保手机已通过 Magisk 刷入 LSPosed 框架。
-
下载并安装模块
JustTrustMe(老系统推荐)或TrustMeAlready(支持高版本 Android)。 -
在 LSPosed 控制台中激活该模块,并勾选目标 App。
-
重启目标 App,其内置的证书校验逻辑就会被自动绕过。
2.3 解决方案二:使用 Frida + Objection 动态插桩(免越狱/Root 首选)
如果你使用的是未越狱的设备,或者不想安装系统插件,可以通过 Frida 在内存中临时将验证函数“修改”掉。
# 1. 确保 PC 和手机已搭建好 Frida 环境,且运行了 frida-server。
# 2. 在 PC 终端中通过 objection 注入启动目标 App
objection -g "你的目标应用显示名称" explore
进入 Objection 交互式控制台后,输入以下命令即可动态绕过证书绑定:
# 对于 iOS 设备:
ios sslpinning disable
# 对于 Android 设备:
android sslpinning disable
(objection 会自动寻找常用的 AFNetworking、Alamofire、TrustKit 等库,并在内存中 Hook 它们的验证函数使其强行返回成功)
3. 突破 Flutter 应用的证书校验限制
3.1 防御原理
Flutter 应用具有极高抓包难度的原因在于其完全不走系统的网络协议栈。Flutter 拥有独立编译的二进制 Dart 虚拟机,其内部的加密库(BoringSSL)并不使用 iOS/Android 系统的根证书信任列表,并且忽略系统配置的全局代理。
3.2 解决方案:Frida 强制 Hook BoringSSL 校验函数
既然 Flutter 运行在其自带的 C/C++ 动态链接库(libflutter.so 或 App.framework)中,我们就需要使用 Frida 对其底层的汇编函数进行硬核 Hook。
🛠️ 实战步骤:
- 保存以下通用的 Flutter 绕过 JavaScript 脚本为
flutter_bypass.js:
// 通用 Flutter SSL Pinning 绕过脚本片段
// 原理:定位 libflutter.so/App.framework 中的 ssl_crypto_x509_session_verify_cert_chain 并强制返回 1 (Success)
function bypassFlutter() {
var m = Process.findModuleByName("libflutter.so") || Process.findModuleByName("App");
if (!m) {
console.log("[!] 未找到 Flutter 引擎模块");
return;
}
console.log("[*] 找到 Flutter 引擎基址: " + m.base);
// 不同的 Flutter 版本,其底层函数的特征码有所不同
// 以下脚本会利用内存特征码搜索定位 verify_cert_chain 校验函数
Memory.scan(m.base, m.size, "ff 03 05 d1 fc 6f 0f a9 f8 5f 10 a9 f6 57 11 a9", {
onMatch: function (address, size) {
console.log("[*] 成功定位 Flutter SSL 校验函数地址: " + address);
Interceptor.attach(address, {
onLeave: function (retval) {
console.log("[+] 绕过 Flutter 证书链验证,强制返回成功");
retval.replace(1); // 强制返回 1 (Verify Success)
}
});
},
onComplete: function () {
console.log("[*] 内存特征扫描结束");
}
});
}
Java.perform(function () {
bypassFlutter();
});
- 配合 VPN 劫持工具(如 Shadowrocket 转发到电脑),并使用以下命令启动注入:
```bash
frida -U -f <包名> -l flutter_bypass.js
```
4. 高级排查决策树(如何选择方案)
当你面对一个新 App,不知道它采用了何种防御手段时,请按照以下“决策树”步骤逐步推进:
graph TD
Start[1. 正常配置电脑 Charles 和手机 Wi-Fi 代理] --> Check1{Charles 窗口有无任何该 App 流量?}
Check1 -->|完全没有流量| ActionProxy[2. 说明 App 绕过了代理直连<br>请使用 Shadowrocket 或 Postern 接管流量]
Check1 -->|有流量,但全是红锁或报错| ActionPinning[3. 说明 App 启用了 SSL Pinning<br>请使用 Frida/Objection 或越狱插件绕过]
Check1 -->|有流量,且全显示明文| End[恭喜! 抓包成功]
ActionProxy --> Check2{接管流量后, 出现红锁报错吗?}
Check2 -->|是, 变为红锁| ActionPinning
Check2 -->|否, 显明文了| End
ActionPinning --> Check3{App 是 Flutter 架构吗?}
Check3 -->|是| ActionFlutter[4. 使用专门的 Flutter 内存 Hook 脚本]
Check3 -->|否| ActionCommonPin[5. 使用 Objection sslpinning disable]
ActionFlutter --> End
ActionCommonPin --> End
通过以上系统化的层层排查,配合局域网环境及代理接管,可以突破市面上 99% 移动端应用的抓包限制。