1133 字
6 分钟
MacOS绕过SSL Pining问题
NOTE
本文主要内容
主要是用 Frida 来绕过 MacOS 上的 SSL Pining 问题,方便调试一些应用。主要是做一个备忘录,方便以后查阅,并不涉及非常深入的用法。
最近在尝试逆向部分AI平台时,有些平台只提供了客户端版本,没有网页版本,就导致调试起来比较麻烦。然后发现有些应用启用了 SSL Pining,导致 ProxyMan 抓包时会报错 SSL Pinning Failed。
Electron 应用绕过 SSL Pining
- 首先需要先判断应用是否基于
Electron,可以通过查看应用包内是否有Electron Framework来判断。可以通过ls /Applications/xxx.app/Contents/Frameworks来判断,出现Electron Framework.framework就说明是Electron应用。 - 先使用最简单的办法,直接二进制方式启动程序,然后添加
/Applications/xxx.app/Contents/MacOS/xxx --ignore-certificate-errors参数,忽略证书错误。- 此方法针对的主要是 Electron 主进程绕过 SSL Pining 问题,渲染进程或者其他子进程此方法无效。
- 如果你发现是 Electron 的其他进程存在 SSL Pining 问题,可以使用
inspect邪修办法尝试解决(不一定有效)。- 修改启动参数为:
/Applications/xxx.app/Contents/MacOS/xxx --inspect --ignore-certificate-errors - Chrome 访问 chrome://inspect,此时应该会出现一个设备,如下图,点击
inspect即可:
CleanShot 2026-01-20 at 17.40.26@2x - 出现DevTools后,打开
Console,然后输入以下代码:
const tls = require('tls')const https = require('https')// 保存原始函数const originalConnect = tls.connectconst originalRequest = https.requestconst originalGet = https.get// Hook tls.connecttls.connect = function(...args) {let options = args[0]if (typeof options === 'object') {options.rejectUnauthorized = falseoptions.checkServerIdentity = () => undefined}console.log('🔓 TLS connect intercepted:', options?.host || options?.servername)return originalConnect.apply(this, args)}// Hook https.requesthttps.request = function(url, options, callback) {if (typeof url === 'string') {if (typeof options === 'object') {options.rejectUnauthorized = false} else {options = { rejectUnauthorized: false }}} else if (typeof url === 'object') {url.rejectUnauthorized = false}console.log('🔓 HTTPS request intercepted')return originalRequest.apply(this, arguments)}// Hook https.gethttps.get = function(url, options, callback) {if (typeof url === 'string') {if (typeof options === 'object') {options.rejectUnauthorized = false} else {options = { rejectUnauthorized: false }}} else if (typeof url === 'object') {url.rejectUnauthorized = false}console.log('🔓 HTTPS get intercepted')return originalGet.apply(this, arguments)}console.log('✅ All TLS/HTTPS hooks installed - SSL verification disabled')- 运行完成后,此时应该就可以绕过 SSL Pining 了,ProxyMan 应该会显示明文了。如果还是不行,那么只能使用 Frida 来进行动态注入了。
- 修改启动参数为:
使用 Frida 绕过 SSL Pining
-
安装 Frida:
Terminal window pip install frida-tools -
编写 Frida 脚本
ssl_kill.js,内容如下:Process.enumerateModules().filter(m => m.name.toLowerCase().includes("ssl")).forEach(m => console.log("ssl module:", m.name, m.base));function findSymbol(name) {// 先全局搜(如果你的 Frida 支持的话)if (Module.findExportByName && typeof Module.findExportByName === "function") {const p = Module.findExportByName(null, name);if (p) return p;}// 再在可能的 libssl 名字里搜(macOS 上名字经常不是 libssl.dylib)const candidates = ["libssl.dylib", "libssl.1.1.dylib", "libssl.3.dylib"];for (const m of candidates) {const mod = Process.findModuleByName(m);if (!mod) continue;const p = mod.findExportByName(name);if (p) return p;}return null;}var SSL_get_verify_result = findSymbol("SSL_get_verify_result");var SSL_set_verify = findSymbol("SSL_set_verify");var SSL_CTX_set_verify = findSymbol("SSL_CTX_set_verify");console.log(">>> 开始注入 SSL Bypass...");// 1. Hook SSL_get_verify_result// 这个函数通常在握手完成后被调用,返回值 0 表示验证成功 (X509_V_OK)if (SSL_get_verify_result) {Interceptor.attach(SSL_get_verify_result, {onLeave: function(retval) {// 无论原来验证结果如何,强行篡改为 0 (成功)retval.replace(ptr(0));}});console.log("[+] Hooked SSL_get_verify_result (强制返回验证成功)");} else {console.log("[-] 未找到 SSL_get_verify_result (可能被剥离或改名)");}// 2. Hook SSL_set_verify// 这个函数用来设置验证模式。我们将模式强制设为 0 (SSL_VERIFY_NONE)if (SSL_set_verify) {Interceptor.attach(SSL_set_verify, {onEnter: function(args) {// args[1] 是 mode 参数,强制设为 0args[1] = ptr(0);}});console.log("[+] Hooked SSL_set_verify (强制禁用验证模式)");} else {console.log("[-] 未找到 SSL_set_verify");}// 3. Hook SSL_CTX_set_verify// 上下文级别的设置,同样强制设为 0if (SSL_CTX_set_verify) {Interceptor.attach(SSL_CTX_set_verify, {onEnter: function(args) {// args[1] 是 mode 参数args[1] = ptr(0);}});console.log("[+] Hooked SSL_CTX_set_verify (强制禁用上下文验证)");} else {console.log("[-] 未找到 SSL_CTX_set_verify");}console.log(">>> 注入完成,请检查 Proxyman 是否出现明文数据。"); -
使用 Frida 注入脚本:
Terminal window sudo frida -n "应用进程名" -l ssl_kill.js -
在没关闭
SIP的情况下,大概率会注入失败,报错Failed to attach: unable to access process with pid 5131 from the current user account,这种情况可以重新签名二进制文件来绕过限制- 先找到应用的二进制文件路径,比如
/Applications/xxx.app/Contents/Resources/bin/xxx - 然后执行以下命令重新签名:
Terminal window # 进入应用目录cd /Applications/xxx.app/Contents/Resources/xxx/xxx# 删除原有签名sudo xattr -cr xxx# 创建一个plist文件,内容如下echo '<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"><plist version="1.0"><dict><key>com.apple.security.get-task-allow</key><true/></dict></plist>' > debug.plist# 重新签名codesign -f -s - --entitlements debug.plist /Applications/xxx.app/Contents/Resources/bin/xxx/xxxcodesign -d --entitlements - /Applications/xxx.app/Contents/Resources/bin/xxx/xxx - 最后执行
sudo frida -l ssl_kill.js -n "应用进程名"重新注入脚本。
- 先找到应用的二进制文件路径,比如
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
MacOS绕过SSL Pining问题
https://blog.useforall.com/posts/macos-bypass-ssl-pining/ 最后更新于 2026-01-20,距今已过 56 天
部分内容可能已过时
Lim's Blog