网络协议逆向:从抓包到自定义协议解析

说实话,网络协议逆向这块,是二进制安全里最「实在」的技能之一。你想想看,无论是分析恶意软件、做漏洞挖掘,还是搞工控安全,最终都要落到「这个数据包到底在说什么」这个问题上。我个人习惯把协议逆向分成三个层次:先会用工具看,再能理解标准协议,最后能搞定那些奇奇怪怪的自定义协议。

Wireshark 抓包:不只是点个开始按钮

很多人觉得 Wireshark 就是点一下「开始捕获」就完事了。嗯,我在项目里见过太多人抓了一堆包,结果全是噪音,根本找不到关键数据。这里我分享几个实战技巧。

抓包前的准备工作:
  • 先确定要抓哪个接口——无线网卡还是有线?本地回环还是远程?
  • 设置捕获过滤器,比如 host 192.168.1.100port 443
  • 如果流量太大,用 tcpdump -w capture.pcap 先存文件,回头再分析

我曾经遇到过一个案例:某工控设备每隔 5 秒发一个心跳包,但偶尔会夹带一个异常数据包。如果不设过滤器,抓 10 分钟就是几千个包,眼睛都看花了。后来我直接用 tcp.port == 502 过滤 Modbus 协议,问题一下子就清晰了。

Wireshark 的显示过滤器才是真正的利器。记住几个常用的:

# 只看特定 IP 之间的通信
ip.addr == 10.0.0.1 && ip.addr == 10.0.0.2

# 只看 TCP 三次握手
tcp.flags.syn == 1 && tcp.flags.ack == 0

# 只看重传包
tcp.analysis.retransmission

# 只看特定 payload 长度
frame.len > 1000
注意:捕获过滤器和显示过滤器是两回事。捕获过滤器在抓包时就丢弃了不符合条件的数据,无法恢复;显示过滤器只是隐藏,数据还在。我建议抓包时尽量宽泛,分析时再精细过滤。

TCP/UDP 协议分析:理解传输层的「潜规则」

TCP 和 UDP 的区别,教科书上讲得很清楚。但实际逆向中,你需要关注的是那些「教科书不会告诉你」的细节。

TCP 的「指纹」特征

每个操作系统、甚至每个版本的 TCP/IP 协议栈,在发送 SYN 包时都会有一些细微差异。这就是所谓的 TCP 指纹。我在分析恶意软件时,经常通过 TCP 指纹来判断 C2 服务器跑的是什么系统。

特征字段 Windows 10 Linux 5.x macOS
初始 TTL 128 64 64
MSS 1460 1460 1460
窗口缩放 8 7 3
SACK 许可

你看,光是一个窗口缩放因子,就能帮你缩小范围。我当年逆向一个 IoT 僵尸网络时,就是靠这个特征发现它的 C2 服务器其实跑在 Windows 上,而不是一开始以为的 Linux。

UDP 的「无状态」陷阱

UDP 没有连接状态,但这不代表它没有规律。很多自定义协议选择 UDP 是因为延迟低,但代价是应用层必须自己处理丢包和重传。我在分析一个游戏外挂时,发现它用 UDP 发送坐标数据,但每隔 5 个包会夹带一个序列号校验包——这就是应用层自己实现的「伪 TCP」机制。

核心思路:分析 UDP 协议时,重点关注三个东西——固定头部、可变长度字段、校验和/序列号。这三个要素基本能帮你还原出协议结构。

自定义协议识别与解析:从零到一

这才是真正的硬核部分。标准协议有 RFC 文档可以参考,但自定义协议?你只能靠逆向。我总结了一套方法论,叫做「三步走」。

第一步:找边界

拿到一堆二进制数据,第一件事不是看内容,而是找「边界」。怎么找?看长度字段。几乎所有自定义协议都会在头部某个位置标明 payload 长度。找到这个字段,你就知道一个完整的数据包从哪里开始、到哪里结束。

// 假设我们抓到这样一段数据
// 0x02 0x00 0x1A 0x00 0x01 0x03 ...
// 如果 0x02 0x00 是小端序的 2,那可能是协议版本
// 如果 0x1A 0x00 是小端序的 26,那很可能是 payload 长度

// 验证方法:从头部开始数 26 个字节,看看是不是一个完整的数据单元

我曾经逆向过一个工业机器人协议,它的长度字段藏在第 4-5 字节,但用的是大端序。我一开始按小端序解析,结果怎么都对不上,折腾了两天才发现这个坑。

第二步:找特征

每个协议都有「指纹」。可能是固定的魔数(Magic Number),可能是特定的命令码,也可能是某种编码方式。把多个数据包放在一起对比,找出那些不变的部分。

实用技巧:用 Wireshark 的「Follow TCP Stream」功能,把整个会话的 payload 导出来。然后用 xxdhexdump 查看,肉眼对比不同数据包的差异。我习惯用 Beyond Compare 做二进制对比,效率很高。

第三步:写解析器

当你摸清了协议结构,就可以写解析器了。不一定非要用 C 或 Python,我有时候直接用 Wireshark 的 Lua 插件来解析,这样可以直接在 Wireshark 里看到解析结果。

-- 一个简单的 Wireshark Lua 解析器示例
local my_proto = Proto("myproto", "My Custom Protocol")

local f_magic = ProtoField.uint16("myproto.magic", "Magic", base.HEX)
local f_cmd = ProtoField.uint8("myproto.cmd", "Command", base.DEC)
local f_len = ProtoField.uint16("myproto.len", "Length", base.DEC)
local f_payload = ProtoField.bytes("myproto.payload", "Payload")

my_proto.fields = { f_magic, f_cmd, f_len, f_payload }

function my_proto.dissector(buffer, pinfo, tree)
    if buffer:len() < 5 then return false end
    
    local magic = buffer(0, 2):uint()
    if magic ~= 0xABCD then return false end
    
    local subtree = tree:add(my_proto, buffer(), "My Protocol Data")
    subtree:add(f_magic, buffer(0, 2))
    subtree:add(f_cmd, buffer(2, 1))
    subtree:add(f_len, buffer(3, 2))
    
    local len = buffer(3, 2):uint()
    if buffer:len() >= 5 + len then
        subtree:add(f_payload, buffer(5, len))
    end
    
    return true
end

-- 注册到 TCP 端口 8888
local tcp_table = DissectorTable.get("tcp.port")
tcp_table:add(8888, my_proto)

这个脚本虽然简单,但已经能处理大部分自定义协议了。我在实际项目中,经常在这个基础上加一些高级功能,比如自动识别变长字段、处理加密数据等。

SVG:协议逆向的核心流程

自定义协议逆向三步走 第一步:找边界 识别长度字段 确定数据包边界 第二步:找特征 对比多个数据包 提取固定魔数/命令码 第三步:写解析器 Lua/Python/C 自动化解析 常用工具 Wireshark · tcpdump · xxd · Beyond Compare · 010 Editor · Python scapy ⚠ 常见陷阱 • 大小端序搞反(尤其是工业协议,很多用大端序) • 长度字段包含头部自身长度还是只包含 payload? • 协议可能有多个版本,同一个字段在不同版本中含义不同 • 加密或压缩的数据,需要先解密/解压才能看到真实结构 核心原则:先找不变,再找变化,最后自动化

实战中的几个坑

最后,分享几个我在实际项目中踩过的坑,希望能帮你少走弯路。

坑一:大小端序的陷阱
我曾经逆向一个金融交易协议,它的长度字段在第 2-3 字节,我按小端序解析,结果长度总是对不上。后来发现这个协议是 Motorola 68000 架构的遗留系统,用的是大端序。从那以后,我拿到任何协议数据,第一件事就是确认端序。
坑二:长度字段的「自指」问题
有些协议的长度字段包含头部自身的长度,有些只包含 payload 的长度。如果不搞清楚这一点,解析出来的数据会整体偏移。我的习惯是:先假设长度字段只包含 payload,如果解析结果不对,再尝试包含头部。
我的小技巧:在 Wireshark 里分析自定义协议时,我会同时打开两个窗口——一个显示原始 hex,一个显示解析后的字段。这样能快速发现解析错误。另外,多准备几个不同场景的抓包文件,对比着看,很多规律就自然浮现了。

协议逆向说到底就是「模式识别」——在看似随机的二进制流中找到规律。这个能力需要大量练习,但一旦掌握了,你会发现很多看似复杂的系统,底层逻辑其实很简单。嗯,今天就先聊到这里,下次有机会再深入讲讲加密协议的逆向思路。


公众号:蓝海资料掘金营,微信deep3321