Skip to content

SSL/TLS Hook 机制 ​

这是 r0capture 最核心的原理:为什么 hook SSL_read/SSL_write 就能拿到明文。

TLS 加密的"分界线" ​

理解 r0capture,先要理解 TLS 在数据链路里的位置。SSL_read 和 SSL_write 这两个函数,正好是明文与密文的分界线:

  • SSL_write(明文) 内部把明文加密成 TLS record,交给下层 TCP 发出去
  • SSL_read() 内部把 TLS record 解密,返回明文给调用方

在它们身上下钩子,拿到的天然是明文——这就是 r0capture 的全部秘密。

hook 的精确位置 ​

r0capture 不是 hook Java 方法,而是 hook native 层的 OpenSSL/BoringSSL 符号:

SSL_write / SSL_read 是 libssl.so 导出的 C 函数。r0capture 用 Frida 的 Module.findExportByName 找到它们的地址,挂上 Interceptor.attach:

javascript
// script.js 简化示意
const ssl_write = Module.findExportByName(null, 'SSL_write')
Interceptor.attach(ssl_write, {
  onEnter(args) {
    // args[0]=SSL*, args[1]=buf, args[2]=len
    this.buf = args[1]
    this.len = args[2].toInt32()
  },
  onLeave(retval) {
    // SSL_write 返回后,buf 里就是刚写入的明文
    send({ type: 'ssl_write', src, dst }, this.buf.readByteArray(this.len))
  }
})

为什么绕过证书校验 ​

证书校验/Pinning 发生在 SSL 握手阶段,而 SSL_read/write 是握手完成后才被调用的:

r0capture 的 hook 点在握手之后。所以:

  • 校验通过 → 正常通信 → r0capture 抓到明文 ✅
  • 校验没通过(Pinning 拒绝)→ App 根本不会调 SSL_write 发业务数据 → 但这跟 r0capture 无关,App 自己连不上

Pinning 是"能不能通信"的问题,r0capture 是"通信了就抓得到"的问题,两者正交。

多版本 SSL 库的适配 ​

不同安卓版本、不同 App,SSL 符号的位置和命名不同。r0capture 用通配符匹配 + 多候选:

这也是为什么 WebView/Flutter 抓不到——它们静态链接了自己的 BoringSSL,符号不导出到动态符号表,findExportByName 找不到。

下一篇:pcap 文件格式 →

基于 VitePress 构建 · 教学用途