当前位置: 首页 > news >正文

【Frida Android】实战篇5:SSL Pinning 证书绑定绕过 Hook 教程(二)

文章目录

  • 1. 前言
  • 2. 方案简介
  • 3. 应用修改
    • 步骤1:在清单文件中启用配置
    • 步骤2:创建具体的配置文件
    • 校验不通过的表现
  • 4. Hook 流程
    • 方案一:直接“跳过”关键检查步骤
      • 核心逻辑
      • 完整脚本
      • 为什么这样有效?
    • 方案二:用“自己人”替换系统的“保安”
      • 核心逻辑
      • 完整脚本
      • 为什么这样有效?
    • 方案总结
  • 5. 本章总结
  • 6. 下章预告

⚠️本博文所涉安全渗透测试技术、方法及案例,仅用于网络安全技术研究与合规性交流,旨在提升读者的安全防护意识与技术能力。任何个人或组织在使用相关内容前,必须获得目标网络 / 系统所有者的明确且书面授权,严禁用于未经授权的网络探测、漏洞利用、数据获取等非法行为。

1. 前言

在上一章里,我们学习了如何绕过通过X509TrustManager实现的证书绑定——简单说就是直接“修改”了负责检查证书的“保安”,让它对所有证书都放行。但在实际开发中,企业更常用另一种更规范的证书绑定方式:通过network_security_config.xml配置文件来实现。这种方式是Android系统在7.0版本后专门推出的“官方规范”,某些大厂会用它来保障App的网络安全。本章就来学习如何绕过这种更“标准”的证书绑定,帮你搞懂其中的原理和操作方法。

本章节使用的示例 APK 和 APK 源码如下:
链接: https://pan.baidu.com/s/1dhKQqjcle1tLv-q_C6KQlg?pwd=b65b
提取码: b65b

2. 方案简介

network_security_config.xml是Android 7.0及以上系统提供的“网络安全配置文件”,它的核心作用可以简单理解为:给系统自带的证书检查规则“加额外条件”

打个比方:系统默认的证书检查(由TrustManager负责)就像小区保安,会核对访客的“身份证”(证书)是否有效;而network_security_config.xml就像小区新增的规定——比如“只允许住在某几栋楼的人进入”,保安在核对身份证后,还要额外检查是否符合这个新规定。

其中最常用的“额外规定”就是“证书指纹绑定(PinSet)”,比如这样配置:

<!-- res/xml/network_security_config.xml -->
<network-security-config><base-config><pin-set><!-- 配置服务器证书的指纹,只有匹配的证书才被信任 --><pin digest="SHA-256">abc123...</pin></pin-set></base-config>
</network-security-config>

这段配置的意思是:无论证书本身是否有效,只有指纹是abc123...的证书才会被信任。

它的工作逻辑很简单:

  1. App依然用系统自带的“保安”(TrustManager)来检查证书;
  2. 但这个“保安”会多做一步:检查服务器返回的证书指纹是否和network_security_config.xml里配置的一致;
  3. 不一致?直接“拒之门外”(断开连接并报错)。

3. 应用修改

要给App加上这种证书绑定,步骤很简单,分两步:

步骤1:在清单文件中启用配置

打开AndroidManifest.xml(App的“身份清单”),在application标签里加一行配置,告诉系统“我要用自定义的网络安全规则”:

<application...android:networkSecurityConfig="@xml/network_security_config"> <!-- 新增这行 -->
</application>

这里的@xml/network_security_config就是告诉系统:配置文件在res/xml文件夹下,名叫network_security_config.xml

步骤2:创建具体的配置文件

res/xml文件夹下新建network_security_config.xml,填入具体的绑定规则,比如:

<?xml version="1.0" encoding="utf-8"?>
<network-security-config><!-- 针对特定域名的配置 --><domain-config cleartextTrafficPermitted="false"> <!-- 禁止明文传输(只允许HTTPS) --><domain includeSubdomains="true">x.x.x.x</domain> <!-- 要绑定的域名(包括子域名) --><pin-set expiration="2035-12-31"> <!-- 证书指纹配置,过期时间到2035年 --><pin digest="SHA-256">xxxxxx</pin> <!-- 服务器证书的SHA-256指纹 --></pin-set></domain-config>
</network-security-config>

配置项说明:

  • domain:指定要生效的域名(比如api.example.com),includeSubdomains="true"表示子域名也生效;
  • cleartextTrafficPermitted="false":禁止该域名的明文HTTP请求,只能用HTTPS;
  • pin-set:证书指纹绑定的核心,digest="SHA-256"表示指纹算法,xxxxxx是具体的证书指纹;
  • expiration:配置的过期时间,到期后该绑定规则失效。

校验不通过的表现

启动本地服务的 python 脚本与上一章相同,本章不再重复。

如果App连接的服务器证书指纹和配置不匹配,会直接报错,比如:

在这里插入图片描述

查看日志(logcat)会看到类似这样的错误信息:

Caused by: java.security.cert.CertificateException: java.security.cert.CertPathValidatorException: Trust anchor for certification path not found.at com.android.org.conscrypt.TrustManagerImpl.verifyChain(TrustManagerImpl.java:674)at com.android.org.conscrypt.TrustManagerImpl.checkTrustedRecursive(TrustManagerImpl.java:549)at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:505)at com.android.org.conscrypt.TrustManagerImpl.checkTrusted(TrustManagerImpl.java:425)at com.android.org.conscrypt.TrustManagerImpl.getTrustedChainForServer(TrustManagerImpl.java:353)at android.security.net.config.NetworkSecurityTrustManager.checkServerTrusted(NetworkSecurityTrustManager.java:94)
2025-11-15 09:39:07.056  3956-4041  NetworkService          com.example.fridaapk                 E  	at android.security.net.config.RootTrustManager.checkServerTrusted(RootTrustManager.java:90)at com.android.org.conscrypt.ConscryptEngineSocket$2.checkServerTrusted(ConscryptEngineSocket.java:163)at com.android.org.conscrypt.Platform.checkServerTrusted(Platform.java:255)at com.android.org.conscrypt.ConscryptEngine.verifyCertificateChain(ConscryptEngine.java:1638)at com.android.org.conscrypt.NativeCrypto.ENGINE_SSL_read_direct(Native Method)at com.android.org.conscrypt.NativeSsl.readDirectByteBuffer(NativeSsl.java:569)at com.android.org.conscrypt.ConscryptEngine.readPlaintextDataDirect(ConscryptEngine.java:1095)at com.android.org.conscrypt.ConscryptEngine.readPlaintextData(ConscryptEngine.java:1079)

从日志能看出证书检查的流程(简单理解):

服务器返回证书 → 系统检查证书是否有效(TrustManagerImpl) → 检查是否符合network配置(NetworkSecurityTrustManager) → 不匹配则报错

4. Hook 流程

启动 Frida_Sever 服务、Python 启动脚本与《实战篇4》的步骤相同,本章聚焦 Hook 脚本的编写,之前的步骤不再重复。

要绕过这种证书绑定,核心是“让系统的检查规则失效”。下面两种方案都能实现,原理不同但目标一致。

方案一:直接“跳过”关键检查步骤

这种方案的思路是:找到证书检查流程中的关键方法,直接修改它们的逻辑,让检查“通过”。

这里通过上一章的 Logcat 日志和 Android 源码(需要网络较好):

# AOSP 源码# TrustManagerImpl:getTrustedChainForServer 有4个重载方法
https://cs.android.com/android/platform/superproject/main/+/main:external/conscrypt/repackaged/common/src/main/java/com/android/org/conscrypt/TrustManagerImpl.java;l=1?q=com%2Fandroid%2Forg%2Fconscrypt%2FTrustManagerImpl.java&sq=&hl=zh-cn# NetworkSecurityTrustManager:checkPins 方法中调用 isPinningEnforced 方法
https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/security/net/config/NetworkSecurityTrustManager.java;l=1?q=frameworks%2Fbase%2Fcore%2Fjava%2Fandroid%2Fsecurity%2Fnet%2Fconfig%2FNetworkSecurityTrustManager.java&hl=zh-cn

核心逻辑

  1. 绕开系统的基础证书校验(TrustManagerImplgetTrustedChainForServer方法);
  2. 绕开network_security_config.xml的绑定检查(NetworkSecurityTrustManagerisPinningEnforcedcheckPins方法)。

完整脚本

语法技巧:前面说到getTrustedChainForServer有4个重载方法,一个个hook太麻烦,如何一次性绕过所有重载方法。

  1. TrustManagerImpl.getTrustedChainForServer 是 Android 系统中负责对服务器提供的证书链进行校验的关键方法。
  2. 核心操作: - 使用 overloads.forEach 遍历该方法的所有重载版本。
  3. 对每个重载版本都替换其实现(implementation),即 hook 操作。
  4. Hook 后的行为: - 当应用调用 getTrustedChainForServer 方法时,不执行原本的证书校验逻辑,而是直接将服务器传入的证书数组(arguments[0])通过 arrayToList 转换为 List 并返回。
import Java from "frida-java-bridge";Java.perform(function() {console.log("[*] 开始绕过证书绑定...");// 获取系统中负责基础证书校验的类(TrustManagerImpl)var TrustManagerImpl = Java.use('com.android.org.conscrypt.TrustManagerImpl');// 获取负责network配置检查的类(NetworkSecurityTrustManager)var NetworkSecurityTrustManager = Java.use('android.security.net.config.NetworkSecurityTrustManager');// 辅助工具类(将数组转成List)var ArrayList = Java.use('java.util.ArrayList');// 辅助函数:把证书数组转成系统需要的List格式function arrayToList(array) {var list = ArrayList.$new();if (array != null) {for (var i = 0; i < array.length; i++) {list.add(array[i]);}}return list;}// 绕过基础证书校验:不管证书是否有效,直接返回服务器的证书链if (TrustManagerImpl.getTrustedChainForServer) {TrustManagerImpl.getTrustedChainForServer.overloads.forEach(function(overload) {overload.implementation = function() {console.log("[*] 已绕过基础证书校验");// 直接把服务器返回的证书数组转成List返回(假装校验通过)return arrayToList(arguments[0]);};});}// 关闭证书绑定强制检查:告诉系统“不需要检查绑定规则”if (NetworkSecurityTrustManager.isPinningEnforced) {NetworkSecurityTrustManager.isPinningEnforced.implementation = function() {console.log("[*] 已关闭证书绑定强制检查");return false; // 返回false表示“不强制检查绑定”};}// 跳过证书绑定的具体检查:即使需要检查,也直接“通过”if (NetworkSecurityTrustManager.checkPins) {NetworkSecurityTrustManager.checkPins.implementation = function() {console.log("[*] 已跳过证书绑定检查");// 空实现:不做任何检查,相当于“通过”};}console.log("[+] 证书绑定绕过完成");
});

为什么这样有效?

  • getTrustedChainForServer是系统判断“证书是否有效”的核心方法,修改后直接返回服务器的证书(不管是否有效),相当于“基础检查通过”;
  • isPinningEnforced控制是否启用network_security_config的绑定规则,返回false就是“不启用”;
  • checkPins是具体对比证书指纹的方法,空实现就是“不对比,直接过”。

方案二:用“自己人”替换系统的“保安”

这种方案更彻底:直接创建一个“不做任何检查”的信任管理器(TrustManager),然后替换系统原来的,让所有证书检查都由“自己人”负责(自然就通过了)。

核心逻辑

  1. 自定义一个“无校验”的TrustManager(不管证书是否有效、是否匹配绑定规则,都放行);
  2. 拦截系统初始化信任管理器的过程(SSLContext.init方法),用自定义的替换原来的。

完整脚本

import Java from "frida-java-bridge";Java.perform(function () {console.log('[*] 开始绕过 SSL 证书校验...');// 创建自定义的“无校验”信任管理器const trustManager = Java.registerClass({name: 'com.example.CustomTrustManager', // 自定义类名implements: [Java.use("javax.net.ssl.X509TrustManager")], // 实现系统的TrustManager接口methods: {// 客户端证书校验:空实现(不检查)checkClientTrusted: function (chain, authType) {},// 服务器证书校验:空实现(不检查,直接放行)checkServerTrusted: function (chain, authType) {},// 信任的CA列表:返回空(不限制任何CA)getAcceptedIssuers: function () { return []; }}}).$new(); // 创建实例// 拦截SSLContext的初始化方法,替换信任管理器Java.use("javax.net.ssl.SSLContext").init.overload("[Ljavax.net.ssl.KeyManager;","[Ljavax.net.ssl.TrustManager;","java.security.SecureRandom").implementation = function (keyManagers, trustManagers, secureRandom) {console.log("[+] 已拦截SSLContext初始化,替换为自定义TrustManager");// 忽略系统原来的trustManagers,传入我们自己的“无校验”管理器this.init(keyManagers, [trustManager], secureRandom);};console.log('[*] SSL 证书校验绕过完成');
});

为什么这样有效?

  • 所有HTTPS连接的证书检查,最终都由SSLContext里的TrustManager负责;
  • 我们创建的CustomTrustManager对所有校验都“放行了事”;
  • 拦截SSLContext.init后,系统无论原来用什么TrustManager,都会被换成我们的“自己人”,自然就绕过了所有检查(包括network_security_config的绑定)。

方案总结

方法1和方法2本质上都是为了绕过证书绑定,但思路不同:

  • 方法1是“针对性破解”:它精准定位network_security_config.xml配置生效的关键环节(比如NetworkSecurityTrustManager的绑定检查、TrustManagerImpl的证书链校验),直接“跳过”这些具体步骤,相当于“堵住了这个配置的生效路径”,但不影响系统其他默认的证书校验逻辑。
  • 方法2是“釜底抽薪”:它不关心具体的配置细节,而是直接替换了整个证书校验的“执行者”——SSLContext中的TrustManager。因为所有证书校验(包括系统默认规则、network_security_config.xml的额外配置)最终都要通过TrustManager来执行,当我们用“无校验”的自定义TrustManager替换系统默认的管理器后,原本依赖系统管理器才能生效的network_security_config.xml配置,自然就失去了作用(相当于换了一个“完全不看规则”的保安,原来的规定也就无效了)。

简单说:方法1是“拆零件”,只针对network_security_config.xml相关的校验步骤;方法2是“换机器”,直接让所有依赖原校验机制的规则(包括该配置)都失效,适用范围更广。

5. 本章总结

本章学习了通过network_security_config.xml配置的证书绑定及其绕过方法:

  1. network_security_config.xml是Android 7+的系统级配置,作用是给证书检查加“额外规则”(如证书指纹绑定);
  2. 绕过方案一:直接Hook关键检查方法(TrustManagerImpl.getTrustedChainForServerNetworkSecurityTrustManager的相关方法),跳过校验;
  3. 绕过方案二:创建“无校验”的TrustManager,替换系统默认的,从根源上关闭所有检查。

两种方案各有优势:方案一更针对性(只改必要步骤),方案二更通用(覆盖所有场景)。

6. 下章预告

证书绑定不仅可以通过系统配置实现,很多App还会用第三方网络库(如OkHttp)自己实现证书绑定。下一章我们将学习如何绕过基于OkHttp库的证书绑定,进一步完善证书校验绕过的技能。

http://www.dtcms.com/a/618707.html

相关文章:

  • 东丰网站建设邮件格式模板
  • VB6安全子类化,关闭IDE数据丢失,SetProp写入数据
  • 毕业设计代做网站jsp注册商标设计
  • 网站视频无法播放怎么办湖南省建设厅宁艳芳
  • shell的基础
  • 解决 Oracle 11g Data Guard ORA-16047 的实战经验
  • 友情链接网站源码网站搭建源码
  • 手机做公司网站wordpress二次开发主题
  • RabbitMQ四种交换器类型详解及示例
  • 网站配图尺寸信息流是sem还是seo
  • 安微凤阳县建设局网站网页设计html模板下载
  • 精品网站设计商标logo图片
  • RK3588平台部署MNN和OPENCL
  • 基于Spring Cloud的电商系统设计与实现——用户与商品模块的研究(下)
  • 网站触屏版建站软件排行榜
  • docker-study
  • 为什么建设厅的网站不好打开龙华网站开发公司电话
  • 网站建设方案书是啥外贸网站建设深圳
  • 基础算法精讲 13 | 二叉树的层序遍历
  • 网站设计包含哪些技术wordpress数据库更改账号密码
  • 如何通过reactor实现流式响应接口
  • vue-leaflet使用教程(一)
  • 江苏省徐州市建设银行网站技术培训网站
  • 如何取外贸网站域名建设网站平台费
  • python 贪心-dfs-dp
  • Android Studio - 使用 BuildConfig
  • 在ec2上部署Qwen2.5omini和Qwen3omini模型
  • 设备通信的艺术:从协议选型、性能调优到自定义实现的全维度技术实践
  • 过滤器模式、责任链模式
  • 做货源的网站郑州企业免费建站