西门子作为一个老牌工控企业,在中国市场拥有很高的市场占有率。如果要说起西门子的通信协议,相信大家多多少少能说出一些,比如MPI、PPI、USS、Profibus、Profinet、S7等,但是西门子在协议的开放性方面要相对要封闭一些,所以我们是没法知道这些协议的底层通信原理的。
本文主要是结合Wireshark抓包工具,跟大家去分享一下,如何抓取西门子S7通信协议底层通信报文的,希望通过报文分析,让大家都能够对西门子S7协议有所了解的同时,也学会基本的抓包操作与报文分析。
一、环境搭建
1、首先我们要准备要准备一个西门子的PLC,并保证PLC与PC之间的网络连接正常。如果手头没有PLC,可以通过PLCSIM-Advanced搭建一个仿真环境。为了抓取到通信的报文,需要实现PC与PLC之间的通信,这里采用KepServer与PLC通信。
2、安装Wireshark抓包软件:Wireshark软件安装比较简单,大家可以自行安装。
3、认识S7协议的网络模型:
|-----------|-------------------------------|
| OSI层 | 通信协议 |
| 第7层:应用层 | S7 协议 S7 Communication |
| 第6层:表示层 | S7 协议(COTP) |
| 第5层:会话层 | S7 协议(TPKT) |
| 第4层:传输层 | Transmission Control Protocol |
| 第3层:网络层 | IP |
| 第2层:数据链路层 | Ethernet |
| 第1层:物理层 | Ethernet |
4、将KepServer与PLC之间的通信连接配置好:
5、将Wireshark软件打开,并处于监控报文状态。
二、报文分析
1、当KepServer启动连接,并开始监控变量时,打开Wireshark软件,观察报文。
2、我们发现西门子的S7通信并不是简简单单的TCP通信,在TCP执行三次握手之后,还需要发送两次连接验证,在两次连接验证之后,才进行真正的数据交互。
3、三次握手过程,如下图所示:

4、S7连接第一次验证,如下图所示:

5、S7连接第二次验证,如下图所示:

6、四次挥手过程,如下图所示:

7、S7第一次验证发送报文分析:

TPKT (第五层:会话层)
该层总共占4个字节:
版本号:0x03;
预留:0x00
长度:0x0016
COTP (第六层:表示层)
该层总共占用18个字节:
长度:0x11
PDU类型(CR Connect Request 连接请求):0x0E
目标引用:0x0000
源引用:0x0001
扩展格式/流控制:0x00
参数代码 TPDU-Size:0xC0
参数长度:0x01
TPDU大小:0x0A
参数代码 SRC-TASP:0xC1
参数长度:0x02
Source TSAP:0x0201
参数代码 DST-TASP:0xC2
参数长度:0x02
Destination TSAP:0x0201
8、S7第一次验证返回报文

TPKT (第五层:会话层)
该层总共占4个字节:
版本号:0x03
预留:0x00
长度:0x0016
COTP (第六层:表示层)
该层总共占18个字节:
长度:0x11
PDU类型(CC Connect Confirm 连接确认):0x0D
目标引用:0x0001
源引用:0x0006
扩展格式/流控制:0x00
参数代码 TPDU-Size:0xC0
参数长度:0x01
TPDU大小:0x0A
参数代码 SRC-TASP:0xC1
参数长度:0x02
源TSAP Source TSAP:0x0201
参数代码 DST-TASP:0xC2
参数长度:0x02
目标TASP Destination TSAP:0x0201
9、S7第二次验证发送报文

TPKT (第五层:会话层)
该层总共占4个字节:
版本号:0x03
预留:0x00
长度:0x0019
COTP (第六层:表示层)
该层总共占3个字节:
长度:0x02
PDU类型(DT Data):0xF0
目标引用:0x80
S7 Communication (第七层:应用层)
该层总用占18个字节,并且分两部分:
Header :
协议ID(Protocol ID):0x32
ROSCTR:0x01
预留:0x0000
协议数据单元引用:0x037C
参数长度:0x0008
数据长度:0x0000
Parameter :
功能码:0xF0
预留:0x00
最大AmQ(Calling):0x0001
最大AmQ(Called):0x0001
PDU长度:0x03C0
10、S7第二次验证返回报文

TPKT (第五层:会话层)
该层总共占4个字节:
版本号:0x03
预留:0x00
长度:0x0019
COTP (第六层:表示层)
该层总共占3个字节:
长度:0x02
PDU类型(DT Data):0xF0
目标引用:0x80
S7 Communication (第七层:应用层)
该层总用占20个字节,并且分两部分:
Header :
协议ID(Protocol ID):0x32
Ack_Data:0x03
预留:0x0000
协议数据单元引用:0x037C
参数长度:0x0008
数据长度:0x0000
错误等级:0x00
错误代码:0x00
Parameter :
功能码:0xF0
预留:0x00
最大AmQ(Calling):0x0001
最大AmQ(Called):0x0001
PDU长度:0x00F0
11、读取发送报文:读取DB1.DBX0.0 开始的4个字节

TPKT (第五层:会话层)
该层总共占4个字节:
版本号:0x03
预留:0x00
长度:0x001F
COTP (第六层:表示层)
该层总共占3个字节:
长度:0x02
PDU类型(DT Data):0xF0
目标引用:0x80
S7 Communication (第七层:应用层)
该层总用占24个字节,并且分两部分:
Header :
协议ID(Protocol ID):0x32
Ack_Data:0x01
预留:0x0000
协议数据单元引用:0x037D
参数长度:0x000E
数据长度:0x0000
Parameter :
功能码 Read Var:0x04
通信项数:0x01
通信项1:
通信项Header
变量指定:0x12
地址长度:0x0A
Syntax ID:0x10
传输数据类型 byte:0x02
通信项Param
读取长度:0x04
DB号:0x01
存储区类型 DB存储区:0x84
开始字节:0x000000
12、读取数据返回报文

TPKT (第五层:会话层)
该层总共占4个字节:
版本号:0x03
预留:0x00
长度:0x001D
COTP (第六层:表示层)
该层总共占3个字节:
长度:0x02
PDU类型(DT Data):0xF0
目标引用:0x80
S7 Communication (第七层:应用层)
该层总用占22个字节,并且分两部分:
Header :
协议ID(Protocol ID):0x32
Ack_Data:0x03
预留:0x0000
协议数据单元引用:0x037D
参数长度:0x0002
数据长度:0x0008
错误等级:0x00
错误代码:0x00
Parameter :
功能码 Read Var:0x04
通信项数:0x01
通信项1:
返回结果Success:0xFF
传输数据类型 Byte/Word/DWord:0x04
长度:0x0020
数据:0x00000000
整体总结
通过上述S7协议抓包的分析,我们对S7协议应该有了一个初步的认识。
-
S7协议不是一个开放的协议,因此没有完整的协议文档,本文只是通过抓包的方式来分析和了解报文。
-
S7协议整体来说,比一般的协议要稍微复杂一些,如果有精力可以通过抓包分析报文之后,然后手搓一个通信库。
-
从我个人的角度来说,我是不建议初学者花很多时间去研究S7协议,因为目前市面上已经有很多免费开源的S7通信库,比如S7NetPlus、Sharp7等。