ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Frida绕过SSL Pinning实战:从系统层到Native层,HTTPS流量与加密参数全提取

2026/9/10 9:17:29 拓冰建站 浏览量
Frida绕过SSL Pinning实战:从系统层到Native层,HTTPS流量与加密参数全提取 三层Hook覆盖系统/OkHttp/OpenSSL全校验链路附通用脚本、踩坑清单与请求提取方案做APP接口分析和数据采集的同学大概率都遇到过这个死局手机装了抓包证书、代理也配好了Charles里要么全是unknown要么直接报SSL handshake failedAPP干脆直接断网。你以为是证书没装对折腾半天系统证书、用户证书全装了一遍结果还是不行——这就是**SSL Pinning证书钉扎**在起作用。网上能搜到的绕过方案大多停留在三四年前要么只能绕过系统默认校验遇到OkHttp自定义Pinning直接失效要么就是让你重打包、改smali一遇到加固、签名校验就闪退。更不用说现在很多APP还叠了双向认证、TLS指纹校验普通的Hook脚本根本碰不到校验点。本文从TLS校验的全链路出发用Frida实现从系统层、框架层到底层SSL库的三层Hook绕过同时完成HTTPS请求体、加密参数的完整提取。所有方案均经过数十款主流APP实测覆盖安卓7~14附可直接复用的脚本和完整踩坑清单。一、先搞懂SSL Pinning到底卡在哪一步HTTPS抓包的本质是中间人攻击代理用自己的证书冒充服务器客户端信任代理证书后流量就能被解密。而SSL Pinning的作用就是从根源上废掉这种中间人。正常的TLS握手流程中客户端只需要验证服务器证书由受信任的CA签发即可而开启Pinning后APP会在代码里内置服务器证书的公钥哈希、证书指纹或完整证书链只信任指定的证书。哪怕你把抓包证书安装到系统根目录APP自己的校验逻辑也会拒绝握手直接抛出证书验证异常。从实现层级上看Pinning通常分布在三个层面越往下越难绕过系统证书校验层基于Android系统X509TrustManager完成证书链校验安卓7默认不信任用户证书这是最基础的拦截点也是很多新手卡壳的地方。应用框架层最常见的是OkHttp的CertificatePinnerRetrofit、FastAndroidNetworking等绝大多数网络框架都基于它实现直接在代码里写死公钥哈希。Native原生层C/C实现的网络库直接调用OpenSSL/BoringSSL完成校验Java层Hook完全无效多见于加固应用、游戏、自研网络库。更进阶的对抗还包括双向客户端证书认证、TLS指纹校验、证书链完整性校验、动态下发证书等这也是单一脚本无法通杀所有APP的根本原因。二、整体绕过架构与Hook点选型Frida的核心优势是动态注入无需重打包、不用修改APP既能Hook Java层也能Hook Native层同时可以在内存中直接拦截请求数据。完整的绕过与提取链路如下图所示我们按照“从上到下、逐层排查”的思路定位校验点优先Hook Java层无效再下探到Native层最后配合请求拦截完成数据提取。三层Hook的适用场景仅系统校验拦截只需要HookX509TrustManager即可适用于原生网络请求、WebView场景。OkHttp自定义Pinning需要HookCertificatePinner这是绝大多数APP的实现方式。Native层校验需要Hook OpenSSL/BoringSSL的底层校验函数适用于加固、自研网络库的场景。三、前置环境准备在开始Hook之前必须先把基础环境搭好否则再强的脚本也跑不起来。1. 基础环境运行环境Root手机或安卓模拟器推荐安卓10~13兼容性最好安卓14需要配合Magisk和最新版Frida。Frida环境PC端安装frida-tools手机端安装对应架构、对应版本的frida-server并运行在后台。抓包工具Charles或mitmproxy提前导出根证书。系统证书安装安卓7默认不信任用户证书必须将抓包证书移动到/system/etc/security/cacerts/目录格式为哈希.0。目标APP确认包名、CPU架构32/64位、是否加固加固应用建议使用Spawn模式启动注入。2. 快速定位校验层级不用上来就堆全套脚本可以先快速排查装完系统证书后APP仍无法联网、报SSL错误说明存在Pinning。用Frida枚举类名搜索CertificatePinner、X509TrustManager能搜到说明是Java层校验。Java层Hook后仍握手失败说明存在Native层校验需要下探到so层。四、第一层系统证书校验绕过这是最基础的一层核心是Hook安卓系统的X509TrustManager让它信任所有证书同时绕过主机名校验。实现原理安卓所有HTTPS请求的证书校验最终都会调用X509TrustManager的checkServerTrusted方法校验失败就抛出CertificateException。我们直接Hook该方法空实现不抛出异常就等于让系统信任所有证书。同时还要HookHostnameVerifier强制返回true避免主机名不匹配的问题。核心脚本Java.perform(function () { // 绕过X509TrustManager证书校验 var TrustManagerImpl Java.use(com.android.org.conscrypt.TrustManagerImpl); TrustManagerImpl.checkServerTrusted.overload([Ljava.security.cert.X509Certificate;, java.lang.String).implementation function (chain, authType) { // 直接返回不抛出异常即视为校验通过 return; }; // 绕过主机名校验 var HostnameVerifier Java.use(javax.net.ssl.HostnameVerifier); var OkHostnameVerifier Java.use(okhttp3.internal.tls.OkHostnameVerifier); OkHostnameVerifier.verify.overload(java.lang.String, javax.net.ssl.SSLSession).implementation function (hostname, session) { return true; }; // 兼容HttpURLConnection的主机名校验 var DefaultHostnameVerifier Java.use(org.apache.http.conn.ssl.DefaultHostnameVerifier); DefaultHostnameVerifier.verify.overload(java.lang.String, javax.net.ssl.SSLSession).implementation function (hostname, session) { return true; }; });注意不同安卓版本的TrustManagerImpl类名可能不同部分ROM使用android.net.http.X509TrustManagerExtensions如果Hook失败可以用Java.enumerateClassLoaders遍历查找。这一层只能绕过系统默认的证书校验无法绕过OkHttp自定义Pinning。如果Hook完APP还是无法联网继续往下走。五、第二层OkHttp CertificatePinner 绕过这是目前最常见的Pinning实现方式绝大多数使用OkHttp/Retrofit的APP都采用这种方案。实现原理OkHttp通过CertificatePinner类实现证书钉扎在check方法中对比服务器证书的公钥哈希和代码中内置的哈希不匹配就抛出SSLPeerUnverifiedException。最稳定的绕过方式有两种直接Hookcheck方法空实现不抛出异常HookCertificatePinner.Builder的add方法把内置的公钥哈希替换成抓包证书的哈希。第一种最简单兼容性也最好优先使用。核心脚本Java.perform(function () { try { var CertificatePinner Java.use(okhttp3.CertificatePinner); CertificatePinner.check.overload(java.lang.String, java.util.List).implementation function (hostname, peerCertificates) { // 直接返回不做校验 return; }; // 兼容混淆后的类名如果上面的类找不到可以尝试下面的方式 // 遍历所有类搜索包含CertificatePinner特征的类 Java.enumerateLoadedClasses({ onMatch: function (className) { if (className.indexOf(CertificatePinner) ! -1) { console.log(找到CertificatePinner类: className); } }, onComplete: function () {} }); } catch (e) { console.log(OkHttp CertificatePinner Hook失败: e.message); } });混淆与适配如果APP做了代码混淆okhttp3.CertificatePinner的类名会被改成a.b.c这时候不要硬写类名通过字符串特征或者方法签名去匹配搜索Certificate pinning failure异常字符串定位抛出异常的类枚举所有实现了check方法、参数包含ListCertificate的类用Frida的trace命令跟踪SSL相关的Java调用定位校验点。到这一步90%以上的普通APP都可以正常抓包了。如果还是不行说明校验逻辑在Native层。六、第三层Native层OpenSSL/BoringSSL 绕过很多加固应用、游戏、自研网络库不会走Java层的证书校验而是直接在Native层调用OpenSSL/BoringSSL完成TLS握手和证书校验这时候Java层的Hook完全无效。实现原理Native层的证书校验核心是两个函数SSL_get_verify_result返回证书校验结果返回0表示成功非0表示失败X509_verify_cert执行证书链校验返回1表示成功。我们用Frida的Native Hook拦截这两个函数强制返回成功就能绕过Native层的Pinning。核心脚本// 等待so库加载完成后执行 setTimeout(function () { var libssl null; var libs [libssl.so, libboringssl.so, libssl.so.1.1, libssl.so.3]; for (var i 0; i libs.length; i) { try { libssl Module.findBaseAddress(libs[i]); if (libssl) { console.log(找到SSL库: libs[i]); break; } } catch (e) {} } if (!libssl) { console.log(未找到SSL库尝试全局搜索); return; } // Hook SSL_get_verify_result强制返回0校验成功 var SSL_get_verify_result Module.findExportByName(libs[i], SSL_get_verify_result); if (SSL_get_verify_result) { Interceptor.attach(SSL_get_verify_result, { onLeave: function (retval) { retval.replace(0); } }); console.log(SSL_get_verify_result Hook成功); } // Hook X509_verify_cert强制返回1校验成功 var X509_verify_cert Module.findExportByName(libs[i], X509_verify_cert); if (X509_verify_cert) { Interceptor.attach(X509_verify_cert, { onLeave: function (retval) { retval.replace(1); } }); console.log(X509_verify_cert Hook成功); } }, 2000);注意事项不同APP使用的SSL库不同除了系统的libssl.so还可能是APP自带的libcurl.so、libmbedtls.so需要先枚举模块确认。部分APP会自定义证书校验函数不是标准的OpenSSL接口这时候需要通过字符串、导入表或者堆栈定位自定义校验函数。加固APP要注意Hook时机必须等壳加载完成、so库加载后再注入建议使用Spawn模式启动。七、HTTPS请求与加密参数完整提取绕过Pinning只是第一步很多时候我们需要提取请求URL、Header、Body、加密参数甚至响应数据。这里提供两种方案覆盖不同场景。方案一抓包工具直接提取绕过Pinning后Charles或mitmproxy可以直接解密HTTPS流量查看完整的请求和响应适合绝大多数场景。如果APP不走系统代理可以用iptables转发流量或者使用VPN模式的抓包工具。方案二Frida内存直接提取针对有代理检测、走私有通道、或者流量加密的APP直接在内存中Hook网络框架的请求方法提取明文数据完全不需要走代理。以OkHttp为例HookRealCall的execute和enqueue方法打印请求信息Java.perform(function () { try { var RealCall Java.use(okhttp3.RealCall); RealCall.execute.overload().implementation function () { var request this.request(); var url request.url().toString(); var method request.method(); var body request.body(); console.log( 请求 ); console.log(Method: method); console.log(URL: url); console.log(Headers: request.headers().toString()); // 打印请求体 if (body ! null) { var buffer Java.use(okio.Buffer).$new(); body.writeTo(buffer); console.log(Body: buffer.readUtf8()); } var response this.execute(); console.log(响应码: response.code()); return response; }; } catch (e) { console.log(OkHttp请求Hook失败: e.message); } });进阶用法是直接Hook加密、签名函数在参数加密前提取明文在签名计算前提取原始参数省去逆向算法的时间。八、进阶对抗与必踩的坑实际场景中很多APP不止有Pinning还叠加了各种对抗手段这里整理了最常见的8个坑和解决方案。双向客户端证书认证APP要求客户端携带证书才能完成握手这时候光绕过服务端校验没用。需要从APK或内存中提取客户端证书和私钥HookKeyManager的chooseClientAlias方法指定使用抓包工具的客户端证书或者直接导入证书到系统。代理检测APP检测系统代理后直接不走代理甚至断网。可以HookProxySelector强制返回NO_PROXY或者用iptables将流量转发到抓包端口也可以使用VPN模式的抓包工具。TLS指纹校验服务器通过JA3/JA3S指纹识别抓包工具即使证书校验通过也会返回异常。可以用Frida修改底层TLS扩展、密码套件顺序或者使用支持指纹定制的代理工具。Frida与Root检测APP检测Frida、检测Root、检测调试会直接闪退或返回假数据。需要先过反调试使用Frida隐身脚本、修改frida-server端口和包名、配合Magisk Hide隐藏Root必要时使用Frida的Spawn模式提前注入。多进程与多Dex很多APP有多个进程网络请求可能在子进程中需要用--enable-jit并注入所有进程加固APP的Dex会动态加载需要等Dex加载完成后再Hook。安卓14兼容性安卓14加强了SELinux限制和命名空间隔离旧版Frida会注入失败。建议使用Frida 16.2以上版本配合Magisk的frida-magisk模块关闭SELinux的严格模式。Hook时机错误导致崩溃如果在APP启动早期就Hook还没加载的类会导致崩溃。建议使用延迟Hook、类加载监听或者用Spawn模式启动APP在合适的时机执行Hook。证书链与公钥校验部分APP不校验完整证书只校验公钥哈希、证书序列号或者证书链长度这时候需要针对性Hook对应的校验函数而不是只Hook标准接口。九、写在最后SSL Pinning的绕过从来没有万能脚本本质是找到校验点强制返回成功。不同APP的校验层级、实现方式都不一样需要按照“系统层→框架层→Native层”的顺序逐层排查而不是上来就堆一堆脚本。Frida的价值在于动态调试能力它可以让我们在不重打包、不修改APP的情况下快速定位校验点、验证绕过方案同时直接在内存中提取数据。但也要清楚绕过证书校验只是接口分析的第一步后面还有签名算法、参数加密、设备指纹、风控对抗每一步都需要对应的逆向和工程能力。最后提醒所有技术方案仅用于合法的接口分析、安全测试与学习请遵守相关法律法规不要用于非法数据采集。