4. 协议报文结构解析

工业协议流量识别的第一步,不是看端口号,而是看报文本身。端口可以改、可以复用,但报文的帧结构、功能码语义、地址空间布局和数据编码方式,是协议最稳定的“指纹”。本节围绕 Modbus TCP、S7comm、EtherNet/IP 与 CIP 三类典型协议,拆解从字节到语义的解析路径,帮助你在流量分析中快速定位“这是什么协议、在做什么操作、操作了哪个对象”。

核心结论:协议识别 = 帧格式定边界 + 功能码定动作 + 地址空间定对象 + 数据编码定值。四者缺一不可,只靠端口或单一字段极易误判。

一、核心原理:四层解析模型

工业协议报文解析可以抽象为四层递进模型。第一层是帧格式,确定报文的起止边界与长度字段,解决“一个完整报文从哪里开始、到哪里结束”。第二层是功能码,确定请求/响应的操作类型,解决“这条报文想干什么”。第三层是地址空间,确定操作对象在设备中的位置,解决“操作的是哪个寄存器、哪个变量”。第四层是数据编码,确定字节序、数据类型与量纲,解决“读到的值到底是多少”。

这四层在流量识别中的价值不同:帧格式用于协议分类,功能码用于行为识别,地址空间用于资产建模,数据编码用于异常判定。例如,同样是写操作,写线圈和写保持寄存器的安全含义完全不同;同样是 4 字节,大端和小端解析出的数值可能相差 256 倍。

工业协议报文四层解析模型 从字节边界到业务语义的递进拆解 ① 帧格式 定边界 MBAP 头 / TPKT+COTP / EtherNet/IP 封装头 事务ID · 协议ID · 长度 · 单元ID · 服务码 · 会话句柄 作用:切分报文、协议分类、长度校验 ② 功能码 定动作 0x01/0x03/0x10 · 0x04/0x05 · CIP Service 0x4C/0x52 读线圈 · 读保持寄存器 · 写多寄存器 · 读输入 · 写单线圈 作用:行为识别、操作意图判定、异常动作告警 ③ 地址空间 定对象 线圈 0x · 离散输入 1x · 输入寄存器 3x · 保持寄存器 4x S7:DB 块 · I/Q/M 区 · 偏移量;CIP:类/实例/属性 作用:资产建模、工艺映射、越界访问检测 ④ 数据编码 定数值 大端/小端 · INT16/UINT32/FLOAT · 字节交换 · 量纲缩放 寄存器高低字顺序 · 位打包 · 时间戳格式 作用:数值还原、阈值判定、异常检测 帧格式 → 功能码 → 地址空间 → 数据编码:逐层剥离,最终还原业务语义 识别顺序建议:先定协议,再定动作,后定对象,最后校验数值

二、典型协议帧格式对照

不同工业协议的封装差异很大,但都可以用“头部 + 协议数据单元”来理解。Modbus TCP 的 MBAP 头固定 7 字节,其中长度字段表示后续字节数,是切分报文的关键。S7comm 运行在 TPKT 与 COTP 之上,需要先剥掉 4 字节 TPKT 和 COTP 头,才能看到 S7 的 ROSCTR 与功能码。EtherNet/IP 则使用封装头携带会话句柄和命令码,CIP 服务再嵌套其中。

协议 关键头部字段 典型功能码/服务 地址空间 数据编码要点
Modbus TCP 事务ID、协议ID、长度、单元ID 0x01 读线圈、0x03 读保持、0x10 写多寄存器 0x/1x/3x/4x 四区,偏移从 0 起 大端;寄存器 16 位;32 位需高低字组合
S7comm TPKT 长度、COTP、ROSCTR、PDU 参考 0x04 读变量、0x05 写变量、0x1A 请求下载 DB 块、I/Q/M 区、字节偏移 大端;位/字节/字/双字;DB 号需单独解析
EtherNet/IP + CIP 命令码、长度、会话句柄、状态 0x4C 读标签、0x52 写标签、0x6B 读数据 类/实例/属性;标签名寻址 小端为主;CIP 数据类型显式声明

三、方法流程:从抓包到语义还原

  1. 定位流:按五元组聚合会话,观察请求/响应配对关系,排除重传与心跳。
  2. 切分帧:依据长度字段或固定头长度,把 TCP 字节流还原为独立 PDU。
  3. 识别协议:检查 MBAP 协议ID是否为 0、TPKT 版本是否为 3、EtherNet/IP 命令码是否合法。
  4. 解析功能码:提取功能码/服务码,判断读、写、诊断、下载等操作类型。
  5. 还原地址:解析起始地址与数量,映射到设备变量表或资产模型。
  6. 解码数值:按字节序与数据类型还原工程值,必要时应用缩放系数。
实操提示:在 Wireshark 中可用 modbus.func_code == 16、s7comm.param.func == 0x05、enip.command == 0x6f 等显示过滤器快速定位目标操作,再结合 tcp.stream eq N 跟踪完整会话。

四、案例场景:一次异常写操作的识别

某产线监控中发现一条 Modbus TCP 写操作,目标单元 ID 为 1,功能码 0x10,起始地址 40001,写入数量 2,数据为 0x00 0x64 0x00 0x00。解析过程如下:MBAP 头确认协议ID为 0,长度字段为 13,说明后续 13 字节有效;功能码 0x10 表示写多个保持寄存器;地址 40001 对应保持寄存器区第一个寄存器;数据大端解析为 100 和 0。结合工艺映射,该寄存器为“设定转速”,正常范围 0~50,写入 100 明显越界,触发异常告警。

原始字节(十六进制):
00 01 00 00 00 0D 01 10 00 00 00 02 04 00 64 00 00

字段解析:
事务ID   = 0x0001
协议ID   = 0x0000   → Modbus
长度     = 0x000D   → 后续 13 字节
单元ID   = 0x01
功能码   = 0x10     → 写多个保持寄存器
起始地址 = 0x0000   → 40001
寄存器数 = 0x0002
字节数   = 0x04
数据     = 00 64 00 00 → 100, 0(大端)

五、常见误区与复盘

  • 误区一:只看端口判协议。502 端口可能承载非 Modbus 流量,S7 也可能跑在非 102 端口,必须校验头部特征。
  • 误区二:忽略长度字段。不按长度切分会导致粘包,后续功能码和地址全部错位。
  • 误区三:地址从 1 开始计数。Modbus 报文中的地址从 0 开始,而文档常写 40001,解析时需减 1。
  • 误区四:字节序想当然。Modbus 与 S7 为大端,EtherNet/IP 多为小端,32 位浮点还涉及高低字交换。
  • 误区五:功能码与地址空间脱节。0x01 只能操作线圈区,若地址落在保持寄存器区,说明报文构造异常或存在攻击行为。
复盘要点:协议解析的准确性直接决定异常检测的误报率。建议为每条协议建立“头部特征 + 功能码白名单 + 地址范围 + 数值区间”四维基线,任何一维越界都值得进一步核查。