抓 HTTP 包,你看到的是请求和响应;抓裸 TCP,你看到的是一串没有边界的字节。UDP 更碎,一个数据报就是一份完整的东西,顺序和到达都不保证。把 HTTP 那套习惯直接搬过来,第一反应基本是:这堆东西哪一段是开头、哪一段是结尾?
这篇按五步走:先抓到、认方向、看字节、拆帧、再谈改写。用的还是 TraceEagle 的网卡直抓和自定义解码。
代理抓包只认 HTTP 那一套,DNS、QUIC、ICMP、游戏协议、IoT 的长连接,它收不到。想看这些,得走网卡。
在 TraceEagle 里新建会话,选「本机网卡抓包」,再挑一块网卡。工具会自动列出本机所有网卡,也会默认选中当前活动的那块,不知道选哪个就先用默认的。
开抓前可以设一个过滤条件,也可以直接点内置预设:TLS、HTTP、QUIC、DNS、TCP、UDP、ICMP、ARP、SSH。这个过滤只在开始前设定,开始之后改不了;如果想在已经抓到的数据里再筛,用逐包视图的「显示过滤」,语法是 Wireshark 那一套,
tcp.port==443、
tls.handshake、
dns 都能用。
抓到之后有两个视图互相配合:逐包视图看单个包的字节和协议分层树,连接视图把散包重组成一条条连接,右键「追踪此连接」能把整条流完整看下来。这一步没什么技巧,选对网卡、过滤开对就行吧。
TCP 是有连接的。三次握手之后,两边可以同时发数据,所以同一条连接上有两个方向:客户端到服务器,服务器到客户端。看流的时候,发送和接收是分开的两列,别把它们当成一条时间线。
UDP 没有连接,每个数据报都是独立的。方向只能从源地址和目的地址判断,丢包和乱序也都是常态。一个请求发出去,等回来的可能是空的,也可能是几条,跟 TCP 的体验完全不一样啊。
TCP 的重传、去重和排序由协议栈处理,应用层看到的是有序的字节流;UDP 没有这些保证,丢包、重复、乱序都得应用自己扛。这也是为什么很多实时音视频、游戏会选 UDP——宁可丢一帧,也不想等重传。
方向这件事不只是看着舒服。自定义解码器会对发送流和接收流分别跑一遍,并自动给每条消息标方向;改写也一样,要选是改上行还是下行。方向认错,后面的拆帧和改写都会歪。
原始字节的查看方式就两种:hex 和文本。工具里可以随时切,未解密或者非 HTTP 的数据,就靠这两个视图。
看字节的目标不是把整条流读懂,是先找规律。几个常见的线索:
1f 8b 是 gzip,
50 4b 是 zip,
89 50 4e 47 是 PNG。\0 或者某个特殊字符结尾。二进制协议里,这几样经常同时出现:一个固定头、一个长度、一段负载,负载再压一道。别一上来就按文本去解啊,那样只会得到乱码。
还有一种常见结构:头是固定的,负载长度写在头里的某个字段,负载本身可能是 protobuf 或者压缩过的 JSON。先按头切,再把负载交给工具自动识别,基本就够用了。
TCP 给的是字节流,不是消息流。「一条消息」是应用层自己定义的,工具必须知道在哪切、切多少,才能把它变成一条一条可看的东西。
它会先自动试一轮常见边界,比如定长的前缀。试不出来,可以手动上模板:长度前缀、Magic 签名边界、分隔符(支持 hex)、定长,还有 gzip 和按类型分派。改几个数字就能跑。
再复杂一点,就写解码器。整个解码器是一个函数,工具把某条连接的剩余字节交给它,它切出一条消息、返回消费了多少字节,然后再问下一次:
1function decode(buf, out) {2 if (buf.byteLength < 4) return 0 // 长度头还没到齐3 const total = 4 + u32be(buf, 0) // 4 字节头 + 负载4 if (buf.byteLength < total) return 0 // 整条还没到齐5 out.push(sub(buf, 4, total - 4)) // 剥掉头,负载交给自动识别6 return total // 消费掉这一条7}
这就是一个最典型的长度前缀协议:前四字节大端读出长度,凑齐了再切。 TraceEagle 会分别对发送流和接收流跑这个函数,方向自动标好;切出来的消息还会再过一遍自动识别,是 protobuf、JSON 还是 plist,能解就继续解。脚本写坏了也不会把会话搞崩,最差就是看到原始字节,改完保存再重解一次,不用重新抓呢。
规则改写里有一类专门给非 HTTP 流量用:裸 TCP / UDP 字节流按方向做替换,和 WebSocket 帧改写是一套逻辑,都是
old=>new。
方向还是那三个:客户端到服务器、服务器到客户端、双向。改客户端请求里的固定字段,选上行;模拟服务器返回一个错误码,选下行。选错方向,帧一点变化都没有。
说清楚一个边界:改写挂在代理会话的规则上,走代理的 TCP/UDP(比如 SOCKS5 的数据报)能按方向替换;网卡直抓更适合看和解码,别指望在原始抓到的包上直接改。两者解决的不是同一个问题。
改之前还得先看一眼协议结构。如果这条消息有长度前缀、校验和、压缩或者加密,直接替换字节可能让后面的帧全乱套:长度对不上,解析器就找不到下一条;校验和不对,服务端可能直接丢掉。稳妥的做法是改完在工具里重新解一遍,确认边界还成立、校验还能过,再往下测。举个具体的:某个自研协议用 4 字节长度头,你想把下行消息里的错误码从 1001 改成 2001。先确认替换不改变长度,再按服务器到客户端的方向替换,改完重新解一遍,看下一条消息还能不能切出来。
Wireshark 的协议解析器库是这几家里最全的,几百种协议开箱就能拆,显示过滤、Follow Stream、专家信息都很成熟。纯看包、做协议层分析,它还是更专业的那一站。它不做流量改写,这也不是它的目标。
tcpdump 胜在轻和无头:ssh 到服务器上跑一条命令,把流量落成 pcap,再拉回本地慢慢看。它只负责抓,解析和改写都得另找工具。
它把网卡抓取、逐包和连接视图、自定义解码、规则改写放在一个界面里,非 HTTP 协议能一路走完抓、看、改,链路是通的。真要比协议解析的广度,它不如 Wireshark;要比无头抓取,它不如 tcpdump 轻。三者搭着用,比互相替代更实际吧。
非 HTTP 抓包的难点不在抓,在认边界。抓到字节只是开头,知道哪一段是一条消息、这条消息往哪个方向走、改完会不会破坏结构,才算真的看懂。
顺序可以记一下:选对网卡,用过滤收窄范围;先认方向,再看 hex 和文本;找到边界就上模板或写解码器;要改的话,先确认长度和校验,再按方向替换,改完重解一遍验证。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/70051050/viewspace-3186479/ ,如需转载,请注明出处,否则将追究法律责任。