关于 bypassing-mobile-pinning
面向经授权移动应用测试的技能,用于诊断和处理 TLS 代理流量不可见的问题。它先区分证书信任、代理设置、双向 TLS 等原因,再根据 Android 或 iOS 的网络栈选择验证和绕过方法。
主要功能
- 01诊断代理流量不可见的原因
- 02识别 Android 与 iOS TLS 网络栈
- 03按网络栈选择挂钩位置
- 04排查双向 TLS 与代理绕行
- 05通过请求修改验证拦截效果
适用场景
- 01调查移动应用的 TLS 握手失败
- 02为授权测试查看应用 API 请求
- 03区分证书固定与其他网络问题
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ trilwu/ secskills --skill bypassing-mobile-pinning安装后在 Claude Code 中输入/bypassing-mobile-pinning确认已加载。
详细介绍
绕过移动应用证书固定
在这里浪费的时间,大多花在绕过根本不存在的证书固定上。代理为空至少有六种原因,每种原因的解决方法都不同——其中一种根本不是证书固定,而是 Android 默认不信任用户 CA;另一种则是应用使用了自己的 TLS 栈,根本没有经过你的代理。先诊断,再考虑使用绕过脚本。
仅对你获准测试的应用执行此操作。
适用场景
- Burp/mitmproxy/Charles 显示来自移动应用的 TLS 握手失败
- 应用显然正在访问网络,但代理中什么也没有
- 配置代理后,应用报告“网络错误”“连接不安全”或类似信息
- 你知道目标应用采用了证书固定,需要针对其协议栈选择合适的 Hook
不适用场景
- Flutter 目标应用——使用
reversing-flutter-apps;Flutter 的故障表现完全相同,但原因和解决方法针对其引擎 - 更广泛的移动应用安全评估——使用
testing-mobile-applications - 流量可见后的后端测试——使用
testing-apis - 深入逆向原生
.so文件——使用analyzing-binaries
先诊断
在安装任何内容之前先运行此操作。症状会告诉你原因。
| 症状 | 可能原因 | 解决方法 |
|---|---|---|
代理收到 CONNECT,随后出现 TLS 警报 unknown_ca / bad_certificate | 你的 CA 不受信任 | 将其安装为系统 CA,或修补 Network Security Config |
| 代理收到 CONNECT,随后只有部分域名出现警报 | 真正的证书固定,且仅针对这些主机 | Hook 证书固定检查 |
| 代理完全没有收到任何内容,但应用正常运行 | 应用忽略了系统代理 | 在网络层强制转发流量(Flutter、gRPC、某些 SDK) |
| 代理收到握手,但服务器拒绝客户端 | 双向 TLS——应用提供了客户端证书 | 提取客户端证书;这不是证书固定 |
| 在模拟器上正常,在设备上失败(或反之) | Root/模拟器检测,不是 TLS | 这是另一类问题——请参阅检测章节 |
| 仅在登录后失败 | 证书固定仅应用于 API 主机 | 执行 Hook,然后再次检查 |
# What does the app actually declare?
apktool d target.apk -o out
cat out/res/xml/network_security_config.xml 2>/dev/null
rg -n 'networkSecurityConfig|usesCleartextTraffic' out/AndroidManifest.xml
# Which TLS stack is in play?
rg -l 'okhttp3|CertificatePinner|TrustKit|AFNetworking|Alamofire' out/ 2>/dev/null | head
unzip -l target.apk | rg 'libssl|libcrypto|libconscrypt|libflutter|libil2cpp|libmonodroid'
不要在排查证书固定之前,先检查 Network Security Config。 Android 7 起,应用默认不信任用户安装的 CA。即使应用完全没有证书固定代码,流量拦截仍然会失败。有两种解决方法:
# A. Install your CA as a SYSTEM certificate (no app modification — preferred)
# Emulator:
emulator -avd <name> -writable-system
adb root && adb remount
openssl x509 -inform PEM -subject_hash_old -in burp.pem | head -1 # → e.g. 9a5ba580
cp burp.pem 9a5ba580.0 && adb push 9a5ba580.0 /system/etc/security/cacerts/
adb shell chmod 644 /system/etc/security/cacerts/9a5ba580.0
# Rooted device: use a Magisk module so the change survives reboot
# B. Patch the config and repack (when you cannot get a system CA)
# Add to network_security_config.xml:
# <base-config><trust-anchors>
# <certificates src="system"/><certificates src="user"/>
# </trust-anchors></base-config>
apktool b out -o patched.apk && apksigner sign --ks debug.keystore patched.apk
方案 A 更好:它不会修改应用,因此完整性检查、签名检查和 Play Integrity 不会受到影响。只有在无法向设备安装系统 CA 时,才考虑方案 B。
Android:按技术栈 Hook
先识别技术栈,再进行 Hook。通用脚本如果没有命中,看起来就像是“绕过失败”,但实际上只是针对了错误的层。
# Start here — covers the common Java-layer stacks in one shot
objection -g com.target.app explore
# then: android sslpinning disable
# Or a maintained universal script
frida -U -f com.target.app -l android-ssl-bypass.js --no-pause
| 技术栈 | 标记 | Hook 点 |
|---|---|---|
| OkHttp 3/4 | okhttp3.CertificatePinner | CertificatePinner.check() — 正常返回 |
| HttpURLConnection | javax.net.ssl.* | 自定义 X509TrustManager.checkServerTrusted() |
| Conscrypt | libconscrypt_jni.so | Platform.checkServerTrusted,或原生层 |
| Apache HttpClient | org.apache.http | SSLSocketFactory 验证器 |
| WebView | onReceivedSslError | 强制执行 handler.proceed() |
| 原生 / BoringSSL | libssl.so,自定义 .so | SSL_CTX_set_custom_verify、ssl_verify_peer_cert |
| Xamarin | libmonodroid.so、libxamarin* | Mono 层的 ServicePointManager / HttpClientHandler |
| Unity | libil2cpp.so | UnityWebRequest 证书处理器,或 BestHTTP 的验证器 |
| gRPC | libgrpc.so | 通道凭据;通常也会忽略代理 |
原生证书固定是通用脚本失效的地方。 当 objection 报告成功但流量仍然失败时,检查位于某个 .so 中。BoringSSL 的验证入口点没有导出,因此脚本会通过模式扫描来定位它们——而模式与版本有关。请确认你遇到的情况:
# Is a native TLS stack even present?
unzip -j target.apk 'lib/arm64-v8a/*' -d libs && rg -l 'SSL_|BoringSSL|s2n' libs/
# Trace the native calls to see which library terminates TLS
frida-trace -U -f com.target.app -i 'SSL_*' -i '*verify*'
对于 Unity、Xamarin 和 Flutter 构建版本,先恢复符号——reversing-unity-il2cpp、reversing-flutter-apps——然后 Hook 命名函数,而不是盲目进行模式扫描。
iOS
# Frida-based, covers NSURLSession and the common libraries
objection -g com.target.app explore
# then: ios sslpinning disable
# Jailbroken device, no Frida
# SSL Kill Switch 3 — system-wide, survives app updates
| 库 | Hook 点 |
|---|---|
| NSURLSession(默认) | URLSession:didReceiveChallenge: → 使用服务器信任的 .useCredential |
| TrustKit | TSKPinningValidator 结果 |
| AFNetworking | AFSecurityPolicy.evaluateServerTrust: |
| Alamofire | ServerTrustManager / ServerTrustEvaluating |
| 原生/BoringSSL | 与 Android 相同 — Hook 验证回调 |
对于非越狱设备:使用 Frida gadget 重新打包 IPA(objection patchipa)、重新签名并侧载。请预期这会触发安全加固应用中的完整性或证明检查。
仍然失败时
按顺序排查,不要继续尝试更多绕过脚本。
- 应用根本没有使用你的代理。 某些技术栈完全忽略系统代理设置。强制转发流量:使用
iptables进行透明重定向,或使用基于 VPN/tun 的代理。adb shell su -c 'iptables -t nat -A OUTPUT -p tcp --dport 443 -j DNAT --to <proxy>:8080' - 证书透明度强制检查。 某些 SDK 要求 SCT;你的 CA 没有。查找 CT 库,并专门 Hook CT 验证器。
- 双向 TLS。 服务器要求客户端证书。从应用包中提取
.p12或密钥库,找回其密码(通常在代码或strings中),并将其载入代理的客户端证书设置。这是独立于证书固定的机制,任何证书固定绕过都不会影响它。 - Root/越狱或 Frida 检测。 应用检测到插桩后会安全失败,看起来像是 TLS 问题。检查是否扫描
frida字符串、探测端口 27042、检查/proc/self/maps,或进行 Play Integrity 检查。先绕过检测,再重试证书固定绕过。 - 流量不是 HTTP。 可能是 WebSockets、gRPC、MQTT 或基于 TLS 的自定义协议。HTTP 代理不会显示这些流量——请在套接字层捕获,或使用支持相应协议的代理。
- 证书固定仅应用于特定主机。 分析流量正常,但 API 失败。对比代理中出现的主机,确认这一点。
验证是否真正成功
只有当你能端到端地查看并修改请求时,才算确认绕过成功——应用仅仅不再报错并不足够。
1. Proxy shows the API host, not just analytics and CDN traffic
2. Request and response bodies are readable
3. A modified request produces a different server response
4. Authenticated flows still work through the proxy
如果只有第 1 步通过,你看到的可能是备用路径,而真正的 API 流量走了其他路径。
应拒绝的错误说法
- “绕过失败了,应用一定用了强证书固定。” 可能有六种原因,其中一种是证书固定。请根据症状表进行诊断。
- “我安装了 CA,TLS 就应该能正常工作。” 如果它是用户证书,且应用运行在 Android 7+ 上又未选择启用相关支持,那就无法正常工作。
- “objection 说证书固定已禁用。” 它禁用的是自己能识别的 Java 层检查。原生代码中的证书固定不受影响。
- “代理中没有流量,说明应用处于离线状态。” 这说明应用没有使用你的代理。
- “我直接修补 APK 就行。” 重新打包会破坏签名并触发完整性检查。优先使用系统 CA 和运行时 Hook;只有作为最后手段时才修补。
- “证书固定已绕过,评估完成。” 绕过证书固定只是准备工作,不是发现项。证书固定是一种纵深防御措施;缺少这项措施只需作为低严重性说明记录——真正的发现项在它后面的 API 中。
参考资料
testing-mobile-applications— 解锁后续评估所需的更广泛测试reversing-flutter-apps— Flutter 独立的 TLS 栈和代理行为reversing-unity-il2cpp、reversing-react-native-apps— 在 Hook 框架专属栈之前恢复符号testing-apis— 查看流量后,真正发现项所在之处- objection、Frida、SSL Kill Switch 3、apktool、apksigner、Magisk