从SSL_read/write入手:一个脚本搞定iOS/Android双向证书抓包难题
当移动应用采用双向证书验证或自定义SSL Pinning技术时,传统的中间人代理工具往往束手无策。本文将揭示如何通过Hook底层SSL/TLS通信的核心函数,实现跨平台的流量解密方案。
1. 双向证书抓包的技术原理
现代移动应用的安全防护通常包含以下层级:
- 网络层加密:标准TLS/SSL协议
- 证书绑定:SSL Pinning防止中间人攻击
- 双向验证:客户端需提交有效证书
常规抓包工具失效的根本原因在于无法绕过这些安全机制。而SSL_read和SSL_write作为加解密流程的最后关口,具有以下关键特性:
| 函数 | 作用阶段 | 数据状态 | 可获取内容 |
|---|---|---|---|
SSL_write | 发送前 | 明文 | 原始请求数据 |
SSL_read | 接收后 | 解密后明文 | 服务器原始响应 |
2. 跨平台Hook方案设计
2.1 iOS平台实现要点
iOS系统使用libboringssl.dylib作为加密库,典型Hook流程如下:
// 定位目标函数 const ssl_write = Module.findExportByName("libboringssl.dylib", "SSL_write"); const ssl_read = Module.findExportByName("libboringssl.dylib", "SSL_read"); // Hook写入操作 Interceptor.attach(ssl_write, { onEnter: function(args) { console.log("Request data:", hexdump(args[1], {length: args[2].toInt32()}) ); } }); // Hook读取操作 Interceptor.attach(ssl_read, { onLeave: function(retval) { if(retval > 0) { console.log("Response data:", Memory.readByteArray(this.args1, retval) ); } } });注意:iOS 15+版本可能需要处理PAC保护机制,建议使用Frida 15+版本
2.2 Android平台差异处理
Android系统采用libssl.so库,需注意以下差异点:
库文件路径可能因Android版本而异:
/system/lib/libssl.so/system/lib64/libssl.so- 第三方应用可能自带OpenSSL
典型Hook代码调整:
const ssl_lib = Process.findModuleByName("libssl.so"); const ssl_write = ssl_lib.getExportByName("SSL_write");3. 实战:r0capture脚本深度解析
r0capture作为通杀脚本的核心优势在于:
- 智能库检测:自动识别iOS/Android环境
- 完整会话记录:关联请求响应关系
- 多协议支持:处理TCP/UDP基础套接字
关键实现逻辑:
function hookSSL() { const resolver = new ApiResolver("module"); const targets = [ ["SSL_read", "读取解密"], ["SSL_write", "写入加密"], ["SSL_get_fd", "获取文件描述符"] ]; targets.forEach(([func, desc]) => { const address = resolver.getExportByName(func); Interceptor.attach(address, { onEnter: function(args) { this.trace = Thread.backtrace(this.context); }, onLeave: function(retval) { log(`${desc}操作完成`, this.trace); } }); }); }4. 高级调试技巧与问题排查
4.1 常见问题解决方案
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 找不到SSL函数 | 库版本不匹配 | 使用Process.enumerateModules()确认库名 |
| 数据截断 | 缓冲区大小限制 | 动态调整hexdump的length参数 |
| 进程崩溃 | 线程安全问题 | 添加try-catch保护逻辑 |
4.2 性能优化建议
- 过滤无关流量:
Interceptor.attach(ssl_read, { onEnter: function(args) { const fd = SSL_get_fd(args[0]); if(!isTargetSocket(fd)) return; // 处理逻辑... } });- 启用异步日志:
const logQueue = []; setInterval(() => { if(logQueue.length) { send(logQueue.shift()); } }, 100);5. 数据解析与业务应用
获取原始数据后的处理流程:
协议识别:
- HTTP头部特征检测
- gzip/br自动解压
- Protobuf/Thrift反序列化
会话重组示例代码:
def reassemble_packets(packets): sessions = defaultdict(list) for pkt in packets: key = (pkt['src_ip'], pkt['dst_ip'], pkt['src_port'], pkt['dst_port']) sessions[key].append(pkt) return sessions- 自动化分析工具链整合:
- 与Wireshark联动分析
- 导入Burp Suite进行漏洞测试
- 自定义签名检测敏感信息泄露