西门子中国总代理2024已更新
西门子中国总代理2024已更新
西门子中国总代理2024已更新
西门子中国总代理2024已更新
浔之漫智控技术有限公司长期低价销售西门子PLC,200,300,400,1200,西门子PLC附件,西门子电机,西门子人机界面,西门子变频器,西门子数控伺服,西门子总线电缆现货供应,欢迎来电咨询系列产品,折扣低,货期准时,并且备有大量库存.长期有效
西门子S7通信1. 总体结构1.1. 西门子通信场景在讨论更多的技术细节之前,首先我想简单介绍一下西门子通信场景的基本情况。当我谈到“S7协议”时,我指的是以太网S7通信,主要用于将PLC连接到(I)PC站(PG/PC - PLC通信)。不要将此与西门子设备使用的不同现场总线协议混淆,如MPI、Profibus、IE和Profinet (Profinet是一种基于以太网的协议,用于将plc连接到IO模块,而不是设备的管理协议)
大多数时候,西门子通信遵循传统的主从或客户端-服务器模型,PC(主/客户端)向现场设备(从/服务器)发送S7请求。这些请求用于向设备查询、向设备发送数据或发出某些命令。有一些例外情况,当PLC可以作为通信主程序时,通过FB14/FB15设备可以向其他设备发起GET和PUT请求。
在S400系列中实现了一个所谓的循环数据I/O功能,这类似于传统的发布者-订阅者模型。PC可以订阅某些事件,而PLC则定期将请求的数据推送到网络。当主动伙伴请求连接并调用块发送,同时被动伙伴调用块接收方法时,还存在一个伙伴或点对点模型。
有关S7通信总体概述的更多信息,请参阅西门子Simatic Net和Snap7文档。
1.2. S7 PDUTCP/IP实现的S7协议依赖于面向块的ISO传输服务。S7协议封装在TPKT和ISO-COTP协议中,允许PDU(协议数据单元)通过TCP传输。ISO over TCP通信是在RFC1006中定义的,ISO- cotp是在RFC2126中定义的,该RFC2126基于ISO 8073协议(RFC905)。这个结构如下图所示。
S7协议是面向功能/命令的,这意味着一个传输包含一个S7请求和一个适当的应答(很少有例外)。并联传输的数量和PDU的Zui大长度在连接建立时协商。
S7 PDU主要由三个部分组成:
Header:包含长度信息、PDU引用和消息类型常量
Parameters:根据PDU的消息和功能类型,内容和结构有很大的不同
Data:它是一个可选的字段来携带数据,如果有任何,例如内存值,块代码,固件数据等。
1.2.1 Header报头长度为10-12字节,确认消息包含两个额外的错误码字节。除此之外,所有pdu的头格式是一致的。
字段:
Protocol ID:[1b]协议常量总是设置为0x32
Message Type[1b]消息的一般类型(有时称为ROSCTR类型)
0x01-Job Request:主机发送的请求(例如读/写内存,读/写块,启动/停止设备,建立通信)
0x02-Ack:简单的确认由从机发送,没有数据字段(我从未见过它由S300/S400设备发送)
0x03-Ack-Data:带有可选数据字段的确认,包含对作业请求的回复
0x07-Userdata:原始协议的扩展,参数字段包含请求/响应id,(用于编程/调试,SZL读取,安全函数,时间设置,循环读取…)
Reserved:[2b]总是设置为0x0000(但可能被忽略)
PDU reference:[2b]由主机生成,随着每次新的传输而增加,用于链接对其请求的响应,小字节序(注意:这是WinCC、Step7和其他西门子程序的行为,它可能是随机生成的,PLC只是将其复制到应答中)
Parameter Length:[2b]参数字段的长度,大字节序
Data Length:[2b]数据字段的长度,大字节序
(Error class):[1b]只出现在Ack-Data消息中,可能的错误常量列在constants.txt中
(Error code):[1b]只出现在Ack-Data消息中,可能的错误常量列在constants.txt中
2. 作业请求和Ack数据本部分进一步研究了Job Request和Ack Data消息的目的和内部结构。这些消息类型被放在一起讨论,因为它们非常相似,而且通常每个Job Request都会得到一个Ack Data应答。
前面介绍了S7 PDU的结构和通用协议头。但是,参数头是特定于消息类型的,对于Job和Ack Data消息,它以函数代码开始。其余字段的结构依赖于这个值。此函数代码确定消息的目的,并作为进一步讨论的基础。
2.1. 设置通信[0xF0]Pcap:S300-setup-communication
这个消息对(一个Job和Ack数据响应)在每个会话开始时发送,然后才能交换任何其他消息。它用于协商Ack队列的大小和Zui大PDU长度,双方声明各自支持的值。Ack队列的长度决定了可以在没有确认的情况下同时启动的并行作业的数量。PDU和队列长度字段都是大字节序。
参数头如下图所示:
2.1.1 S7认证与保护Pcap:S300-setup-communication
这里可能是讨论S7身份验证和保护机制的好地方(尽管它们与实际的通信设置没有关系)。在配置CPU时,可以设置三种保护模式。
没有保护:就像人们认为不需要身份验证一样。
写保护:对于某些写数据和配置更改操作,需要鉴权。
读写保护:与前一种保护类似,但某些读操作也需要认证。
需要注意的是,即使启用了读/写保护,也有一些操作是允许的,比如读取SZL list或读写Marker区域。其他操作,如读或写对象/函数/数据块应该返回权限错误。
有两个与CPU相关的保护级别集,分配的保护级别和实际的保护级别。指定的保护级别为配置时设置的保护级别,实际的保护级别为当前通信会话适用的保护级别。
在正常操作时,需要读写权限的客户端在通信建立后通过SZL读(SZL ID: 0x0132 SZL Index: 0x0004)查询真实的和分配的保护级别。如果需要认证,密码会以userdata消息的形式发送给设备,这会降低有效的保护级别。
在有人认为这至少提供了一点点安全性之前,让我澄清一下,并不是。密码是6个字节,几乎是明文发送的(xord与常量和移位)。它具有可重复性,并且可以被强制执行。该协议也不提供完整性或机密性保护,消息注入和修改是可能的。S7安全的一般经验法则是,如果你能ping通设备,你就能拥有它。
这里必须指出的是,S7-1200/1500系列设备使用了稍微不同的方法,保护级别处理有点不同,发送的密码明显更长(它实际上是密码的散列),但它仍然是恒定的和可重放的。
2.2. 读/写变量[0x04/0x05]Pcaps:
s300-read-variable-simple
s300-read-write-variable (用简单的寻址来读写多个变量)
s400-read-write-variable-db (多个变量使用数据库寻址进行读写)
当事情开始变得有点复杂的时候,我强烈建议在阅读本节时查看提供的pcap (wireshark2带有默认启用的S7 dissector)。数据读写操作通过指定变量的内存区域、它的地址(偏移量)和它的大小或类型来实现。在讨论协议细节之前,我想简要介绍一下S7寻址模型。
与前面提到的一样,通过指定变量的地址来访问变量,这个地址由三个主要属性组成。内存区域:
Merker:[M]任意标记变量或标记寄存器驻留在这里。
Data Block:[DB]DB区域是存储设备不同功能所需数据的Zui常见的地方,这些数据块是地址的一部分。
Input:[I]数字和模拟输入模块的值,映射到内存中。
Output:[Q]类似的内存映射输出。
Counter:[C]不同数值的计数器所使用的PLC程序。
Timer:[T]PLC程序所使用的不同定时器的值。
还有其他不太常见的内存区域(如本地数据[L]和外设访问[P]等)。
变量的类型决定了它的长度以及如何解释它。以下是一些例子:
BIT:[X]单个位。
WORD:两个字节宽的无符号整数。
DINT:四个字节宽的带符号整数。
REAL:四个字节宽的IEEE浮点数。
COUNTER:计数器类型采用PLC程序计数器。
变量的一个示例地址是DB123X2.1,它访问数据块#123的第三字节的第二个位。
在短暂的绕道之后,让我们回到协议中变量读/写的实现。S7协议支持在单个消息中使用不同的寻址模式查询多个变量读写。主要有三种模式:
any-type:这是默认的寻址模式,用于查询任意变量。所有三个参数(区域、地址、类型)都是为每个指定地址的变量指定的。
db-type:这是专为处理DB区域变量而设计的特殊模式,它比任何类型的寻址更紧凑。
symbolic-addressing:S7-1200/1500系列设备使用这种方式,允许用预定义的符号名对某些变量进行寻址。这里不详细讨论此模式。
对于每个寻址模式,Parameters头的结构是相同的:
Function Code:[1b]读的常量值为0x04,写的常量值为0x05。
Item Count:[1b]以下请求项目结构的数量。
Request Item:该结构用于处理实际变量,其长度和字段取决于所使用的寻址类型。这些项只出现在Job请求中,并且从相应的Ack Data中发出,无论寻址模式是什么,或者它是一个读或写请求。
根据消息的类型(读/写)和方向(Job/Ack Data),S7 PDU的Data部分有所不同:
读请求: Data部分为空。
读响应:Ack数据消息的数据部分由数据项结构组成,一个用于原始请求中的每个请求项。这些项包含读变量的实际值,格式取决于寻址模式。
写请求:包含与读响应类似的数据项,每个请求项在参数头中对应一个。类似地,它们包含要写入从设备的变量值。
写响应:Ack数据消息的数据部分仅仅包含一个字节的错误码
总而言之,Request Item总是包含变量的描述,并且可以在Job请求中发送多个变量,而Data Items则包含所描述变量的实际值。数据项结构必须从偶数字节开始,所以如果它们的长度是奇数,并且有一个紧随其后的数据项,那么它们将用一个零字节填充。
剩下要讨论的是请求/数据项结构的格式。如前所述,它们依赖于所使用的寻址模式,因此它们将在此基础上引入。
2.2.1 任意类型寻址的项目结构下图显示了请求和数据项结构:
请求项的字段:
Specification Type:[1b]这个字段决定了项目结构的主要类型,对于读/写消息,它总是有值0x12,这代表变量规格。
Length:[1b]本项目其余部分的长度。
Syntax ID:[1b]该字段确定寻址模式和项目结构的其余部分的格式。对于任意类型的寻址,它的常量值是0x10。
Variable Type:[1b]这用于确定变量的类型和长度(通常使用S7类型,如REAL, BIT, BYTE, WORD, DWORD, COUNTER,…)。
Count:[2b]可以用单个项目结构选择一个类似变量的整个数组。这些变量必须具有相同的类型,并且在内存中必须是连续的,并且count字段决定这个数组的大小。对于单个变量读或写,它被设置为1。
DB Number:[2b]数据库的地址,如果该区域没有设置为DB,它将被忽略(见下一个字段)。
Area:[1b]选择寻址变量的存储区域。查看constants.txt获取内存区域常量。
Address:[3b]包含所选内存区域中寻址变量的偏移量。从本质上讲,地址被转换为位偏移量,并按照网络(大端)字节顺序在3个字节上进行编码。在实践中,Zui重要的5位从未被使用过,因为地址空间小于5位。作为一个示例,DBX40.3将是0x000143,即40 * 8 + 3。
类似地,关联的Data Item的字段:
Error Code:[1b]操作的返回值,0xff表示成功。在写请求消息中,该字段总是设置为零。
Variable Type and Count:[1b 2b]与请求项相同。
Data:该字段包含指定变量的实际值,其大小为len(variable) * count。
2.2.2 使用db类型寻址的项结构我只在S400系列设备上看到过这种类型的寻址,不过一些S300系列plc也可能支持这种寻址。它只用于访问DB变量,并提供了一种替代方案,以更紧凑的格式在单个项中处理多个不同的变量。下图显示了Request(请求)和Data(数据)项结构:
请求项的字段:
Specification Type:[1b]与任何类型的寻址相同。
Length:[1b]本项目其余部分的长度。
Syntax ID:[1b]决定了寻址模式,对于db-type,固定值为0xb0。
Number of Subitems:[1b]下列分项的数目。
Subitem:
Size:[1b]指定从所选地址读或写的字节数。
DB Number:[2b]寻址变量所在的DB。
Address:[2b]变量到给定DB的字节偏移量。
数据项的字段:
Error Code:[1b]操作的返回值,0xff表示成功。
Variable Type:[1b]总是设置为0x09(字符串)。
Length:[2b]剩余子响应数据的长度。
Subresponse:
Error Code:[1b]与子项请求相关联的返回值。
Data:实际数据的读取或写入,解释这需要相应的子项。
2.3. 阻塞/下载[0x1a-1f]Pcaps:
s300-download-ob1
s300-snap7-upload
这就是事情开始变得混乱的地方。首先,在西门子的术语中,下载是主服务器向从服务器发送块数据,上传是另一个方向。在西门子设备上,程序代码和(大部分)程序数据存储在块中,这些块有自己的头和编码格式,这里不详细讨论。从协议的角度来看,它们是需要传输的二进制blob(对于感兴趣的阅读器来说,snap7源提供了关于块头及其编码的信息)。
西门子设备识别出七种不同类型的区块:
OB:组织块,存储主要程序。
(S)DB:(系统)数据块,存储PLC程序所需的数据。
(S)FC:(系统)函数,函数是无状态的(没有自己的内存),它们可以从其他程序调用。
(S)FB:(系统)函数块,有状态的函数,它们通常有一个相关联的(S)DB。
这些块的用途在Siemens文档中有很好的描述。
这些块在up/download请求中使用一个特殊的ASCII文件名进行寻址。此文件名的结构如下:
File Identifier:[1 char]据我所知,它的值总是’_'。
Block Type:[2 char]确定块类型,具体值见constants.txt。
Block Number:[5 char]给定块的十进制数。
Destination File System:[1 char]该字段的值可以是’A’,代表主动文件系统,也可以是’P’,代表被动文件系统。复制到活动文件系统的块被立即链接起来,这意味着只要PLC执行恢复,它们就会生效。另一方面,复制到被动文件系统的块需要首先被激活。
示例文件名是_0800001P,用于从被动文件系统复制OB 1。
让我简要地介绍一下区块编码和内容保护。有两种措施可以保护设备上的程序内容和数据,并允许程序库的分发。第一个被称为专有技术保护,如果设置阻止STEP7或TIA显示块的实际内容。不幸的是,绕过它是很简单的,因为它只在块的头部设置了两位,可以很容易地清除。另一种保护措施是块“加密”,它实际上只是线性变换的一种混淆(按字节进行xoring和用常量旋转),要绕过它也应该是微不足道的。因此,不要依赖这些“安全”机制来保护您的专有技术。否则,数据块包含原始的、初始化的内存映像。程序块包含MC7(机器代码7)二进制指令。
上传和下载块涉及3-3种不同类型的消息对。下面列出了它们和相关的功能代码:
Request Download请求下载- 0x1a
Download Block下载块- 0x1b
Download Ended下载结束- 0x1c
Start Upload开始上传- 0x1d
Upload Block上传块- 0x1e
End Upload结束上传- 0x1f
这些消息的结构非常简单,但是消息序列(特别是下载)需要一些解释。
在Ack Data - Start Upload消息中,从服务器告诉区块的长度,然后主服务器继续发送Job - Upload block消息,直到接收到所有字节。Zui后,它使用Job - End upload消息关闭上传序列。block的实际数据是由slave在Ack data - Upload block消息中发送的。
Job-Start Upload 参数头:
Function Code:[1b]0x1d表示开始上传。
Function Status:[1b]仅在上传消息中使用,如果需要发送更多数据,则设置为0x01。
Unknown:[2b]始终为0x0000。
Session ID:[4b]一个与每个上传序列相关联的唯一id,它在Ack Data - Start upload消息中设置。
Filename Length:[1b]之后文件名的长度。
Filename:标识之前介绍的块的文件名。
Ack Data-Start Upload 参数头:
Function Code:[1b]0x1d表示开始上传。
Function Status:[1b]同上。
Unknown:[2b]始终为0x0100。
Session ID:[4b]此处设置了Session ID,连续消息使用相同的值。
Length String Length:[1b]块长度字符串的长度。
Length String:编码为ASCII C字符串的块的十进制长度。
Job - Upload 参数头:
包含上面讨论的Function Code(0x1e)、Function Status、Unknown(0x0000)和会Session ID。
Ack Data-Upload 参数和数据部分:
Function Code:[1b]0x1d表示开始上传。
Function Status:[1b]如果需要发送更多数据,请设置为0x01。
Data part:
Length:[2b]块数据的长度。
Unknown:[2b]始终为0x0000。
Block Data:上传数据块的一部分。
Job - End Upload 参数头:
Ack Data - End Upload 参数头:
只包含Function Code(0x1f)
2.3.2 数据块上传和下载之间的关键区别是,在下载过程中,通信的方向改变了,从服务器变成了主服务器。在初始的请求下载交换后,从服务器发送Job消息,主服务器用Ack数据回复,这是“从服务器只回复”规则的唯一例外。发送完所有字节后,主(原始)发送Download Ended Job以关闭下载会话。参见下面的序列图。
实际消息的结构与上传消息非常相似,所以我只介绍它们的区别。为了准确的语法描述,请在wireshark中打开示例pcap。
Job - Request下载消息包含两个额外的字段,下载块的块长度和块的有效载荷长度(没有块头的长度)。这两个字段都是用ASCII字符串编码的十进制数字。响应Ack Data - Request Download只包含函数代码。
另一个显著的区别是,尽管Session ID字段存在,但它没有被使用(仍然是0x00000000),而是在每个Job - Download块中传输Filename。其余消息的结构与前面讨论的相同。
Pcaps:
s300-control-commands (复制Ram到Rom,压缩内存,启动PLC)
s300-copy-ram-to-rom
s300-activate-blocks
s300-delete-blocks (激活/删除块,启动PLC)
(尝试使用s7comm.param.func == 0x28 wireshark filter查找PLC控制消息)
PLC控制消息用于在从设备上执行修改其执行/内存状态的不同例程。这些命令用于启动或停止PLC控制程序的执行,激活或删除设备上的程序块,或将其配置保存到持久内存中。这些消息的结构相当简单,我们将在不讨论具体细节的情况下对它们进行解释(参见所附的捕获)。
Job - PLC控制消息由两个主要部分组成,被调用方法的ASCII名称和它的参数(也被编码为一个ASCII字符串)。方法名的结构与块传输部分中引入的文件名类似。参数取决于方法类型,可以将它们视为方法的参数。Ack数据消息简单地包含PLC控制功能代码。
一些函数名及其相关参数示例:
_INSE:激活设备上下载的块,参数是块的名称(例如OB1)。
_DELE:从设备的文件系统中移除一个块,参数仍然是块的名称。
P_PROGRAM:设置设备的运行状态(启动、停止、mem复位)。它是发送无参数启动设备,然而停止plc程序使用不同的功能代码(见下一节)。
_GARB:压缩PLC内存。
_MODU:复制ram到rom,参数包含文件系统标识符(A/E/P)。
联系方式
- 地址:上海松江 上海市松江区石湖荡镇塔汇路755弄29号1幢一层A区213室
- 邮编:201600
- 联系电话:未提供
- 经理:吴悦
- 手机:19514718569
- QQ:2810544350
- Email:2810544350@qq.com