SKILL: Mobile SSL Pinning Bypass — Expert Attack Playbook
SKILL: 移动端SSL固定绕过 —— 专家攻击手册
AI LOAD INSTRUCTION: Expert SSL pinning bypass techniques for mobile platforms. Covers Android and iOS bypass methods (Frida, Objection, Xposed, SSL Kill Switch), framework-specific bypasses (Flutter, React Native, Xamarin), and troubleshooting non-standard pinning implementations. Base models miss framework-specific hook points and multi-layer pinning configurations.
AI加载说明:适用于移动平台的专业SSL固定绕过技术,涵盖Android和iOS绕过方法(Frida、Objection、Xposed、SSL Kill Switch)、框架专属绕过方案(Flutter、React Native、Xamarin),以及非标准固定实现的故障排查。基础模型缺少框架专属hook点和多层固定配置的相关知识。
0. RELATED ROUTING
0. 相关关联技能
Before going deep, consider loading:
- android-pentesting-tricks for broader Android testing beyond SSL bypass
- ios-pentesting-tricks for broader iOS testing beyond SSL bypass
- api-sec once traffic is intercepted for API-level testing
深入学习前,可考虑加载以下内容:
- android-pentesting-tricks 了解除SSL绕过之外的更全面Android测试技巧
- ios-pentesting-tricks 了解除SSL绕过之外的更全面iOS测试技巧
- api-sec 流量拦截完成后用于API层面的测试
1. SSL PINNING TYPES
1. SSL固定类型
| Pinning Type | What Is Pinned | Resilience | Common In |
|---|
| Certificate pinning | Exact leaf certificate (DER/PEM) | Low (breaks on cert rotation) | Legacy apps |
| Public key pinning | Subject Public Key Info | Medium (survives cert renewal if key unchanged) | Modern apps |
| SPKI hash pinning | SHA-256 of SPKI | Medium (same as public key) | OkHttp, AFNetworking |
| CA pinning | Intermediate or root CA cert | High (any cert from that CA works) | Enterprise apps |
| Multi-pin (backup pins) | Primary + backup pins | High (fallback pins) | HPKP-aware apps |
| 固定类型 | 固定内容 | 抗破解能力 | 常见使用场景 |
|---|
| 证书固定 | 精确的叶子证书(DER/PEM格式) | 低(证书轮转时会失效) | 老旧应用 |
| 公钥固定 | 主体公钥信息(SPKI) | 中等(密钥不变的情况下证书续期不受影响) | 现代应用 |
| SPKI哈希固定 | SPKI的SHA-256哈希值 | 中等(和公钥固定效果一致) | OkHttp、AFNetworking |
| CA固定 | 中间证书或根CA证书 | 高(该CA签发的任意证书都可生效) | 企业级应用 |
| 多固定(备份固定) | 主固定+备份固定 | 高(支持 fallback 到备份固定值) | 支持HPKP的应用 |
How Pinning Works
固定机制工作原理
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
TLS 握手
│
├── 服务端返回证书链
│
├── 标准校验(系统信任存储)
│ └── 校验通过?继续流程 : 连接失败
│
└── 固定值校验(应用层检查)
├── 提取服务端证书/公钥/SPKI哈希
├── 和应用内置的固定值对比
└── 匹配成功?→ 允许连接 : → 拒绝连接
2. ANDROID BYPASS METHODS
2. Android 绕过方法
2.1 Frida Universal SSL Bypass
2.1 Frida通用SSL绕过脚本
javascript
// 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');
});
javascript
// Hooks TrustManager, OkHttp, Volley, Retrofit, Conscrypt
Java.perform(function() {
// ── TrustManagerImpl (Android系统) ──
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 (自定义实现) ──
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 (One Command)
2.2 Objection(单命令执行)
bash
objection -g com.target.app explore --startup-command "android sslpinning disable"
bash
objection -g com.target.app explore --startup-command "android sslpinning disable"
2.3 Network Security Config (Debug Override)
2.3 网络安全配置(调试模式覆盖)
xml
<!-- AndroidManifest.xml: android:networkSecurityConfig="@xml/network_security_config" -->
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system" />
<certificates src="user" /> <!-- Trust user-installed CAs -->
</trust-anchors>
</base-config>
</network-security-config>
Workflow: decompile APK → add/modify config → repackage → re-sign → install.
bash
apktool d target.apk -o target_dir
xml
<!-- AndroidManifest.xml: android:networkSecurityConfig="@xml/network_security_config" -->
<!-- res/xml/network_security_config.xml -->
<network-security-config>
<base-config>
<trust-anchors>
<certificates src="system" />
<certificates src="user" /> <!-- 信任用户安装的CA -->
</trust-anchors>
</base-config>
</network-security-config>
工作流程:反编译APK → 添加/修改配置 → 重新打包 → 重签名 → 安装。
bash
apktool d target.apk -o target_dir
Edit res/xml/network_security_config.xml
Edit res/xml/network_security_config.xml
Add reference in AndroidManifest.xml if missing
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
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 Modules
2.4 Xposed / LSPosed 模块
| Module | Method | Scope | Root Required |
|---|
| JustTrustMe | Hooks TrustManager + OkHttp | Per-app | Yes (Xposed) |
| SSLUnpinning | Hooks certificate validation | Per-app | Yes (LSPosed) |
| TrustMeAlready | Global TrustManager bypass | System-wide | Yes (LSPosed) |
| 模块 | 实现方法 | 生效范围 | 需要Root |
|---|
| JustTrustMe | 钩子拦截TrustManager + OkHttp | 单应用 | 是(Xposed) |
| SSLUnpinning | 钩子拦截证书校验 | 单应用 | 是(LSPosed) |
| TrustMeAlready | 全局TrustManager绕过 | 全系统 | 是(LSPosed) |
2.5 Magisk + System CA Installation
2.5 Magisk + 系统CA安装
Install proxy CA as system cert (Android 7+ requires this for system-level trust)
将代理CA安装为系统证书(Android 7+需要此操作才能获得系统级信任)
Method 1: MagiskTrustUserCerts module
方法1: MagiskTrustUserCerts 模块
Moves user CAs to /system/etc/security/cacerts/ via Magisk overlay
通过Magisk overlay将用户CA移动到 /system/etc/security/cacerts/
Method 2: Manual (requires root)
方法2: 手动安装(需要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
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 # 哈希命名
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
openssl x509 -inform PEM -subject_hash_old -in burp_ca.pem | head -1
Output: 9a5ba575 → filename is 9a5ba575.0
Output: 9a5ba575 → 文件名为 9a5ba575.0
2.6 Manual Decompile → Patch → Repackage
2.6 手动反编译 → 补丁 → 重打包
Step 1: Decompile
步骤1: 反编译
jadx -d decompiled/ target.apk
jadx -d decompiled/ target.apk
Step 2: Find pinning code
步骤2: 查找固定代码
grep -r "CertificatePinner|X509TrustManager|checkServerTrusted|ssl" decompiled/
grep -r "CertificatePinner|X509TrustManager|checkServerTrusted|ssl" decompiled/
Step 3: Identify pinning implementation and patch
步骤3: 识别固定实现并打补丁
Use smali editing for precise control:
使用smali编辑实现精确控制:
Edit smali files to NOP out pinning checks
编辑smali文件,用NOP指令跳过固定检查
Look for invoke-virtual {checkServerTrusted} and replace with return-void
查找 invoke-virtual {checkServerTrusted} 并替换为 return-void
Step 4: Repackage and sign
步骤4: 重打包并签名
apktool b target_dir -o patched.apk
apksigner sign --ks debug.keystore patched.apk
apktool b target_dir -o patched.apk
apksigner sign --ks debug.keystore patched.apk
3. iOS BYPASS METHODS
3. iOS 绕过方法
3.1 Frida (SecTrust Hooks)
3.1 Frida(SecTrust钩子)
javascript
// 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) {}
javascript
// 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 (One Command)
3.2 Objection(单命令执行)
bash
objection -g com.target.app explore --startup-command "ios sslpinning disable"
bash
objection -g com.target.app explore --startup-command "ios sslpinning disable"
3.3 SSL Kill Switch 2 (Jailbreak Tweak)
3.3 SSL Kill Switch 2(越狱插件)
Install via Cydia/Sileo
通过Cydia/Sileo安装
Package: com.nablac0d3.sslkillswitch2
包名: com.nablac0d3.sslkillswitch2
Disables SSL pinning system-wide or per-app via Settings toggle
通过设置开关实现系统级或单应用的SSL固定禁用
- SecTrustEvaluate
- SecTrustEvaluate
- SSLHandshake
- SSLHandshake
- SSLSetSessionOption
- SSLSetSessionOption
- tls_helper_create_peer_trust
- tls_helper_create_peer_trust
3.4 Library-Specific Hooks
3.4 专属库钩子
| Library | iOS Hook Point | Frida Approach |
|---|
| AFNetworking | AFSecurityPolicy.evaluateServerTrust:forDomain:
| Return YES |
| Alamofire | ServerTrustManager.evaluate(_:forHost:)
| Skip evaluation |
| TrustKit | TSKPinningValidator verifyPublicKeyPin:
| Return success |
| NSURLSession | URLSession:didReceiveChallenge:completionHandler:
| Call completionHandler with .useCredential |
| 库 | iOS钩子点 | Frida实现方案 |
|---|
| AFNetworking | AFSecurityPolicy.evaluateServerTrust:forDomain:
| 返回YES |
| Alamofire | ServerTrustManager.evaluate(_:forHost:)
| 跳过校验 |
| TrustKit | TSKPinningValidator verifyPublicKeyPin:
| 返回成功 |
| NSURLSession | URLSession:didReceiveChallenge:completionHandler:
| 传入.useCredential调用completionHandler |
3.5 Manual Binary Patch
3.5 手动二进制补丁
Find pinning function in binary
在二进制文件中查找固定函数
strings decrypted_binary | grep -i "pin|cert|trust"
strings decrypted_binary | grep -i "pin|cert|trust"
Disassemble and find the validation function
反汇编找到校验函数
Replace comparison/branch instruction with NOP or unconditional pass
将比较/分支指令替换为NOP或无条件通过指令
LLDB runtime modification
LLDB运行时修改
lldb -n TargetApp
(lldb) breakpoint set -n "SecTrustEvaluateWithError"
(lldb) breakpoint command add 1
thread return 1
continue
DONE
lldb -n TargetApp
(lldb) breakpoint set -n "SecTrustEvaluateWithError"
(lldb) breakpoint command add 1
thread return 1
continue
DONE
4. FRAMEWORK-SPECIFIC BYPASSES
4. 框架专属绕过方案
Flutter uses Dart's
library with BoringSSL underneath. Standard Frida hooks on Java/ObjC layers don't work.
javascript
// 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 tool (recommended for Flutter apps):
bash
pip install reflutter
reflutter target.apk
Flutter使用Dart的
库,底层基于BoringSSL,Java/ObjC层的标准Frida钩子无效。
javascript
// Flutter SSL绕过 —— 必须直接钩子BoringSSL
// 在libflutter.so中查找ssl_crypto_x509_session_verify_cert_chain
var libflutter = Process.findModuleByName('libflutter.so'); // Android
// var libflutter = Process.findModuleByName('Flutter'); // iOS
// Hook ssl_verify_peer_cert (BoringSSL函数)
// 签名随Flutter版本变化 —— 使用模式匹配查找
var pattern = 'FF C3 ..'; // 示例模式,不同版本有差异
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() {}
});
// 替代方案: 使用reflutter工具自动打补丁
// reflutter target.apk
// 直接补丁Flutter引擎中的BoringSSL
reflutter工具(Flutter应用推荐使用):
bash
pip install reflutter
reflutter target.apk
Outputs patched APK that redirects traffic to your proxy
输出补丁后的APK,会将流量重定向到你的代理
Also disables SSL verification in the BoringSSL engine
同时禁用BoringSSL引擎中的SSL校验
4.2 React Native
4.2 React Native
React Native uses platform networking: OkHttp on Android, NSURLSession on iOS.
| Platform | Networking Stack | Bypass Method |
|---|
| Android | OkHttp3 | Standard OkHttp CertificatePinner hook |
| iOS | NSURLSession | Standard SecTrust hooks |
| Android (Hermes) | Same OkHttp | Same hooks, but Hermes JIT may need additional handling |
javascript
// 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) {}
});
React Native使用平台原生网络栈:Android用OkHttp,iOS用NSURLSession。
| 平台 | 网络栈 | 绕过方法 |
|---|
| Android | OkHttp3 | 标准OkHttp CertificatePinner钩子 |
| iOS | NSURLSession | 标准SecTrust钩子 |
| Android (Hermes) | 同OkHttp | 相同钩子,但Hermes JIT可能需要额外处理 |
javascript
// React Native Android —— 和OkHttp绕过逻辑一致
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) {}
});
csharp
// Xamarin pinning typically via:
// ServicePointManager.ServerCertificateValidationCallback
// or custom HttpClientHandler
javascript
// 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)
csharp
// Xamarin固定通常通过以下方式实现:
// ServicePointManager.ServerCertificateValidationCallback
// 或自定义HttpClientHandler
javascript
// Xamarin的Frida绕过(Mono runtime)
// Hook Mono方法: System.Net.ServicePointManager.set_ServerCertificateValidationCallback
var mono_method = Module.findExportByName('libmonosgen-2.0.so',
'mono_runtime_invoke');
// 更实用的方案: 在CIL层面钩子托管回调
// 使用Frida的Mono桥接或objection内置的Xamarin支持
// Objection内置Xamarin绕过:
// objection -g com.target.app explore
// > android sslpinning disable (覆盖Android端Xamarin场景)
5. CERTIFICATE TRANSPARENCY & HPKP
5. 证书透明度与HPKP
| Technology | Status | Impact on Testing |
|---|
| Certificate Transparency (CT) | Active, enforced by browsers | Mobile apps rarely enforce CT; not a bypass obstacle |
| HPKP (HTTP Public Key Pinning) | Deprecated (2018) | Legacy apps may still check; remove header from proxy response |
| Expect-CT header | Deprecated (2024) | Minimal impact on mobile testing |
| CT in mobile apps | Rare | Only Google apps enforce via custom CT checks |
| 技术 | 状态 | 对测试的影响 |
|---|
| 证书透明度(CT) | 活跃,浏览器强制要求 | 移动应用很少强制CT校验,不会成为绕过障碍 |
| HPKP(HTTP公钥固定) | 已废弃(2018年) | 老旧应用可能仍有校验,从代理响应中移除对应头即可 |
| Expect-CT头 | 已废弃(2024年) | 对移动测试影响极小 |
| 移动应用中的CT | 罕见 | 只有Google系应用通过自定义CT检查强制要求 |
6. TROUBLESHOOTING
6. 故障排查
6.1 Common Failures
6.1 常见失败场景
| Symptom | Cause | Fix |
|---|
| Bypass script loaded but traffic still fails | Multiple pinning layers | Hook ALL layers: TrustManager + OkHttp + custom checks |
| "Client certificate required" | Mutual TLS (mTLS) | Extract client cert from app bundle/keychain, import into proxy |
| Connection works but no HTTP traffic | Non-HTTP protocol (MQTT, gRPC, WebSocket) | Use Wireshark or protocol-specific proxy |
| App crashes after bypass | Anti-tampering detects hooks | Bypass integrity checks first, then SSL |
| Proxy CA not trusted | Android 7+ user CA restrictions | Install CA as system cert (Magisk module) |
| Flutter app ignores hooks | BoringSSL not hooked at native layer | Use reflutter or native BoringSSL hooks |
| Certificate chain validation timeout | OCSP stapling mismatch | Disable OCSP checks or mock OCSP responder |
| 现象 | 原因 | 修复方案 |
|---|
| 绕过脚本加载成功但流量仍失败 | 多层固定校验 | 钩子覆盖所有层:TrustManager + OkHttp + 自定义校验 |
| 提示「需要客户端证书」 | 双向TLS(mTLS) | 从应用包/钥匙串中提取客户端证书,导入到代理中 |
| 连接成功但没有HTTP流量 | 非HTTP协议(MQTT、gRPC、WebSocket) | 使用Wireshark或对应协议的专属代理 |
| 绕过完成后应用崩溃 | 反篡改检测识别到钩子 | 先绕过完整性校验,再处理SSL绕过 |
| 代理CA不被信任 | Android 7+用户CA权限限制 | 将CA安装为系统证书(Magisk模块) |
| Flutter应用忽略钩子 | 没有在原生层钩子BoringSSL | 使用reflutter或原生BoringSSL钩子 |
| 证书链校验超时 | OCSP stapling不匹配 | 禁用OCSP检查或模拟OCSP响应器 |
6.2 Diagnostic Steps
6.2 诊断步骤
Verify proxy CA is installed correctly
验证代理CA安装正确
adb shell "ls /system/etc/security/cacerts/ | grep $(openssl x509 -subject_hash_old -in ca.pem | head -1)"
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
iOS: 设置 → 通用 → 关于本机 → 证书信任设置
Check if target app is actually using SSL (vs. plain HTTP)
检查目标应用是否实际使用SSL(而非明文HTTP)
Wireshark filter: tcp.port == 443 and ip.addr == <device_ip>
Wireshark过滤规则: tcp.port == 443 and ip.addr == <设备IP>
Check if Frida is hooking the right process
检查Frida是否钩子到正确的进程
frida-ps -U | grep target
frida-ps -U | grep target
Verbose Frida output for debugging hooks
开启Frida详细输出调试钩子
frida -U -f com.target.app -l bypass.js --debug
frida -U -f com.target.app -l bypass.js --debug
7. SSL PINNING BYPASS DECISION TREE
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
需要拦截移动应用HTTPS流量
│
├── 平台?
│ ├── Android ↓
│ │ ├── 有Root设备可用?
│ │ │ ├── 是 → Frida通用绕过 (§2.1) [优先尝试]
│ │ │ │ ├── 生效? → 完成
│ │ │ │ └── 失败? → 添加Conscrypt + Volley钩子
│ │ │ ├── 仍失败? → LSPosed + TrustMeAlready (§2.4)
│ │ │ └── 仍失败? → 将CA安装为系统证书 (§2.5)
│ │ └── 无Root?
│ │ ├── 调试构建版本? → 网络安全配置修改 (§2.3)
│ │ └── 正式构建版本? → 反编译 + 补丁 + 重打包 (§2.6)
│ │
│ └── iOS ↓
│ ├── 有越狱设备可用?
│ │ ├── 是 → Objection ios sslpinning disable (§3.2) [优先尝试]
│ │ │ ├── 生效? → 完成
│ │ │ └── 失败? → Frida SecTrust钩子 (§3.1)
│ │ ├── 仍失败? → SSL Kill Switch 2 (§3.3)
│ │ └── 仍失败? → 专属库钩子 (§3.4)
│ └── 无越狱?
│ ├── 用Frida gadget重签名 → 运行Frida钩子
│ └── 二进制补丁 → 侧载安装 (§3.5)
│
├── 是框架专属应用?
│ ├── Flutter → reflutter工具或BoringSSL原生钩子 (§4.1)
│ ├── React Native → 标准平台钩子 (§4.2)
│ └── Xamarin → Objection或Mono runtime钩子 (§4.3)
│
├── 绕过后仍有问题?
│ ├── 需要客户端证书? → 提取 + 导入到代理 (§6.1)
│ ├── 非HTTP协议? → 对应协议专属工具 (§6.1)
│ └── 应用崩溃? → 先绕过反篡改校验 (§6.1)
│
└── 所有方法都失败?
├── 网络层面分析流量 (Wireshark/tcpdump)
├── 检查是否为自定义私有协议
└── 考虑iptables + 透明代理方案
8. PROXY SETUP QUICK REFERENCE
8. 代理配置快速参考
| Proxy Tool | Best For | SSL Bypass Integration |
|---|
| Burp Suite | Full HTTP analysis | Import CA to device |
| mitmproxy | Scripted interception | mitmproxy --set confdir=~/.mitmproxy
|
| Charles Proxy | macOS-native, easy setup | Built-in CA installation |
| Proxyman | macOS/iOS native | Direct iOS device support |
| HTTP Toolkit | Quick Android setup | Automated CA + Frida bypass |
| 代理工具 | 适用场景 | 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
Android代理配置
adb shell settings put global http_proxy <host_ip>:8080
adb shell settings put global http_proxy <host_ip>:8080
adb shell settings put global http_proxy :0
adb shell settings put global http_proxy :0
iOS proxy: Settings → Wi-Fi → Configure Proxy → Manual
iOS代理: 设置 → Wi-Fi → 配置代理 → 手动