You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在iOS上通过Frida从SSL Context获取SSL固定证书的方法咨询

从SSL上下文/连接中提取服务器证书的Frida解决方案

你当前Hook的SSL_CTX_set_custom_verify操作的是SSL上下文(配置模板),实际的服务器证书存储在单个SSL连接实例中,而非上下文对象。以下是直接提取证书并导出为PEM格式的修改方案:

完整Frida脚本

function dumpSSLCert() {
    // 定位BoringSSL核心函数
    const funcMap = {
        SSL_get_peer_certificate: Module.findExportByName("libboringssl.dylib", "SSL_get_peer_certificate"),
        PEM_write_bio_X509: Module.findExportByName("libboringssl.dylib", "PEM_write_bio_X509"),
        BIO_new_mem_buf: Module.findExportByName("libboringssl.dylib", "BIO_new_mem_buf"),
        BIO_get_mem_data: Module.findExportByName("libboringssl.dylib", "BIO_get_mem_data"),
        BIO_free: Module.findExportByName("libboringssl.dylib", "BIO_free"),
        X509_free: Module.findExportByName("libboringssl.dylib", "X509_free"),
        SSL_connect: Module.findExportByName("libboringssl.dylib", "SSL_connect")
    };

    // 检查必要函数是否存在
    for (const [name, addr] of Object.entries(funcMap)) {
        if (!addr) {
            console.log(`[!] 缺失函数: ${name}`);
            return;
        }
    }

    // 包装Native函数
    const ssl_get_peer_cert = new NativeFunction(funcMap.SSL_get_peer_certificate, 'pointer', ['pointer']);
    const pem_write_bio_x509 = new NativeFunction(funcMap.PEM_write_bio_X509, 'int', ['pointer', 'pointer']);
    const bio_new_mem_buf = new NativeFunction(funcMap.BIO_new_mem_buf, 'pointer', ['pointer', 'int']);
    const bio_get_mem_data = new NativeFunction(funcMap.BIO_get_mem_data, 'pointer', ['pointer', 'pointer']);
    const bio_free = new NativeFunction(funcMap.BIO_free, 'void', ['pointer']);
    const x509_free = new NativeFunction(funcMap.X509_free, 'void', ['pointer']);

    // Hook SSL连接成功事件,提取证书
    Interceptor.attach(funcMap.SSL_connect, {
        onLeave: function(retval) {
            // SSL_connect返回1表示连接成功
            if (retval.toInt32() !== 1) return;
            
            // ARM64架构下,第一个参数(SSL连接实例)存放在x0寄存器
            const sslInstance = this.context.x0;
            const certPtr = ssl_get_peer_cert(sslInstance);
            
            if (certPtr === null) return;

            // 创建内存缓冲区存储PEM格式证书
            const bio = bio_new_mem_buf(null, 0);
            if (bio === null) {
                x509_free(certPtr);
                return;
            }

            // 将证书转为PEM格式
            if (pem_write_bio_x509(bio, certPtr) === 1) {
                let lenPtr = ptr(0);
                const pemData = bio_get_mem_data(bio, lenPtr);
                const pemStr = pemData.readUtf8String(lenPtr.toInt32());
                
                console.log("[*] 服务器证书PEM:\n" + pemStr);
                // 可选:将证书发送到Frida客户端保存
                send({ type: "cert", data: pemStr });
            }

            // 释放内存,避免泄漏
            bio_free(bio);
            x509_free(certPtr);
        }
    });

    console.log("[*] SSL_connect已Hook,等待连接触发...");
}

// 保留你原有的SSL_CTX Hook(可选)
function overrideCustomVerify() {
    const SSL_CTX_set_custom_verify = Module.findExportByName("libboringssl.dylib", "SSL_CTX_set_custom_verify");
    if (!SSL_CTX_set_custom_verify) {
        console.log("[!] SSL_CTX_set_custom_verify未找到");
        return;
    }

    Interceptor.replace(SSL_CTX_set_custom_verify, new NativeCallback(function(ssl_ctx, mode, callback) {
        console.log("[*] SSL_CTX_set_custom_verify触发");
        // 调用原函数,避免破坏原有证书验证逻辑
        const originalFunc = new NativeFunction(SSL_CTX_set_custom_verify, 'void', ['pointer', 'int', 'pointer']);
        originalFunc(ssl_ctx, mode, callback);
    }, 'void', ['pointer', 'int', 'pointer']));

    console.log("[*] SSL_CTX_set_custom_verify已Hook");
}

// 启动Hook
setImmediate(function() {
    overrideCustomVerify();
    dumpSSLCert();
});

关键说明

  1. 为什么Hook SSL_connect:SSL上下文是全局配置模板,实际的服务器证书仅在单个SSL连接建立后才会加载,SSL_connect成功返回时,证书已完成协商,此时可通过SSL_get_peer_certificate获取证书指针。
  2. 内存管理:必须调用BIO_free和X509_free释放Native层内存,避免应用内存泄漏。
  3. PEM格式导出:通过BoringSSL的PEM_write_bio_X509将证书转为标准PEM格式,可直接保存为.crt文件用于代理工具。

使用方法

  1. 将脚本保存为dump_cert.js
  2. 运行命令:frida -U -f com.your.target.app -l dump_cert.js --no-pause
  3. 触发App内的HTTPS请求,控制台会打印证书PEM内容,也可通过Frida客户端接收数据保存到本地。

内容的提问来源于stack exchange,提问作者Darren

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.27 08:13:21