关于 mobile-ssl-pinning-bypass
面向移动安全测试的指南,介绍 Android 和 iOS 应用的 SSL Pinning 绕过方法。涵盖运行时钩子、应用补丁、框架专用方案,以及流量拦截失败时的排查。
主要功能
- 01Android 和 iOS 绕过方法
- 02Frida 与 Objection 钩子
- 03应用反编译和重新打包流程
- 04Flutter、React Native 和 Xamarin 指南
- 05Pinning 失败诊断
适用场景
- 01在授权测试中拦截应用 HTTPS 流量
- 02测试具有多层 Pinning 的应用
- 03检查 Flutter 应用的网络验证
- 04排查代理证书信任问题
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ yaklang/ hack-skills --skill mobile-ssl-pinning-bypass安装后在 Claude Code 中输入/mobile-ssl-pinning-bypass确认已加载。
详细介绍
技能:移动端 SSL Pinning 绕过——专家攻击手册
AI LOAD INSTRUCTION:移动平台 SSL pinning 绕过专家技术。涵盖 Android 和 iOS 绕过方法(Frida、Objection、Xposed、SSL Kill Switch)、特定框架的绕过方法(Flutter、React Native、Xamarin),以及非标准 pinning 实现的故障排查。基础模型容易遗漏特定框架的 hook 点和多层 pinning 配置。
0. 相关路由
深入分析前,可考虑加载:
- android-pentesting-tricks,了解 SSL 绕过之外更广泛的 Android 测试
- ios-pentesting-tricks,了解 SSL 绕过之外更广泛的 iOS 测试
- 流量被拦截后,加载 api-sec 进行 API 层测试
1. SSL PINNING 类型
| Pinning 类型 | Pinning 的内容 | 抗攻击能力 | 常见于 |
|---|---|---|---|
| 证书 pinning | 精确的叶证书(DER/PEM) | 低(证书轮换时会失效) | 旧版应用 |
| 公钥 pinning | Subject Public Key Info | 中(密钥不变时,证书续期后仍有效) | 现代应用 |
| SPKI 哈希 pinning | SPKI 的 SHA-256 | 中(与公钥 pinning 相同) | OkHttp、AFNetworking |
| CA pinning | 中间 CA 或根 CA 证书 | 高(该 CA 颁发的任意证书均可) | 企业应用 |
| 多 pin(备用 pin) | 主 pin + 备用 pin | 高(备用 pin 可回退使用) | 支持 HPKP 的应用 |
Pinning 的工作原理
TLS Handshake
│
├── Server presents certificate chain
│
├── Standard validation (system trust store)
│ └── Passes? continue : connection fails
│
└── Pin validation (app-level check)
├── Extract server cert/pubkey/SPKI hash
├── Compare against embedded pins
└── Match found? → allow : → reject connection
2. ANDROID 绕过方法
2.1 Frida 通用 SSL 绕过
// Hooks TrustManager, OkHttp, Volley, Retrofit, Conscrypt
Java.perform(function() {
// ── TrustManagerImpl (Android system) ──
try {
var TMI = Java.use('com.android.org.conscrypt.TrustManagerImpl');
TMI.verifyChain.implementation = function() {
console.log('[Bypass] TrustManagerImpl.verifyChain');
return arguments[0]; // return untouched chain
};
} catch(e) {}
// ── X509TrustManager (custom implementations) ──
var TrustManager = Java.registerClass({
name: 'com.bypass.TrustManager',
implements: [Java.use('javax.net.ssl.X509TrustManager')],
methods: {
checkClientTrusted: function() {},
checkServerTrusted: function() {},
getAcceptedIssuers: function() { return []; }
}
});
var SSLContext = Java.use('javax.net.ssl.SSLContext');
SSLContext.init.overload('[Ljavax.net.ssl.KeyManager;',
'[Ljavax.net.ssl.TrustManager;', 'java.security.SecureRandom')
.implementation = function(km, tm, sr) {
console.log('[Bypass] SSLContext.init');
this.init(km, [TrustManager.$new()], sr);
};
// ── OkHttp3 CertificatePinner ──
try {
var CP = Java.use('okhttp3.CertificatePinner');
CP.check.overload('java.lang.String', 'java.util.List').implementation = function() {
console.log('[Bypass] OkHttp3 CertificatePinner.check: ' + arguments[0]);
};
// check$okhttp variant (OkHttp 4.x)
try { CP['check$okhttp'].implementation = function() {}; } catch(e) {}
} catch(e) {}
// ── Retrofit / OkHttp interceptor ──
try {
var OkHttpClient = Java.use('okhttp3.OkHttpClient$Builder');
OkHttpClient.certificatePinner.implementation = function(pinner) {
console.log('[Bypass] OkHttpClient.Builder.certificatePinner');
return this; // return builder without pinner
};
} catch(e) {}
// ── Volley (HurlStack) ──
try {
var HurlStack = Java.use('com.android.volley.toolbox.HurlStack');
HurlStack.createConnection.implementation = function(url) {
console.log('[Bypass] Volley HurlStack: ' + url);
var conn = this.createConnection(url);
// Remove hostname verifier
conn.setHostnameVerifier(Java.use(
'javax.net.ssl.HttpsURLConnection').getDefaultHostnameVerifier());
return conn;
};
} catch(e) {}
// ── Conscrypt / BoringSSL (modern Android) ──
try {
var Conscrypt = Java.use('org.conscrypt.ConscryptFileDescriptorSocket');
Conscrypt.verifyCertificateChain.implementation = function() {
console.log('[Bypass] Conscrypt verifyCertificateChain');
};
} catch(e) {}
// ── Apache HttpClient (legacy) ──
try {
var AbstractVerifier = Java.use('org.apache.http.conn.ssl.AbstractVerifier');
AbstractVerifier.verify.overload('java.lang.String', '[Ljava.lang.String;',
'[Ljava.lang.String;', 'boolean').implementation = function() {
console.log('[Bypass] Apache AbstractVerifier');
};
} catch(e) {}
// ── HostnameVerifier ──
try {
var HV = Java.use('javax.net.ssl.HttpsURLConnection');
HV.setDefaultHostnameVerifier.implementation = function(v) {
console.log('[Bypass] Ignoring custom HostnameVerifier');
};
} catch(e) {}
console.log('[+] Android universal SSL bypass loaded');
});
2.2 Objection(一条命令)
objection -g com.target.app explore --startup-command "android sslpinning disable"
2.3 Network Security Config(调试覆盖)
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system" />
<certificates src="user" />
</trust-anchors>
</base-config>
</network-security-config>
工作流:反编译 APK → 添加/修改配置 → 重新打包 → 重新签名 → 安装。
apktool d target.apk -o target_dir
# Edit res/xml/network_security_config.xml
# Add reference in AndroidManifest.xml if missing
apktool b target_dir -o target_patched.apk
zipalign -v 4 target_patched.apk target_aligned.apk
apksigner sign --ks my-key.keystore target_aligned.apk
adb install target_aligned.apk
2.4 Xposed / LSPosed 模块
| 模块 | 方法 | 范围 | 是否需要 Root |
|---|---|---|---|
| JustTrustMe | Hook TrustManager + OkHttp | 单个应用 | 是(Xposed) |
| SSLUnpinning | Hook 证书验证 | 单个应用 | 是(LSPosed) |
| TrustMeAlready | 全局 TrustManager 绕过 | 系统范围 | 是(LSPosed) |
2.5 Magisk + 系统 CA 安装
# Install proxy CA as system cert (Android 7+ requires this for system-level trust)
# Method 1: MagiskTrustUserCerts module
# Moves user CAs to /system/etc/security/cacerts/ via Magisk overlay
# Method 2: Manual (requires root)
adb push burp_ca.pem /sdcard/
adb shell
su
mount -o remount,rw /system
cp /sdcard/burp_ca.pem /system/etc/security/cacerts/9a5ba575.0 # hash-named
chmod 644 /system/etc/security/cacerts/9a5ba575.0
mount -o remount,ro /system
# Get correct hash filename:
openssl x509 -inform PEM -subject_hash_old -in burp_ca.pem | head -1
# Output: 9a5ba575 → filename is 9a5ba575.0
2.6 手动反编译 → 修补 → 重新打包
# Step 1: Decompile
jadx -d decompiled/ target.apk
# Step 2: Find pinning code
grep -r "CertificatePinner\|X509TrustManager\|checkServerTrusted\|ssl" decompiled/
# Step 3: Identify pinning implementation and patch
# Use smali editing for precise control:
apktool d target.apk
# Edit smali files to NOP out pinning checks
# Look for invoke-virtual {checkServerTrusted} and replace with return-void
# Step 4: Repackage and sign
apktool b target_dir -o patched.apk
apksigner sign --ks debug.keystore patched.apk
3. IOS 绕过方法
3.1 Frida(SecTrust Hooks)
// Hook core iOS SSL validation functions
var SecTrustEvaluateWithError = Module.findExportByName('Security', 'SecTrustEvaluateWithError');
Interceptor.attach(SecTrustEvaluateWithError, {
onLeave: function(retval) {
retval.replace(ptr(1));
}
});
var SecTrustEvaluate = Module.findExportByName('Security', 'SecTrustEvaluate');
Interceptor.attach(SecTrustEvaluate, {
onLeave: function(retval) {
retval.replace(ptr(0));
}
});
// Hook SSLHandshake (lower-level)
var SSLHandshake = Module.findExportByName('Security', 'SSLHandshake');
if (SSLHandshake) {
Interceptor.attach(SSLHandshake, {
onLeave: function(retval) {
if (retval.toInt32() === -9807) { // errSSLXCertChainInvalid
retval.replace(ptr(0));
}
}
});
}
// Hook NSURLSession delegate method
try {
var cls = ObjC.classes.NSURLSession;
// Hook URLSession:didReceiveChallenge:completionHandler: on delegates
ObjC.enumerateLoadedClasses({
onMatch: function(name) {
try {
var methods = ObjC.classes[name].$ownMethods;
for (var i = 0; i < methods.length; i++) {
if (methods[i].indexOf('didReceiveChallenge') !== -1 &&
methods[i].indexOf('completionHandler') !== -1) {
console.log('[SSL] Found delegate: ' + name + ' ' + methods[i]);
}
}
} catch(e) {}
},
onComplete: function() {}
});
} catch(e) {}
3.2 Objection(一条命令)
objection -g com.target.app explore --startup-command "ios sslpinning disable"
3.3 SSL Kill Switch 2(越狱插件)
# Install via Cydia/Sileo
# Package: com.nablac0d3.sslkillswitch2
# Disables SSL pinning system-wide or per-app via Settings toggle
# Hooks:
# - SecTrustEvaluate
# - SSLHandshake
# - SSLSetSessionOption
# - tls_helper_create_peer_trust
3.4 特定库的 Hook
| 库 | iOS Hook 点 | Frida 方法 |
|---|---|---|
| AFNetworking | AFSecurityPolicy.evaluateServerTrust:forDomain: | 返回 YES |
| Alamofire | ServerTrustManager.evaluate(_:forHost:) | 跳过评估 |
| TrustKit | TSKPinningValidator verifyPublicKeyPin: | 返回成功 |
| NSURLSession | URLSession:didReceiveChallenge:completionHandler: | 使用 .useCredential 调用 completionHandler |
3.5 手动二进制修补
# Find pinning function in binary
strings decrypted_binary | grep -i "pin\|cert\|trust"
# Disassemble and find the validation function
# Replace comparison/branch instruction with NOP or unconditional pass
# LLDB runtime modification
lldb -n TargetApp
(lldb) breakpoint set -n "SecTrustEvaluateWithError"
(lldb) breakpoint command add 1
> thread return 1
> continue
> DONE
4. 特定框架的绕过方法
4.1 Flutter
Flutter 使用 Dart 的 dart:io 库,底层依赖 BoringSSL。在 Java/ObjC 层使用标准 Frida Hook 不起作用。
// Flutter SSL bypass — must hook BoringSSL directly
// Find ssl_crypto_x509_session_verify_cert_chain in libflutter.so
var libflutter = Process.findModuleByName('libflutter.so'); // Android
// var libflutter = Process.findModuleByName('Flutter'); // iOS
// Hook ssl_verify_peer_cert (BoringSSL function)
// Signature varies by Flutter version — use pattern scanning
var pattern = 'FF C3 ..'; // Example pattern, varies
var matches = Memory.scan(libflutter.base, libflutter.size, pattern, {
onMatch: function(address, size) {
console.log('[Flutter] Potential verify function at: ' + address);
Interceptor.attach(address, {
onLeave: function(retval) {
retval.replace(ptr(0)); // SSL_VERIFY_OK
}
});
},
onComplete: function() {}
});
// Alternative: use reflutter tool for automated patching
// reflutter target.apk
// This patches BoringSSL in the Flutter engine directly
reflutter 工具(推荐用于 Flutter 应用):
pip install reflutter
reflutter target.apk
# Outputs patched APK that redirects traffic to your proxy
# Also disables SSL verification in the BoringSSL engine
4.2 React Native
React Native 使用平台网络栈:Android 上使用 OkHttp,iOS 上使用 NSURLSession。
| 平台 | 网络栈 | 绕过方法 |
|---|---|---|
| Android | OkHttp3 | 标准 OkHttp CertificatePinner Hook |
| iOS | NSURLSession | 标准 SecTrust Hooks |
| Android(Hermes) | 同样使用 OkHttp | 使用相同的 Hooks,但 Hermes JIT 可能需要额外处理 |
// React Native Android — same as OkHttp bypass
Java.perform(function() {
try {
var CP = Java.use('okhttp3.CertificatePinner');
CP.check.overload('java.lang.String', 'java.util.List').implementation = function() {};
} catch(e) { console.log('OkHttp3 not found, trying okhttp2...'); }
try {
var CP2 = Java.use('com.squareup.okhttp.CertificatePinner');
CP2.check.overload('java.lang.String', 'java.util.List').implementation = function() {};
} catch(e) {}
});
4.3 Xamarin
// Xamarin pinning typically via:
// ServicePointManager.ServerCertificateValidationCallback
// or custom HttpClientHandler
// Frida bypass for Xamarin (Mono runtime)
// Hook Mono method: System.Net.ServicePointManager.set_ServerCertificateValidationCallback
var mono_method = Module.findExportByName('libmonosgen-2.0.so',
'mono_runtime_invoke');
// More practical: hook the managed callback at CIL level
// Use Frida's Mono bridge or objection's built-in Xamarin support
// Objection has built-in Xamarin bypass:
// objection -g com.target.app explore
// > android sslpinning disable (covers Xamarin on Android)
5. 证书透明度与 HPKP
| 技术 | 状态 | 对测试的影响 |
|---|---|---|
| 证书透明度(CT) | 正在使用,由浏览器强制执行 | 移动应用很少强制执行 CT;这不会成为绕过障碍 |
| HPKP(HTTP 公钥 Pinning) | 已弃用(2018) | 旧版应用可能仍会检查;从代理响应中移除该标头 |
| Expect-CT 标头 | 已弃用(2024) | 对移动端测试影响极小 |
| 移动应用中的 CT | 少见 | 只有 Google 应用会通过自定义 CT 检查来强制执行 |
6. 故障排查
6.1 常见故障
| 症状 | 原因 | 解决方法 |
|---|---|---|
| 已加载绕过脚本,但流量仍然失败 | 存在多个固定层 | Hook 所有层:TrustManager + OkHttp + 自定义检查 |
| “需要客户端证书” | 双向 TLS(mTLS) | 从应用包/钥匙串中提取客户端证书,并导入代理 |
| 连接正常,但没有 HTTP 流量 | 使用了非 HTTP 协议(MQTT、gRPC、WebSocket) | 使用 Wireshark 或特定协议代理 |
| 绕过后应用崩溃 | 防篡改机制检测到了 Hook | 先绕过完整性检查,再绕过 SSL |
| 不信任代理 CA | Android 7+ 对用户 CA 的限制 | 将 CA 作为系统证书安装(Magisk 模块) |
| Flutter 应用忽略 Hook | Native 层未 Hook BoringSSL | 使用 reflutter 或 Native BoringSSL Hook |
| 证书链验证超时 | OCSP stapling 不匹配 | 禁用 OCSP 检查或模拟 OCSP 响应器 |
6.2 诊断步骤
# Verify proxy CA is installed correctly
# Android:
adb shell "ls /system/etc/security/cacerts/ | grep $(openssl x509 -subject_hash_old -in ca.pem | head -1)"
# iOS: Settings → General → About → Certificate Trust Settings
# Check if target app is actually using SSL (vs. plain HTTP)
# Wireshark filter: tcp.port == 443 and ip.addr == <device_ip>
# Check if Frida is hooking the right process
frida-ps -U | grep target
# Verbose Frida output for debugging hooks
frida -U -f com.target.app -l bypass.js --debug
7. SSL 固定绕过决策树
Need to intercept mobile app HTTPS traffic
│
├── Platform?
│ ├── Android ↓
│ │ ├── Rooted device available?
│ │ │ ├── Yes → Frida universal bypass (§2.1) [FIRST TRY]
│ │ │ │ ├── Works? → done
│ │ │ │ └── Fails? → add Conscrypt + Volley hooks
│ │ │ ├── Still fails? → LSPosed + TrustMeAlready (§2.4)
│ │ │ └── Still fails? → install CA as system cert (§2.5)
│ │ └── No root?
│ │ ├── Debug build? → Network Security Config (§2.3)
│ │ └── Release build? → decompile + patch + repackage (§2.6)
│ │
│ └── iOS ↓
│ ├── Jailbroken device available?
│ │ ├── Yes → Objection ios sslpinning disable (§3.2) [FIRST TRY]
│ │ │ ├── Works? → done
│ │ │ └── Fails? → Frida SecTrust hooks (§3.1)
│ │ ├── Still fails? → SSL Kill Switch 2 (§3.3)
│ │ └── Still fails? → library-specific hooks (§3.4)
│ └── No jailbreak?
│ ├── Re-sign with Frida gadget → run Frida hooks
│ └── Binary patch → sideload (§3.5)
│
├── Framework-specific app?
│ ├── Flutter → reflutter tool or BoringSSL native hooks (§4.1)
│ ├── React Native → standard platform hooks (§4.2)
│ └── Xamarin → Objection or Mono runtime hooks (§4.3)
│
├── Bypass works but issues remain?
│ ├── Client cert required? → extract + import to proxy (§6.1)
│ ├── Non-HTTP protocol? → protocol-specific tooling (§6.1)
│ └── App crashes? → fix anti-tampering first (§6.1)
│
└── All methods fail?
├── Analyze traffic at network level (Wireshark/tcpdump)
├── Check for custom proprietary protocol
└── Consider iptables + transparent proxy approach
8. 代理设置速查表
| 代理工具 | 适用场景 | SSL 绕过集成方式 |
|---|---|---|
| Burp Suite | 全面的 HTTP 分析 | 将 CA 导入设备 |
| mitmproxy | 脚本化拦截 | mitmproxy --set confdir=~/.mitmproxy |
| Charles Proxy | 原生支持 macOS,易于设置 | 内置 CA 安装 |
| Proxyman | 原生支持 macOS/iOS | 直接支持 iOS 设备 |
| HTTP Toolkit | 快速设置 Android | 自动配置 CA + Frida 绕过 |
# Android proxy setup
adb shell settings put global http_proxy <host_ip>:8080
# Remove proxy
adb shell settings put global http_proxy :0
# iOS proxy: Settings → Wi-Fi → Configure Proxy → Manual
评论
支持 Markdown