pcap 导出
r0capture 把抓到的明文写成一个标准 pcap 文件,可以直接用 Wireshark / tcpdump 打开分析。这一篇讲清楚 pcap 里到底装了什么。
从明文到 pcap 的流程
pcap 文件结构
pcap 是一个极简的二进制格式:1 个全局头 + N 个记录。
linktype 228 是什么
228 = LINKTYPE_IPV4,意思是"这个 pcap 里的每条记录直接就是一个 IPv4 包,没有以太网帧头"。所以记录头后面紧跟的就是 IP 头,比标准网卡抓包少 14 字节。这是 r0capture 的选择——它只关心 IP/TCP 层之上的内容。
一条记录的逐字节解剖
以 selftest 抓到的一条 GET / HTTP/1.1 请求为例:
记录头(16字节): 时间戳秒 | 微秒 | 包含长度 | 原始长度
↓
IPv4头(20字节): 45 00 ... | 源IP | 目的IP
0x45 → 版本4 + 头长5×4=20字节
↓
TCP头(20字节): 源端口 | 目的端口 | seq | ack | flags
flags=0x18 → PSH+ACK (带数据)
↓
载荷(明文): GET / HTTP/1.1\r\n
User-Agent: Dalvik/2.1.0 ...
Host: example.com\r\n\r\n用 Python struct 解析就是:
python
import struct
# 记录头
ts_sec, ts_usec, inc_len, orig_len = struct.unpack('<IIII', rec[:16])
# IPv4 头
version_ihl = pkt[0] # 0x45
ihl = (version_ihl & 0xf) * 4 # 20
src_ip = '.'.join(map(str, pkt[12:16]))
# TCP 头
tcp_off = ihl
src_port = struct.unpack('>H', pkt[tcp_off:tcp_off+2])[0]
doff = ((pkt[tcp_off+12] >> 4) & 0xf) * 4
payload = pkt[tcp_off + doff:] # ← 这就是明文双层结构:明文层 + 密文层
r0capture 的 pcap 里其实混着两层:
- 明文层:来自
SSL_read/writehook,载荷是你要的明文,但地址常是0.0.0.0:0(见 Conscrypt 与 0.0.0.0)。 - 密文层:来自 Java
socketWrite0hook,载荷是 TLS 握手/密文,但地址是真实的。
两层互补:密文层给你网络拓扑,明文层给你内容。
验证:用 tcpdump 打开
bash
$ tcpdump -r selftest.pcap -n
reading from file selftest.pcap, link-type IPV4 (Raw IPv4), snapshot length 65535
15:41:33.050626 IP 172.17.0.5.55252 > 104.20.23.154.443: Flags [P.], length 520
15:41:33.431246 IP 0.0.0.0.0 > 0.0.0.0: Flags [P.], length 176
...link-type IPV4 (Raw IPv4) 说明格式完全标准。Wireshark 同样能直接打开。
下一步:收发包函数定位 →