小程序SSL验证绕过与代理抓包实战:从证书信任到Frida Hook

发布时间:2026/10/21 6:53:42
小程序SSL验证绕过与代理抓包实战:从证书信任到Frida Hook 简介破解支付宝小程序SSL验证的Frida辅助工具包面向移动端安全测试、逆向分析及日常抓包调试人员尤其适合需要分析小程序接口数据、开展支付链路安全评估的读者。针对支付宝小程序证书锁定导致代理无法抓包的问题资源提供绕过SSL验证的完整思路与可运行脚本并附有原理说明帮助读者快速搭建代理抓包环境。压缩包共3个文件包含Python主脚本、JavaScript Hook脚本及Markdown说明文档Py脚本负责Frida注入与参数传递JS脚本实现Hook证书校验函数MD文档覆盖使用步骤、脚本逻辑与注意事项整体仅2KB轻量且便于按需修改。目前已有3014人学习下载适合具备基础Frida使用经验、希望深入小程序安全检测的读者。完成配置后读者可掌握基于Frida的SSL绕过技巧并理解支付宝小程序启动流程与证书校验机制为后续漏洞挖掘、接口分析或合规测试提供实用参考。1. 某支付平台小程序SSL验证与代理抓包为什么全局证书不够用接到一个授权测试任务目标是某支付平台的小程序需要把它发出的 HTTPS 请求完整抓下来分析签名逻辑。常规操作是电脑上开好代理手机把 WiFi 代理指过去安装抓包工具的根证书然后信心满满地打开小程序。结果流量面板里刷出来一片 TLS 握手失败或者干脆只有 CONNECT 隧道看不到任何明文请求。换一台没装证书的手机对比表现完全一样。这时候才意识到真正挡住我们的不是系统证书信任而是小程序内置的 SSL 验证逻辑。这篇文章记录我拆这个问题的完整过程先讲清楚 SSL 验证为什么让代理失效再给出一条可复现的绕过路线最后附上实战里最容易踩的五个坑和验证方法。内容面向移动端开发和安全测试上手不需要太多逆向基础但得能接受折腾。2. 代理抓包为什么只能看到TLSSSL验证的两个层次2.1 系统CA信任与代理证书第一层校验HTTPS 抓包工具的原理是把自己伪装成目标服务器。代理工具会拦截客户端发起的 TLS 连接然后用自己的根证书动态签发一张目标域名的证书。只要客户端信任这个根证书握手就能正常完成代理在中间既能看到请求也能解密响应。这一套能否生效第一步取决于客户端操作系统的证书信任链。iOS 和 Android 都内置了一个系统 CA 列表抓包工具的根证书如果没被安装系统在验证服务器证书链时就会直接报错。所以常规抓包教程都会要求“安装并信任根证书”。但这一步只能解决系统层面的校验对大多数普通 App 有效对小程序未必。某支付平台的小程序虽然跑在宿主 App 里但它的网络请求并不是完全走系统默认网络栈。为了安全开发者在封装请求库时通常会额外开启一层校验在代码里指定只信任某个固定证书或公钥。这就是常说的 SSL Pinning也就是第二层校验。这层校验不受系统 CA 列表控制因为校验逻辑跑在 JavaScript 或者原生层里即使你信任了抓包工具的证书它照样拒绝握手。2.2 代码内SSL Pinning真正的黑匣子第二层校验常见实现方式有三种第一种是证书校验代码里预埋了服务器的证书内容握手时拿到服务器证书后逐字节对比第二种是公钥校验只比对服务器证书里的公钥哈希第三种是自定义校验逻辑在系统回调里追加一堆 base64 字符串比对逻辑。第三种最难缠因为它的结果不一定走系统标准错误码经常是错得莫名其妙。对小程序来说这层逻辑通常被编译进了运行时的 JS 包或者宿主 App 的 native 层。前者可以直接在解包后的 JavaScript 里搜关键字定位后者则要借用 Frida 之类动态插桩工具来 Hook 底层 OpenSSL 和系统网络库。很多人在这时候会去改代理工具的高级设置比如启用 SSL 代理、忽略证书校验等但这些选项作用在代理端改变不了客户端的校验行为。正确的思路是让客户端根本不做校验或者让它以为握手的是真正的服务器。2.3 双向校验与服务端指纹更极端的组合更麻烦的情况是双向 TLS 校验。不仅客户端要验证服务器服务器也要求客户端提供证书。代理工具在中间模拟服务器时拿不到客户端原本要发送的证书即使客户端不校验服务器代理也会因缺少客户端证书而握手失败。某支付平台的小程序在部分内部接口上确实启用了双向校验这也是很多人照着网上通用 Frida 脚本改了之后仍然抓不到包的原因。另一个极端是服务端指纹校验。服务器会在 TLS 握手时校验 ClientHello 里的指纹特征比如 JA3。代理工具的指纹和真机客户端不一样即使证书骗过去了服务器也会中断连接。这类指纹校验通常不在小程序客户端里而是服务端安全策略的一部分绕过时要连代理工具的指纹一起伪装。不过这次我处理的这个目标没有上 JA3所以后续内容不展开但要知道有这个可能性。3. 从wxapkg到Frida Hook定位SSL校验逻辑的常规路线3.1 解包小程序拿到JavaScript与WXML小程序安装后代码文件会以 wxapkg 格式存放在手机存储里。不同宿主平台路径略有差异但解包思路一致把对应小程序目录下的 wxapkg 文件复制出来用开源工具解包成原始 JavaScript 文件。常见工具有 wxappUnpacker 这类解包后能看到 app.js、app.json以及每个页面和组件的 js/wxml/wxss 文件。我这边用的是模拟器环境先把目标小程序跑起来让它释放包体然后从/data/data/某宿主包名/app_wxapkg/目录下复制目标 wxapkg。复制前要确认模拟器已 root或者用可调试版本。解包前先看文件大小如果只有几百 KB说明主包可能只是入口业务逻辑在分包里面要一并复制。adb pull /data/data/com.example.host/app_wxapkg/__APP__/pages.wxapkg . node ./wxappUnpacker.js ./pages.wxapkg -o ./decoded_pages逻辑说明adb pull把设备上的包体拉到本地wxappUnpacker.js负责解包-o指定输出目录。执行后decoded_pages里就能看到分包对应的 JavaScript 文件。参数说明包名和路径要根据实际宿主替换如果拉取时报权限错误先检查 adb root 状态。解包工具对部分加密包体会报错这时需要先解密常见做法是在__app__.json里搜索encrypted标记但绝大多数普通小程序没有加密这里不做展开。3.2 搜索校验关键字正则与字符串定位拿到 JS 文件后先不要盲目读代码。直接搜索一些网络库和证书校验常见的特征字符串定位效率最高。目标网络请求代码一般会用到 wx.request 的底层封装但是 SSL 校验逻辑往往会出现在公共模块里搜索时优先看 app-service.js 或 vendor.js 这类大文件。我习惯先在解包目录下跑一条 grep把带 “certificate”“publicKey”“ssl”“pinning”“x509” 的 js 文件筛出来。不同宿主平台搜索方式一样但匹配结果多少取决于 JS 是否被混淆。如果代码被压缩混淆过字符串可能还是明文的因为证书指纹这类常量没法彻底隐藏如果做了字符串加密则要借助 Hook 或运行时日志来找。grep -rE certificatePinning|publicKey|ssl_pinning|x509|certificate ./decoded_pages -l逻辑说明这条命令会列出包含上述关键字的文件路径。-r递归-E扩展正则-l只显示文件名。拿到文件列表后优先打开体积最大的那个 vendor 文件因为第三方请求库通常被打包在那里。如果你搜索的结果是空白可以换一批关键字再试比如sha256/、pin、checkServerTrusted。对某支付平台小程序我最后是在vendor.js里找到了一个名为verifySsl的函数里面做了证书链校验。3.3 选型Hook系统API还是替换证书库定位到校验逻辑后选择绕过方案。常见三种做法第一种是 Hook 系统证书校验 API。Android 上就是网络库最终调用的 OpenSSL 或 Java 的TrustManager。用 Frida Hook 住这些函数直接让校验返回成功。优点是通用性强不需要理解具体业务代码缺点是如果目标用 NDK 自己编译了静态 OpenSSLHook 点可能落在不常用函数上要花时间找。第二种是运行时替换证书库。把抓包工具的根证书直接塞进系统 CA 目录或者替换掉代码里预埋的证书常量。这种做法适合代码里做了明文证书对比的场景但需要频繁修改包体有时还得过签名校验不建议用于快速抓包。第三种是动态调试思路直接用 Frida 的Java.perform去调用小程序内部方法绕过前端校验逻辑。这个不够通用但偶尔能救命。我最终选择的是 Hook 系统 OpenSSL 校验函数原因是它不依赖具体业务代码而且对某支付平台小程序这样同时跑在 multiple 进程里的应用一个脚本能全覆盖。4. 实操用Frida绕过SSL验证让抓包工具看到明文4.1 环境准备模拟器/root设备与Frida安装先准备一台可 root 的 Android 设备或模拟器。我这里用的是某常见模拟器root 后方便做全局代理和证书安装。准备好 frida-server 与服务端 frida 版本一致否则连不上会报unable to start之类的错误。安装步骤不复杂先确认设备架构adb shell getprop ro.product.cpu.abi输出 arm64-v8a 就下载对应的 frida-server。用 adb push 推到/data/local/tmp/给执行权限后后台运行。宿主机上安装 frida-tools然后跑frida-ps -U看看能不能列出进程。adb push frida-server /data/local/tmp/frida-server adb shell chmod 755 /data/local/tmp/frida-server adb shell /data/local/tmp/frida-server 逻辑说明第一行把 frida-server 推送到设备临时目录第二行加执行权限第三行启动服务。表示后台运行。如果是模拟器可能还要加-D参数以调试模式启动否则偶尔会被系统杀掉。参数说明frida-server 版本必须与宿主机frida一致直接pip install frida-tools安装的配套版本即可。启动后不要关终端否则 server 会退出。4.2 编写Frida脚本Hook SSL_CTX_set_verify与X509_VERIFY_PARAM绕过校验的核心思路很简单让 SSL 握手中的所有证书校验回调都直接通过。常规脚本只需 Hook 两个地方SSL_CTX_set_verify和X509_VERIFY_PARAM_set1_host。前者管是否校验后者管主机名校验。下面是一个能用的 Frida 脚本骨架适用于 Android 上使用 OpenSSL 的 native 库。脚本里 Hook 了SSL_CTX_set_verify把校验模式强制改成SSL_VERIFY_NONE同时 HookX509_VERIFY_PARAM_set1_host让它忽略域名检查。如果目标使用 BoringSSL函数名会略有不同但逻辑是同一套。Interceptor.attach(Module.findExportByName(null, SSL_CTX_set_verify), { onEnter: function (args) { args[2] ptr(0); // SSL_VERIFY_NONE console.log([] SSL_CTX_set_verify - SSL_VERIFY_NONE); } }); Interceptor.attach(Module.findExportByName(null, X509_VERIFY_PARAM_set1_host), { onEnter: function (args) { args[2] ptr(0); // hostname check disabled console.log([] hostname verification disabled); } });逻辑说明Interceptor.attach在函数入口处修改参数。第一个 Hook 里args[2]是第三个参数也就是 SSL 校验模式改成 0 表示完全不校验证书链。第二个 Hook 把主机名校验参数清空因为代理工具的证书域名和目标不一致时会在这里失败。参数说明Module.findExportByName(null, ...)会在所有已加载模块里查找导出函数如果目标进程把符号表剥了可能找不到导出名需要改成从特定 so 文件里查找。如果 Hook 后提示找不到导出可以先frida -U 进程名 -l script.js跑一下看日志。4.3 配置代理与证书让HTTP层请求浮现脚本运行只是第一步抓包工具还得能解密流量。代理端设置好监听端口把模拟器的 WiFi 代理指到宿主机的 IP 和端口然后在模拟器上安装抓包工具的根证书。安装证书要注意 Android 7 之后用户证书默认不被 App 信任必须把证书复制到系统 CA 目录重启模拟器才生效。adb push charles_ca.der /data/local/tmp/charles_ca.der adb shell openssl x509 -inform DER -in /data/local/tmp/charles_ca.der -out /system/etc/security/cacerts/charles_ca.pem adb shell chmod 644 /system/etc/security/cacerts/charles_ca.pem adb reboot逻辑说明第一行把抓包工具的 DER 格式证书推到设备第二行用 openssl 把它转成 PEM 格式并写入系统 CA 目录第三行改权限第四行重启。因为系统证书目录只读如果 adb root 后仍然不能写需要先执行adb remount或使用可写系统镜像。参数说明证书文件名不能带特殊字符文件名中的 CN 字段最好和证书内容一致否则某些版本系统解析会失败。重启后别忘了重新设置代理因为重启会清掉 WiFi 设置。完成这些后打开小程序抓包工具里就能看到 HTTPS 请求变成明文。注意如果之前已经用脚本 Hook 了 SSL 校验这一步理论上会直接成功。4.4 处理双向认证额外Hook客户端证书回调如果目标接口开了双向认证单纯让客户端不校验服务器还不够因为代理拿不到客户端证书。这时要用 Frida 再 Hook 两个函数SSL_CTX_set_client_cert_cb和SSL_CTX_use_certificate。前者是客户端证书回调后者是直接设置证书。常见的做法是让回调返回 0表示“没有客户端证书”但服务端会拒绝。另一个做法是劫持握手过程把目标 App 真正要用的客户端证书提取出来喂给代理。实际操作中我一般会先在日志里看报错信息。如果抓包工具显示 “client certificate required”说明服务端强制要客户端证书。此时需要从 App 的资源或 native 库里找到预置的 PKCS12 文件提取证书和私钥导入代理工具当客户端证书用。这个操作偏业务不同小程序差异很大这里不展开。但记住一个判断如果绕过脚本和证书都配置好了抓包工具里依旧只有 CONNECT 记录十有八九是双向校验没处理。5. 避坑指南绕过SSL验证后的五个典型翻车点5.1 现象代理已连接却一直无流量代理和证书都配置好打开小程序后抓包工具里只有初始的 CONNECT 请求之后没有任何数据。最常见原因是 Frida 脚本没有生效或进程没选对。某支付平台小程序不止一个进程网络请求跑在子进程里而脚本只 attach 了主进程。解决方法是先看 Frida 控制台输出确认SSL_CTX_set_verify - SSL_VERIFY_NONE有没有打出来。如果没有改用frida-ps -U找到网络子进程的进程名重新 attach。还有一种可能脚本虽然 Hook 了但目标用的不是 OpenSSL 而是 BoringSSL函数名对不上。这时需要在 native 模块里搜SSL_CTX_set_verify的替代导出比如SSL_CTX_set_custom_verify。5.2 现象SSL握手失败报错unexpected eof客户端和代理之间建立了 TCP 连接但 TLS 握手在 ClientHello 之后立刻中断。原因一般是代理没有正确解密或者客户端发送了代理无法理解的扩展字段。某支付平台上这个报错特别常出现在 HTTP/2 或 TLS 1.3 场景。解决方法是先在抓包工具里把 SSL 代理的 TLS 版本降到 1.2并关闭 HTTP/2 的优先知识让连接回退到 HTTP/1.1。如果还报错检查证书路径是否被系统目录的 Pinning 逻辑干扰。偶尔是模拟器时间不准确导致证书校验时把有效期判断成过期同步系统时间后再试。5.3 现象小程序启动即闪退或弹窗警告绕过后小程序直接崩溃通常不是因为 SSL Hook而是因为目标检测到了代理环境或 Frida 注入。某支付平台的反调试逻辑会做端口扫描检测到 8080 代理端口就主动退出。模拟器里更容易触发因为宿主 App 对模拟器特征敏感。解决方法是换用透明代理方案避免使用固定的 HTTP 代理端口或者用 iptables 把流量转发到透明代理这样客户端感觉不到代理设置。另一种思路是把 Frida 的检测绕过也加上比如 Hookopen和connect系统调用把端口扫描结果伪装成空。但这类对抗是动态的建议优先选择代理方式升级而不是花时间对抗反调试。5.4 现象只能抓到部分请求图片和消息仍加密部分请求是明文但图片、音视频或长连接的请求仍然是 TLS。原因是脚本只 Hook 了 SSL_CTX_set_verify但这个函数只作用于当前网络栈。如果小程序内部有多套网络库或者走了 QUIC就会漏掉一部分流量。解决办法是观察漏掉的流量特征如果走 QUIC会占用 UDP 443 端口代理工具默认不拦截 UDP需要再用 Frida Hook QUIC 的证书校验函数或者直接把 QUIC 禁用。如果走的是系统 WebView 发起的长连接额外 Hook 一下android.security.net.config.config相关调用也能覆盖。这一步比较费时但能完整抓到所有接口。5.5 现象抓包成功但重放请求被拒绝抓到了明文请求用 curl 原样重放却返回 401 或业务错误码。原因通常是服务端做了内容签名或时效校验而签名计算逻辑依赖本地密钥不是单纯拼一个头就能通过。解决方法是不要跳过签名模块。用 Frida 在 App 内存里找到签名函数把签名计算过程完整复刻或者直接在重放时动态调用签名函数。常见做法是写一个小的辅助脚本把参数传给 App 内的签名方法拿返回值后再发 HTTP 请求。这一步真正考验耐心也是这类安全测试里最需要反复验证的部分。6. 验证与进阶从一次抓包到可回归的自动化验证6.1 用curl验证抓包结果抓包工具里看到明文后我一般会先复制一条请求用 curl 在宿主机上直接发一遍。如果原样返回成功说明代理中间的改动没有影响请求完整性。如果返回失败就按照前一条重放被拒的原因排查签名或时序问题。这一小步能提前暴露“抓得到但用不了”的尴尬。6.2 把Frida Hook固化到回归脚本临时抓包场景跑一次就够了但如果要持续观察接口变更就把 Frida 脚本整理成一个独立文件和代理配置、证书安装步骤写在一个启动脚本里。每次拉起模拟器后执行一遍自动启动 frida-server、设置代理、导入证书最后 attach 到目标进程。这样不需要重复踩配置的坑。6.3 合规边界与我的习惯回到开头那个任务。我最后通过 Frida Hook 绕过了 SSL 校验抓齐了某支付平台小程序的全部接口还把签名逻辑复刻进了回归脚本。但这里要划一条清晰线整个过程只发生在授权测试环境目标是自己公司或客户明确委托的资产绝不能拿这套方法去碰未授权的系统。从那以后我每次开始这类尝试前都会强制走一遍三件事确认授权范围、确认测试设备属于自己、确认抓包数据不落地到公共存储。这个习惯帮我避开过不少麻烦也希望帮到你。如果哪一步卡住优先检查进程、证书和函数名实操里九成问题都出在这三处。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询