Skip to content

SSL_read hook ​

📥 抓 HTTPS 响应明文(服务端 → 本端)的核心 hook。

📎 源码在线查看:script.js#L277-L303(SSL_read hook)

SSL_read 原型 ​

c
int SSL_read(SSL *ssl, void *buf, int num);
// 从 SSL 连接读取已解密的明文数据到 buf,返回读取字节数

hook 实现 ​

javascript
Interceptor.attach(addresses["SSL_read"], {
  onEnter: function (args) {
    // args[0]=ssl, args[1]=buf, args[2]=num
    var message = getPortsAndAddresses(SSL_get_fd(args[0]), true);
    message["ssl_session_id"] = getSslSessionId(args[0]);
    message["function"] = "SSL_read";
    message["stack"] = SSLstackread;  // Conscrypt SSLInputStream.read 时填入
    this.message = message;
    this.buf = args[1];
  },
  onLeave: function (retval) {
    retval |= 0;
    if (retval <= 0) {
      return;
    }
    send(this.message, this.buf.readByteArray(retval));
  }
});

onEnter:记录上下文 ​

  • SSL_get_fd(args[0]):从 ssl 对象拿底层 socket fd
  • getPortsAndAddresses(fd, true):isRead=true 表示收,src 取对端
  • getSslSessionId(args[0]):会话 ID
  • SSLstackread:由 Conscrypt SSLInputStream.read hook 时填入的 Java 调用栈
  • this.buf = args[1]:保存 buf 指针,onLeave 时从它读出明文

onLeave:读取并回传 ​

javascript
onLeave: function (retval) {
  retval |= 0;          // Cast to 32-bit integer
  if (retval <= 0) {    // 0 或负数 = 无数据/出错
    return;
  }
  send(this.message, this.buf.readByteArray(retval));
}

为什么在 onLeave 才 send ​

SSL_read 的明文是函数执行后才写入 buf 的,且实际长度由返回值 retval 决定(可能小于请求的 num)。所以必须等 onLeave:

  1. retval |= 0:转 32 位整数(Frida 的 retval 可能是 NativePointer)
  2. retval <= 0:返回 0 或负数表示无数据 / 出错,跳过
  3. this.buf.readByteArray(retval):从 buf 读 retval 字节明文
  4. send(message, data):连同 message 回传 Python

与 SSL_write 的对比 ​

维度SSL_readSSL_write
方向服务端 → 本端(响应)本端 → 服务端(请求)
明文可见时机onLeave(执行后写 buf)onEnter(args[1] 现成)
send 位置onLeaveonEnter
isRead 参数truefalse
stack 全局SSLstackreadSSLstackwrite

相关文档 ​

基于 VitePress 构建 · 教学用途