14、Frida绕过证书绑定:Frida框架介绍、Frida Hook技术、Frida绕过证书绑定脚本
好,咱们今天聊点硬核的。前面几章我们把证书绑定的原理和实现方式都捋了一遍,也讲了怎么用Xposed去Hook它。但说实话,在真实的Android逆向战场上,Frida才是我的主力武器。
为什么?因为Frida不需要重启手机,不需要修改APK,甚至不需要Root权限(某些场景下)。你写一段JavaScript脚本,就能动态地注入到目标进程里,想Hook哪个函数就Hook哪个函数。这感觉,就像你拿着一把手术刀,直接对运行中的App做「开胸手术」。
我个人习惯把Frida比作「移动端的调试器Pro Max版」。它比Xposed更灵活,比直接改Smali更高效。今天我们就来彻底搞懂它,并且用它干掉证书绑定。
14.1 Frida框架介绍
Frida,全称是「Frida Dynamic Instrumentation Toolkit」。说白了,它是一个动态插桩工具。你不需要提前修改App的代码,而是在App运行的时候,把我们的代码「注射」进去。
它的核心架构是这样的:
你看,整个流程很清晰。你在电脑上写JavaScript脚本,通过USB或者TCP把脚本发给手机上的frida-server,frida-server再把脚本注入到目标App的进程里。然后你的脚本就可以在App内部为所欲为了。
核心要点:Frida的工作模式是C/S架构。电脑是客户端,手机是服务端。服务端(frida-server)负责注入,客户端(frida-tools)负责发送脚本和接收结果。
我记得我第一次用Frida的时候,最震撼的一点是:不需要重启App。你写好了脚本,保存,然后在命令行里敲一下回车,脚本就生效了。如果写错了,改一下,再敲回车,新的脚本又进去了。这种「热更新」式的调试体验,比Xposed那种改完代码还要重启手机的方式,不知道高到哪里去了。
14.2 Frida Hook技术
Frida的Hook技术,说白了就两种:Java层Hook和Native层Hook。我们做证书绑定绕过,99%的情况都是在Java层动手脚。因为大部分App的证书校验逻辑,都是用Java写的。
14.2.1 Java层Hook基础
Frida的Java层Hook,用的是JavaScript语法。你可能会问:「我一个搞Android的,还得学JavaScript?」别担心,Frida的JS API非常简洁,你花10分钟就能上手。
来看一个最基础的例子:
// 1. 找到要Hook的类
var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
// 2. 找到要Hook的方法
TrustManagerImpl.checkServerTrusted.implementation = function(certs, authType) {
console.log('[+] 绕过证书校验!');
// 直接返回,不进行任何校验
return;
};
这段代码干了什么?它找到了Android系统里负责证书校验的类TrustManagerImpl,然后把它的checkServerTrusted
小技巧:如果你不确定目标App用的是哪个类来做证书校验,可以先用Frida的Java.enumerateLoadedClasses()枚举所有已加载的类,然后过滤出包含"TrustManager"、"SSL"、"Certificate"等关键字的类。我在项目中经常用这招来快速定位目标。
14.2.2 常用Hook模式
在实际工作中,我总结了几种最常用的Hook模式:
| 模式 | 适用场景 | 代码示例 |
|---|---|---|
| 替换实现 | 直接跳过校验逻辑 | method.implementation = function() { return; } |
| 修改参数 | 篡改传入的参数值 | method.implementation = function(a, b) { a = 'hacked'; return this.method(a, b); } |
| 修改返回值 | 伪造返回结果 | method.implementation = function() { return true; } |
| 调用原方法 | 在原始逻辑前后插入代码 | method.implementation = function() { console.log('before'); var ret = this.method(); console.log('after'); return ret; } |
你想想看,有了这四种模式,基本上你能想到的任何Hook需求都能满足了。特别是「调用原方法」这个模式,我经常用它来打印函数的入参和返回值,用来分析App的通信协议。
14.2.3 动态加载与时机问题
这里有个坑,我必须提醒你。Frida的Hook脚本是在App启动之后才注入的。如果App在启动的瞬间就完成了证书校验,你的脚本可能还没来得及Hook上去,校验就已经结束了。
我曾经在一个金融App上遇到过这个问题。App在Application的onCreate里就做了证书绑定,我的脚本还没加载完,它就已经校验失败了。怎么办?
解决方案是:使用Frida的延迟加载机制。你可以让脚本等待目标类加载完成后再进行Hook:
// 等待类加载完成
Java.perform(function() {
// 延迟100ms,确保类已经加载
setTimeout(function() {
var TargetClass = Java.use('com.example.MyTrustManager');
TargetClass.checkServerTrusted.implementation = function() {
console.log('[+] 延迟Hook成功!');
return;
};
}, 100);
});
或者更稳妥的做法,是用Java.enumerateLoadedClasses配合回调,等目标类出现时再Hook。嗯,这里要注意,时机问题是Frida使用中最容易翻车的地方,没有之一。
14.3 Frida绕过证书绑定脚本
好了,理论知识讲完了。咱们直接上干货——一个完整的、经过实战检验的Frida绕过证书绑定脚本。
这个脚本我用了很久,从Android 6到Android 14,从OkHttp到HttpsURLConnection,基本上通吃。它的核心思路是:Hook所有可能做证书校验的地方,一个都不放过。
// 通用Frida绕过证书绑定脚本
// 作者:资深移动安全工程师
// 适用:Android 6 - 14,OkHttp / HttpsURLConnection / WebView
Java.perform(function() {
console.log('[+] 开始绕过证书绑定...');
// ========== 1. 绕过 TrustManager 校验 ==========
try {
var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');
TrustManagerImpl.checkServerTrusted.implementation = function(certs, authType) {
console.log('[+] 绕过 TrustManagerImpl.checkServerTrusted');
return;
};
console.log('[✓] TrustManagerImpl 已Hook');
} catch(e) {
console.log('[-] TrustManagerImpl 未找到: ' + e);
}
// ========== 2. 绕过 X509TrustManager 校验 ==========
try {
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
X509TrustManager.checkServerTrusted.implementation = function(chain, authType) {
console.log('[+] 绕过 X509TrustManager.checkServerTrusted');
return;
};
X509TrustManager.checkClientTrusted.implementation = function(chain, authType) {
console.log('[+] 绕过 X509TrustManager.checkClientTrusted');
return;
};
console.log('[✓] X509TrustManager 已Hook');
} catch(e) {
console.log('[-] X509TrustManager 未找到: ' + e);
}
// ========== 3. 绕过 HostnameVerifier 校验 ==========
try {
var HostnameVerifier = Java.use('javax.net.ssl.HostnameVerifier');
HostnameVerifier.verify.implementation = function(hostname, session) {
console.log('[+] 绕过 HostnameVerifier.verify: ' + hostname);
return true;
};
console.log('[✓] HostnameVerifier 已Hook');
} catch(e) {
console.log('[-] HostnameVerifier 未找到: ' + e);
}
// ========== 4. 绕过 OkHttp 的 CertificatePinner ==========
try {
var CertificatePinner = Java.use('okhttp3.CertificatePinner');
CertificatePinner.check.implementation = function(hostname, peerCertificates) {
console.log('[+] 绕过 OkHttp CertificatePinner: ' + hostname);
return;
};
console.log('[✓] OkHttp CertificatePinner 已Hook');
} catch(e) {
console.log('[-] OkHttp CertificatePinner 未找到: ' + e);
}
// ========== 5. 绕过 WebView 的 SSL 校验 ==========
try {
var WebViewClient = Java.use('android.webkit.WebViewClient');
WebViewClient.onReceivedSslError.implementation = function(view, handler, error) {
console.log('[+] 绕过 WebView SSL错误: ' + error);
handler.proceed(); // 继续加载,忽略错误
};
console.log('[✓] WebView SSL 已Hook');
} catch(e) {
console.log('[-] WebView SSL 未找到: ' + e);
}
console.log('[✓] 所有证书绑定绕过完成!');
});
重要警告:这个脚本仅供安全研究和授权测试使用。未经授权对他人App进行抓包和逆向,是违法行为。我曾经见过有人因为用这个脚本抓取竞品数据,最后吃了官司。请务必在法律允许的范围内使用。
14.3.1 脚本使用方式
把这个脚本保存为bypass_ssl.js,然后在命令行里执行:
# 1. 启动frida-server(在手机上)
adb shell su -c '/data/local/tmp/frida-server &'
# 2. 运行脚本(在电脑上)
frida -U -f com.target.app -l bypass_ssl.js --no-pause
参数说明:
-U:连接USB设备-f com.target.app:启动目标App的包名-l bypass_ssl.js:加载我们的脚本--no-pause:不暂停,直接运行
14.3.2 脚本设计思路
你可能会问:「为什么要Hook这么多地方?只Hook一个TrustManager不行吗?」
答案是:不行。不同的App用了不同的网络库。有的用OkHttp,有的用原生的HttpsURLConnection,有的用WebView。甚至同一个App里,不同的网络请求可能走了不同的校验路径。
我记得有一次,我帮一个朋友分析某个社交App。我Hook了TrustManager,抓包工具能抓到登录接口的数据了。但到了图片上传接口,死活抓不到。后来才发现,图片上传用的是OkHttp的CertificatePinner,我根本没Hook它。加上之后,一切正常。
所以,我的经验是:宁可多Hook,不可漏Hook。把所有可能做证书校验的地方全部覆盖,这样不管App走哪条路,都会被我们拦截。
14.4 常见问题与避坑指南
最后,分享几个我在实战中踩过的坑,希望能帮你少走弯路。
避坑指南:
- 问题1:脚本注入成功,但抓包工具还是看不到流量。
原因:App可能用了Native层的证书校验,比如用C++写的OpenSSL。解决方案:需要Hook Native层的SSL_read/SSL_write函数,这个我们后面会讲。 - 问题2:Hook了TrustManager,但App直接崩溃。
原因:有些App会检测TrustManager是否被篡改。解决方案:用Frida的Java.choose动态查找实例,而不是用Java.use静态Hook。 - 问题3:脚本在Android 14上不工作。
原因:Android 14加强了运行时权限检查。解决方案:确保frida-server版本是最新的(15.2.0以上),并且使用--codeshare参数。
我曾经在一个Android 14的设备上折腾了整整两天,就是因为frida-server版本太旧。升级到最新版后,问题迎刃而解。所以,保持工具版本更新,是安全工程师的基本素养。
好了,关于Frida绕过证书绑定,我们就聊到这里。你把这个脚本保存好,以后遇到大部分App的证书绑定,都能用得上。记住,工具是死的,思路是活的。理解了Frida的Hook原理,你就能举一反三,应对各种奇奇怪怪的校验逻辑。
公众号:蓝海资料掘金营,微信deep3321