【笔记】Modbus协议
官方文档
- 下载链接:https://www.modbus.cn/6756.html
- 点击跳转预览
- ai搞了下,后面再边做边加笔记
笔记
func功能码
| 十进制 | 十六进制 | 英文描述(官方) | 中文习惯叫法 | 读/写 | 常用过滤示例 |
|---|---|---|---|---|---|
| 1 | 0x01 | Read Coils | 读线圈 | 读 | modbus.func_code==1 |
| 2 | 0x02 | Read Discrete Inputs | 读离散输入 | 读 | modbus.func_code==2 |
| 3 | 0x03 | Read Holding Registers | 读保持寄存器 | 读 | modbus.func_code==3 |
| 4 | 0x04 | Read Input Registers | 读输入寄存器 | 读 | modbus.func_code==4 |
| 5 | 0x05 | Write Single Coil | 写单个线圈 | 写 | modbus.func_code==5 |
| 6 | 0x06 | Write Single Register | 写单个寄存器 | 写 | modbus.func_code==6 |
| 15 | 0x0F | Write Multiple Coils | 写多个线圈 | 写 | modbus.func_code==15 |
| 16 | 0x10 | Write Multiple Registers | 写多个寄存器 | 写 | modbus.func_code==16 |
| 20 | 0x14 | Read File Record | 读文件记录 | 读 | modbus.func_code==20 |
| 21 | 0x15 | Write File Record | 写文件记录 | 写 | modbus.func_code==21 |
| 22 | 0x16 | Mask Write Register | 屏蔽写寄存器 | 写 | modbus.func_code==22 |
| 23 | 0x17 | Read/Write Multiple regs | 读写多个寄存器 | 读+写 | modbus.func_code==23 |
| 43 | 0x2B | Encap. Interface Transport | 封装接口(MEI) | 诊断 | modbus.func_code==43 |
注:8、9、10、11、12、13、14 为诊断/固件类,CTF 出现频率低,未列出。
wireshark筛选exp
# 1. 只看写操作(改值、插旗、写恶意寄存器) |
- 快速脚本(tshark 批量导出写寄存器值):
- 输出格式:
帧号 源IP 起始地址 寄存器数量 值1,值2,...
tshark -r capture.pcapng -Y 'modbus.func_code==16' \ |
wireshark info字段名含义
| 层级 | 字段名(Wireshark 显示) | 长度 | 官方文档出处 | 含义/取值 |
|---|---|---|---|---|
| MBAP | Trans / Transaction Identifier | 2 B | 第三部分 §3.1.3 | 事务 ID,用于唯一匹配请求与响应,客户端任意递增 |
| MBAP | Protocol Identifier | 2 B | 第三部分 §3.1.3 | 协议标识符,固定 0x0000(Modbus 协议) |
| MBAP | Length | 2 B | 第三部分 §3.1.3 | 后续字节数(Unit + PDU 总长度) |
| MBAP | Unit / Unit Identifier | 1 B | 第三部分 §3.1.3 | 单元标识符,在 TCP 中等同于“从站地址”;<br>0=广播(仅串行),1-247=单个从站,0xFF=无效/直连 |
| PDU | Function Code / Func | 1 B | 第一部分 §4.1 + §6 | 功能码,决定操作类型(01/02/03/04/05/06/15/16…) |
| PDU | Reference Number / Address | 2 B | 各功能码章节 | 寄存器/线圈起始地址(0 基址) |
| PDU | Bit Count / Word Count / Quantity | 2 B | 各功能码章节 | 读/写数量(上限 2000 线圈,125 寄存器) |
| PDU | Byte Count | 1 B | 功能码 01-04、15、16 | 后续数据域字节数(仅变长响应/写请求) |
| PDU | Data (Coil/Register values) | N B | 各功能码章节 | 原始数据,按大端(Big-Endian)排列 |
| PDU | Exception Code | 1 B | 第一部分 §7 | 仅异常响应出现,取值 01-0B(见下表) |
| CRC* | CRC-16 (RTU only) | 2 B | 第二部分 §2.5.1.2 | 串行链路校验,TCP 模式无此字段 |
| LRC* | LRC (ASCII only) | 1 B | 第二部分 §2.5.2.2 | ASCII 模式校验,TCP 模式无此字段 |
异常码速查
| 异常码 | 名称 | 触发场景 |
|---|---|---|
| 01 | Illegal Function | 不支持的功能码 |
| 02 | Illegal Data Address | 地址越界 |
| 03 | Illegal Data Value | 数据值非法(如数量超限) |
| 04 | Server Device Failure | 从站内部故障 |
| 05 | Acknowledge | 长任务已收,请轮询 |
| 06 | Server Device Busy | 从站忙,稍后重试 |
| 08 | Memory Parity Error | 文件记录校验错 |
| 0A | Gateway Path Unavailable | 网关路由不可用 |
| 0B | Gateway Target No Response | 目标设备无响应 |
> 注:TCP 模式完全去掉 Address、CRC、Start/End,以上三项不会出现在 Wireshark 的 Modbus/TCP 解析树中。
coil address(Reference Number)
在 Modbus 协议里,“线圈地址”(人们口语中常说的 coil address)与 “参考号”(Reference Number)本来就是同一个值,只是叫法不同、单位不同:
-
官方文档(GB/T ×××× 对应 Modbus-IDA 规范)对功能码 5 的请求 PDU 定义如下:
Function Code : 1 byte → 0x05
Output Address : 2 bytes → 0x0000 … 0xFFFF
Output Value : 2 bytes → 0x0000 或 0xFF00这里的 Output Address 就是 Wireshark 里解析出来的 Reference Number。
-
该字段的语义是“从哪个线圈开始操作”,协议规定它用 0 基址,即:
字段值 0 → 实际线圈 1
字段值 12 → 实际线圈 13
字段值 13 → 实际线圈 14 … -
因此,当抓包看到
Reference Number: 13
就等于 线圈地址(coil address)= 14;Wireshark 为了让人一眼看懂,把字段值直接标成“线圈地址”,只是忘了加“(0-base)”提示,于是看起来像是“解析出了 coil_address = Reference Number”。
-
总结一句话:
“Reference Number”是协议层面的字段名,“coil address”是用户层面的习惯叫法;二者数值相同,仅基址基准不同,所以工具直接把它们画上了等号。
Modbus 功能码 05 (写单个线圈) Data 字段含义表
| Data 数值 (16进制) | 含义 | 说明 |
|---|---|---|
0000 |
OFF / 停止 / 断开 | 使线圈(Coil)断电或复位至 0 状态 |
FF00 |
ON / 启动 / 闭合 | 使线圈(Coil)通电或置位至 1 状态 |
注意:
- 根据标准协议,除了
0000和FF00之外的其他任何数值通常都是非法的,从机(Server)应该保持线圈状态不变(或者有些设备可能会返回异常)。- 虽然数值是 16 位的(2字节),但实际上只有高 8 位起作用(
00或FF),低 8 位始终为00。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 落殷回的博客!
评论



