The Siemens S7 Communication

The Siemens S7 Communication - Part 1 General Structure

I have been working with Siemens PLCs for quite some time, mostly developing applications that either communicate with them or observe/simulate their communication. I thought it would be time to share my gathered knowledge of the S7 protocol as some might find it useful, interesting. The purpose of this writing is to aid those who wish to gain a deeper understanding of the Siemens S7 communication protocol and help the development of software interfering with these devices. This documentation of the protocol is not comprehensive, there are many parts left to be uncovered. While writing this article I only had access to S-300 and S-400 series devices (S315-2A and S417 to be specific) and I had never worked with S-200/S-1200/S-1500 series PLCs before, thus functions specific to those are not covered here.

As far as I know, there is no publicly available documentation for the S7 protocol, however there are a few notable projects that help to deal with it. Davide Nardella has created a fantastic open source communication library the Snap7, which implements basic communication scenarios. The library comes with the extensive documentation of the basic structure of the S7 protocol. Another great project is the S7 Wireshark dissector by Thomas W. which covers most of the protocol and its source code contains a lengthy list of protocol constants. These proved to be invaluable for me during the years I have spent working with Siemens equipment. Since, there is no official documentation, official terminology does not exists when it comes to the S7 protocol. In the rest of this document I try to comply with the terms used in the above mentioned projects.

Edit: Since I wrote this article I learned about a new and actively developed open-source project, plc4x. The project provides implementation for multiple industrial protocols including the S7 protocol.

我一直在与西门子PLC合作很长一段时间,主要是开发与它们通信或观察/模拟其通信的应用程序。我认为是时候分享我收集的S7协议知识,因为有些人可能觉得它很有用,很有趣。本文的目的是帮助那些希望深入了解西门子S7通信协议并帮助开发干扰这些设备的软件的人。该协议的文档并不全面,还有很多部分需要揭开。在写这篇文章的时候,我只能访问S-300和S-400系列设备(具体是S315-2A和S417),之前我从未使用过S-200 / S-1200 / S-1500系列PLC,因此这里没有涉及那些特定的功能。

据我所知,没有公开的S7协议文档,但有一些值得注意的项目有助于解决它。 Davide Nardella创建了一个梦幻般的开源通信库Snap7,它实现了基本的通信场景。该库附带了S7协议基本结构的详尽文档。另一个伟大的项目是Thomas W.的S7 Wireshark解剖器,它涵盖了大部分协议,其源代码包含很长的协议常量列表。在我使用西门子设备的这些年里,这些证明对我来说非常宝贵。由于没有官方文档,因此在S7协议方面不存在官方术语。在本文档的其余部分,我尝试遵守上述项目中使用的术语。

编辑:自从我写这篇文章以来,我了解了一个新的,积极开发的开源项目plc4x。该项目提供了多种工业协议的实现,包括S7协议。

1. The Siemens Communication Scenario

Before going into more technical details first I’d like to briefly introduce the basic Siemens communication theater. When I talk about the “S7 protocol” I refer to the Ethernet S7 communication that is mainly used to connect the PLCs to the (I)PC stations (PG/PC - PLC communication). This is not to be confused with the different fieldbus protocols that the Siemens equipment use, such as MPI, Profibus, IE and Profinet (which is an Ethernet based protocol used to connect PLCs to IO modules, not the management protocol of the devices).

Most of the time the Siemens communication follows the traditional master-slave or client-server model, where the PC (master/client) sends S7 requests to the field device (slave/server). These requests are used to query from or send data to the device or issue certain commands. There are a few exceptions when a PLC can be the communication master, with FB14/FB15 the device can initiate GET and PUT requests to other devices.

In the S400 series a so called Cyclic Data I/O function is implemented, this resembles to the traditional publisher-subscriber model. The PC can subscribe to certain events, than the PLC periodically pushes the requested data to the network. There is also a Partner or peer-to-peer model, when an Active Partner requests a connection and calls Block Send while at the same time the Passive Partner calls the Block Receive method.

For more information on the general overview of the S7 communication see the Siemens Simatic Net and Snap7 documentation.

在首先介绍更多技术细节之前,我想简要介绍一下基本的西门子通信影院。当我谈到“S7协议”时,我指的是以太网S7通信,主要用于将PLC连接到(I)PC站(PG / PC - PLC通信)。这不能与西门子设备使用的不同现场总线协议相混淆,例如MPI,Profibus,IE和Profinet(这是一种基于以太网的协议,用于将PLC连接到IO模块,而不是设备的管理协议)。

大多数情况下,西门子通信遵循传统的主从模式或客户端 - 服务器模型,其中PC(主/客户端)将S7请求发送到现场设备(从/服务器)。这些请求用于从设备查询或向设备发送数据或发出某些命令。当PLC可以作为通信主站时有一些例外,通过FB14 / FB15,设备可以向其他设备发起GET和PUT请求。

在S400系列中,实现了所谓的循环数据I / O功能,这类似于传统的发布者 - 订户模型。 PC可以订阅某些事件,而不是PLC定期将所请求的数据推送到网络。还有一个合作伙伴或点对点模型,当活动合作伙伴请求连接并调用阻止发送,同时被动合作伙伴调用阻止接收方法。

有关S7通信概述的更多信息,请参阅Siemens Simatic Net和Snap7文档。

2. The S7 PDU

The S7 protocol TCP/IP implementation relies on the block oriented ISO transport service. The S7 protocol is wrapped in the TPKT and ISO-COTP protocols, which allows the PDU(Protocol Data Unit) to be carried over TCP. The ISO over TCP communication is defined in RFC1006, the ISO-COTP is defined in RFC2126 which is based on the ISO 8073 protocol (RFC905).This structure is presented in the figure below.

S7协议TCP / IP实现依赖于面向块的ISO传输服务。 S7协议包含在TPKT和ISO-COTP协议中,允许PDU(协议数据单元)通过TCP承载。 ISO over TCP通信在RFC1006中定义,ISO-COTP在RFC2126中定义,RFC2126基于ISO 8073协议(RFC905)。该结构如下图所示。

The Siemens S7 Communication_第1张图片

The S7 protocol is function/command oriented which means a transmission consist of an S7 request and an appropriate reply (with very few exceptions). The number of the parallel transmission and the maximum length of a PDU is negotiated during the connection setup.

The S7 PDU consists of three main parts:

  • Header: contains length information, PDU reference and message type constant
  • Parameters: the content and structure greatly varies based on the message and function type of the PDU
  • Data: it is an optional field to carry the data if there is any, e.g. memory values, block code, firmware data …etc.

S7协议是面向功能/命令的,这意味着传输由S7请求和适当的应答组成(极少数例外)。 在连接建立期间协商并行传输的数量和PDU的最大长度。

S7 PDU由三个主要部分组成:

标头:包含长度信息,PDU参考和消息类型常量
参数:内容和结构根据PDU的消息和功能类型而有很大差异
数据:如果存在数据,则它是一个可选的字段来携带数据。 内存值,块代码,固件数据等。

2.1 Header

The header is 10-12 bytes long, the Acknowledgement messages contain two extra error code bytes. Other than that the header format is consistent across all the PDUs.

标头长度为10-12个字节,确认消息包含两个额外的错误代码字节。 除此之外,标头格式在所有PDU中是一致的。

The Siemens S7 Communication_第2张图片

Fields:

  • Protocol ID:[1b] protocol constant always set to 0x32
  • Message Type:[1b] the general type of the message (sometimes referred as ROSCTR type)
    • 0x01-Job Request: request sent by the master (e.g. read/write memory, read/write blocks, start/stop device, setup communication)
    • 0x02-Ack: simple acknowledgement sent by the slave with no data field (I have never seen it sent by the S300/S400 devices)
    • 0x03-Ack-Data: acknowledgement with optional data field, contains the reply to a job request
    • 0x07-Userdata: an extension of the original protocol, the parameter field contains the request/response id, (used for programming/debugging, SZL reads, security functions, time setup, cyclic read..)
  • Reserved:[2b] always set to 0x0000 (but probably ignored)
  • PDU reference:[2b] generated by the master, incremented with each new transmission, used to link responses to their requests, Little-Endian (note: this is the behaviour of WinCC, Step7, and other Siemens programs, it could probably be randomly generated, the PLC just copies it to the reply)
  • Parameter Length:[2b] the length of the parameter field, Big-Endian
  • Data Length:[2b] the length of the data field, Big-Endian
  • (Error class):[1b] only present in the Ack-Data messages, the possible error constants are listed in the constants.txt
  • (Error code):[1b] only present in the Ack-Data messages, the possible error constants are listed in the constants.txt

The rest of the message greatly depends on the Message Type and function code I will be covering each of those in the upcoming articles. Part 2 will focus on Job Requests and Ack-Data messages. 

All the different protocol constants are collected in the constants.txt.

I plan to keep these writings updated as much as possible, so if you have anything to add or correct feel free to contact me or leave a comment.

Update 2018-04-08:

  • Added reference to plc4x
  • Added link to the second part

Update 2017-03-14:

  • I have added a git repo with various thematic network captures of S7 communication click here
  • I am no longer working with Siemens equipment however due to the interest in the topic I have started writing part 2 of this article. Since I have no access to real devices it is going to be based on the different traffic captures I have laying around and my memories. Expect more gaps to fill
  • I have limited experience dealing with userdata messages (other than SZL reads and cyclic updates they are mostly used for development, programming and debugging purposes) so I am not sure if I can cover them in a meaningful way based on the few pcaps I have

领域:

协议ID:[1b]协议常量始终设置为0x32
消息类型:[1b]消息的一般类型(有时称为ROSCTR类型)
0x01-作业请求:主站发送的请求(例如读/写存储器,读/写块,启动/停止设备,设置通信)
0x02-Ack:从站发送的简单确认,没有数据字段(我从未见过它由S300 / S400设备发送)
0x03-Ack-Data:带有可选数据字段的确认,包含对作业请求的回复
0x07-Userdata:原始协议的扩展,参数字段包含请求/响应id,(用于编程/调试,SZL读取,安全功能,时间设置,循环读取..)
保留:[2b]始终设置为0x0000(但可能忽略)
PDU参考:[2b]由主站生成,每次新传输递增,用于链接对其请求的响应,Little-Endian(注意:这是WinCC,Step7和其他西门子程序的行为,它可能是随机的生成后,PLC只是将其复制到回复中)
参数长度:[2b]参数字段的长度,Big-Endian
数据长度:[2b]数据字段的长度,Big-Endian
(错误类):[1b]仅存在于Ack-Data消息中,可能的错误常量列在constants.txt中
(错误代码):[1b]仅存在于Ack-Data消息中,可能的错误常量列在constants.txt中
消息的其余部分在很大程度上取决于消息类型和功能代码,我将在接下来的文章中介绍其中的每一个。第2部分将重点介绍作业请求和Ack-Data消息。

所有不同的协议常量都在constants.txt中收集。

我计划尽可能地更新这些着作,所以如果您有任何要添加或更正的内容,请随时与我联系或发表评论。

更新2018-04-08:

添加了对plc4x的引用
添加了第二部分的链接
更新2017-03-14:

我添加了一个带有S7通信的各种主题网络捕获的git repo,请单击此处
我不再使用西门子设备,但由于对该主题的兴趣,我已经开始编写本文的第2部分。由于我无法访问真实设备,因此我将根据我所处理的不同流量捕获和我的记忆。期待填补更多空白
我处理userdata消息的经验有限(除了SZL读取和循环更新,它们主要用于开发,编程和调试目的)所以我不确定我是否可以基于我拥有的几个pcaps以有意义的方式覆盖它们

 

 

The Siemens S7 Communication - Part 2 Job Requests and Ack Data

This article series introduces the Siemens S7 protocol in depth, the first part detailed the general communication scenario and packet structure. This part further examines the purpose and internal structure of the Job Request and Ack Data messages. These message types are discussed together because they are very similar and usually each Job Request results in an Ack Data reply.

The structure of the S7 PDU and the general protocol header is explained in the previous part. However, the parameter header is specific to the message type and for the Job and Ack Data messages it begins with a function code. The structure of the rest of the fields depend on this value. This function code determines the purpose of the message and serves as the basis of further discussion.

本系列文章深入介绍了西门子S7协议,第一部分详细介绍了一般通信场景和数据包结构。 本部分进一步研究了作业请求和Ack数据消息的目的和内部结构。 这些消息类型一起讨论,因为它们非常相似,通常每个作业请求都会产生Ack数据回复。

S7 PDU的结构和通用协议头在前一部分中进行了说明。 但是,参数头特定于消息类型,而Job和Ack Data消息则以功能代码开头。 其余字段的结构取决于此值。 此功能代码确定消息的目的,并作为进一步讨论的基础。
 

1. Setup Communication [0xF0]

Pcap: S300-setup-communication

This message pair (a Job and Ack Data response) is sent at the beginning of each session before any other messages could be exchanged. It is used to negotiate the size of the Ack queues and the max PDU length, both parties declare their supported values. The length of the Ack queues determine the number of parallel jobs that can be initiated simultaneously without acknowledgement. Both the PDU and queue length fields are big endian.

The parameter header is shown in the following diagram:

1.设置通信[0xF0]
PCAP:S300-设置通信

在可以交换任何其他消息之前,在每个会话开始时发送该消息对(作业和确认数据响应)。 它用于协商Ack队列的大小和最大PDU长度,双方都声明其支持的值。 Ack队列的长度决定了可以在没有确认的情况下同时启动的并行作业的数量。 PDU和队列长度字段都是大端。

参数标题如下图所示:

The Siemens S7 Communication_第3张图片

1.1 S7 Authentication and Protection

Pcap: s300-authentication

This is probably a good place to talk about the S7 authentication and protection mechanisms (even though they have nothing to do with the actual communication setup). There are three protection modes that can be set during configuration for the CPU.

  • No protection: Just as one would expect no authentication is required.
  • Write protection: For certain data write and configuration change operations authentication is required.
  • Read/Write protection: Just like the previous one but certain read operations require authentication as well.

It must be noted that even if Read/Write protection is enabled there are certain operations that are allowed such as reading SZL Lists or reading and writing into Marker area. Other operations such as reading or writing Object/Function/Data Blocks should return a permission error.

There are two protection level sets associated with the CPU, the assigned protection level and the real protection level. The assigned protection level is the one set during configuration, while the real one is the current protection level applicable for the communication session.

During normal operation clients that need read/write privileges query the real and assigned protection levels, after the communication setup, through SZL reads (SZL ID: 0x0132 SZL Index: 0x0004). If authentication is required the password is sent to the device, in a userdatamessage, which lowers the effective protection level.

Just before anyone would think that this provides at least a tiny bit of security let me clarify that it is not. The password is six bytes and sent almost in the clear (XORed with constants and shifted). It is replayable and can be bruteforced. The protocol also provides no integrity or confidentiality protection, message injection and modification is possible. The general rule of thumb when it comes to S7 security is if you can ping the device you can own it.

It must be noted here that the S7-1200/1500 series devices use a slightly different approach, protection levels are handled a bit differently and the password sent is significantly longer (it is actually the hash of the password) but it is still constant and replayable.

2. Read/Write Variable [0x04/0x05]

Pcaps:

  • s300-read-variable-simple
  • s300-read-write-variable (multiple variable reads and writes with simple addressing)
  • s400-read-write-variable-db (multiple variable reads and writes with database addressing)

Here is when things start to get a bit more complicated, I highly recommend looking at the provided pcaps while reading this section (wireshark2 comes with S7 dissector enabled by default). Data read and write operations are carried out by specifying the memory area of the variable, its address (offset) and its size or type. Before going into the protocol details I would like to briefly introduce the S7 addressing model.

Like mentioned previously variables are accessed by specifying their addresses, this address is composed of three main attributes. The memory area:

  • Merker:[M] arbitrary marker variables or flag registers reside here.
  • Data Block:[DB] DB areas are the most common place to store data required by the different functions of the device, these data block are numbered which is part of the address.
  • Input:[I] digital and analog input module values, mapped into memory.
  • Output:[Q] similarly memory mapped outputs.
  • Counter:[C] values of different counters used by the PLC program.
  • Timer:[T] values of different timers used by the PLC program.

There are other less common memory areas as well (such as local data [L] and peripheral access [P] and so on).

The type of the variable determines its length and how it should be interpreted. A few examples are:

  • BIT:[X] a single bit.
  • WORD: two bytes wide unsigned integer.
  • DINT: four bytes wide signed integer.
  • REAL: four bytes wide IEEE floating point number.
  • COUNTER: counter type used by the PLC program counters.

An example address of a variable is DB123X 2.1 which accesses the second bit of the third byte of the Data Block #123.

After this short detour let’s go back to the protocol’s implementation of variable read/write. The S7 protocol supports querying multiple variable reads/writes in single message with different addressing modes. There are three main modes:

  • any-type: This is the default addressing mode and it is used to query arbitrary variables. All three parameters (area, address, type) are specified for each addressed variable.
  • db-type: This is special mode designed to address DB area variables, it is more compact than the any-type addressing.
  • symbolic-addressing: This mode is used by the S7-1200/1500 series devices and allows the addressing of certain variables with their pre-defined symbolic names. This mode will not be covered in detail here.

For each addressing mode the Parameters header is structured in the same way:

  • Function Code:[1b] constant value of 0x04 for read or 0x05 for write Jobs and replies.
  • Item Count:[1b] number of following Request Item structures.
  • Request Item: this structure is used to address the actual variables, its length and fields depend on the type of addressing being used. These items are only present in the Job request and are emitted from the corresponding Ack Data no matter what the addressing mode is or whether it is a read or write request.

The Data part of the S7 PDU varies based on the type (read/write) and the direction (Job/Ack Data) of the message:

  • Read Request: the Data part is empty.
  • Read Response: the Ack Data message’s Data part consists of Data Item structures, one for each of the Request Items present in the original request. These items contain the actual value of the read variable and the format depends on the addressing mode.
  • Write Request: contains similar Data Items as the read response, one for each of the Request Items in the Parameter header. Similarly, these contain the variable value to be written on the slave device.
  • Write Response: The Data part of the Ack Data message simply contains a one byte error code for each of the Request Items in the original Write Request. See the constants.txt for the error code values.

To sum it up, the Request Item always contains the description of the variables and multiple of these can be sent in the Job request while the Data Items contain the actual values of the described variables. The Data Item structures must begin on even bytes so if their length is an odd number and there is a following Data Item then they are padded with a zero byte.

What is left to be discussed is the format of the Request/Data Item structures. As previously mentioned they are dependent on the addressing mode being used so they are going to be introduced based on that.

1.1 S7认证和保护

PCAP:S300认证

这可能是讨论S7身份验证和保护机制的好地方(即使它们与实际的通信设置无关)。在配置CPU期间,可以设置三种保护模式。

无保护:正如人们所期望的那样,不需要身份验证。
写保护:对于某些数据写入和配置更改操作,需要进行身份验证。
读/写保护:就像前一个一样,但某些读操作也需要验证。
必须注意的是,即使启用了读/写保护,也会允许某些操作,例如读取SZL列表或读取和写入标记区域。其他操作(如读取或写入对象/功能/数据块)应返回权限错误。

有两个与CPU关联的保护级别集,分配的保护级别和实际保护级别。分配的保护级别是配置期间设置的保护级别,而实际的保护级别是适用于通信会话的当前保护级别。

在正常操作期间,需要读/写权限的客户端在通信设置之后通过SZL读取(SZL ID:0x0132 SZL索引:0x0004)查询实际和分配的保护级别。如果需要身份验证,则会在userdatamessage中将密码发送到设备,从而降低有效保护级别。

就在任何人认为这至少提供了一点点安全性之前,让我澄清它不是。密码是六个字节,几乎以明文形式发送(与常量进行异或并移位)。它是可重放的,可以强制执行。该协议还不提供完整性或机密性保护,可以进行消息注入和修改。 S7安全性的一般经验法则是,如果您可以ping设备,则可以拥有它。

这里必须注意的是,S7-1200 / 1500系列设备使用略有不同的方法,保护级别处理稍有不同,发送的密码明显更长(实际上是密码的哈希),但它仍然是不变的,可玩性。

2.读/写变量[0x04 / 0x05]
Pcaps:

S300-读可变简单
s300-read-write-variable(多变量读写,简单寻址)
s400-read-write-variable-db(使用数据库寻址进行多变量读写)
这是事情开始变得复杂的时候,我强烈建议在阅读本节时查看提供的pcaps(wireshark2默认启用S7解析器)。通过指定变量的存储区域,地址(偏移量)及其大小或类型来执行数据读取和写入操作。在进入协议细节之前,我想简要介绍一下S7寻址模型。

如前所述,通过指定地址来访问变量,该地址由三个主要属性组成。内存区域:

Merker:[M]任意标记变量或标志寄存器驻留在这里。
数据块:[DB] DB区域是存储设备不同功能所需数据的最常见位置,这些数据块编号为地址的一部分。
输入:[I]数字和模拟输入模块值,映射到内存中。
输出:[Q]类似的存储器映射输出。
计数器:PLC程序使用的不同计数器的[C]值。
定时器:PLC程序使用的不同定时器的[T]值。
还有其他不太常见的存储区域(例如本地数据[L]和外设访问[P]等)。

变量的类型决定了它的长度以及它应该如何解释。一些例子是:

BIT:[X]一位。
WORD:两个字节宽的无符号整数。
DINT:四字节宽的有符号整数。
REAL:四个字节宽的IEEE浮点数。
COUNTER:PLC程序计数器使用的计数器类型。
变量的示例地址是DB123X 2.1,其访问数据块#123的第三字节的第二位。

在这个简短的绕道之后,让我们回到协议的变量读/写的实现。 S7协议支持使用不同的寻址模式在单个消息中查询多个变量读/写。主要有三种模式:

any-type:这是默认的寻址模式,用于查询任意变量。为每个寻址变量指定所有三个参数(区域,地址,类型)。
db-type:这是专门用于解决DB区域变量的特殊模式,它比any-type地址更紧凑。
符号寻址:S7-1200 / 1500系列设备使用此模式,允许使用预定义的符号名称寻址某些变量。此处不会详细介绍此模式。
对于每种寻址模式,Parameters头的结构方式相同:

功能代码:[1b]读取的常量值0x04或写入作业和回复的0x05。
项目数:[1b]以下请求项结构的数量。
请求项:此结构用于解决实际变量,其长度和字段取决于所使用的寻址类型。这些项目仅存在于作业请求中,无论寻址模式是什么,还是读取或写入请求,都会从相应的Ack数据中发出。
S7 PDU的数据部分根据消息的类型(读/写)和方向(作业/确认数据)而变化:

读取请求:数据部分为空。
读取响应:Ack数据消息的数据部分由数据项结构组成,每个结构对应于原始请求中的每个请求项。这些项包含读变量的实际值,格式取决于寻址模式。
写请求:包含与读取响应类似的数据项,一个用于参数头中的每个请求项。类似地,这些包含要在从设备上写入的变量值。
写响应:Ack数据消息的数据部分只包含原始写请求中每个请求项的一个字节错误代码。有关错误代码值,请参阅constants.txt。
总而言之,请求项始终包含变量的描述,其中多个可以在作业请求中发送,而数据项包含所描述变量的实际值。数据项结构必须以偶数字节开始,因此如果它们的长度是奇数,并且存在以下数据项,则它们用零字节填充。

剩下要讨论的是请求/数据项结构的格式。如前所述,它们依赖于所使用的寻址模式,因此将基于此引入它们。

2.1 Item Structures with any-type Addressing

The figure below shows the Request and Data Item structures:

2.1具有任何类型寻址的项目结构

下图显示了Request和Data Item结构:

The Siemens S7 Communication_第4张图片

The fields of the Request Item:

  • Specification Type:[1b] this field determines the main type of the item struct, for read/write messages it always has the value 0x12 which stands for Variable Specification.
  • Length:[1b] the length of the rest of this item.
  • Syntax ID:[1b] this field determines the addressing mode and the format of the rest of the item structure. It has the constant value of 0x10 for the any-type addressing.
  • Variable Type:[1b] is is used to determine the type and length of the variable (usual S7 types are used such as REAL, BIT, BYTE, WORD, DWORD, COUNTER, …).
  • Count:[2b] it is possible to select an entire array of similar variables with a single item struct. These variables must have the same type, and must be consecutive in the memory and the count field determines the size of this array. It is set to one for single variable read or write.
  • DB Number:[2b] the address of the database, it is ignored if the area is not set to DB (see next field).
  • Area:[1b] selects the memory area of the addressed variable. See the constants.txt for the memory area constants.
  • Address:[3b] contains the offset of the addressed variable in the selected memory area. Essentially, the addresses are translated to bit offsets and encoded on 3 bytes in network (big endian) byte order. In practice, the most significant 5 bits are never used since the address space is smaller than that. As an example DBX40.3 would be 0x000143 which is 40 * 8 + 3.

Similarly the fields of the associated Data Item:

  • Error Code:[1b] the return value of the operation, 0xff signals success. In the Write Request message this field is always set to zero.
  • Variable Type and Count:[1b 2b] same as in the Request Item.
  • Data: this field contains the actual value of the addressed variable, its size is len(variable) * count.
  • 请求项的字段:

    规范类型:[1b]该字段确定项结构的主要类型,对于读/写消息,它总是具有值0x12,代表变量规范。
    长度:[1b]此项目其余部分的长度。
    语法ID:[1b]此字段确定寻址模式和项目结构其余部分的格式。它具有任意类型寻址的常量值0x10。
    变量类型:[1b]用于确定变量的类型和长度(使用常用的S7类型,如REAL,BIT,BYTE,WORD,DWORD,COUNTER等)。
    计数:[2b]可以用单个项结构选择整个相似变量数组。这些变量必须具有相同的类型,并且必须在内存中连续,并且count字段确定此数组的大小。对于单变量读或写,它设置为1。
    DB编号:[2b]数据库的地址,如果该区域未设置为DB,则忽略该数据库(参见下一个字段)。
    区域:[1b]选择寻址变量的存储区域。有关内存区域常量,请参阅constants.txt。
    地址:[3b]包含所选存储区中寻址变量的偏移量。本质上,地址被转换为位偏移并在网络(大端)字节顺序中的3个字节上编码。实际上,由于地址空间小于5位,所以从不使用最重要的5位。例如,DBX40.3将是0x000143,即40 * 8 + 3。
    类似地,相关数据项的字段:

    错误代码:[1b]操作的返回值,0xff信号成功。在“写入请求”消息中,此字段始终设置为零。
    变量类型和计数:[1b 2b]与请求项中的相同。
    数据:此字段包含已寻址变量的实际值,其大小为len(变量)* count。

2.2 Item Structures with db-type Addressing

I have only seen this type of addressing used with S400 series devices, however it might be supported by some S300 series PLCs as well. It is only used to access DB variables and provides an alternative to address multiple different variables within a single item in a more compact format. The figure below shows the Request and Data Item structures:

2.2具有db-type寻址的项目结构

我只看到过S400系列设备使用的这种类型的寻址,但是某些S300系列PLC也可能支持它。 它仅用于访问数据库变量,并提供了一种替代方案,以更紧凑的格式在单个项目中处理多个不同的变量。 下图显示了Request和Data Item结构:

The Siemens S7 Communication_第5张图片

The fields of the Request Item:

  • Specification Type:[1b] same as with any-type addressing.
  • Length:[1b] the length of the rest of this item.
  • Syntax ID:[1b] determines the addressing mode, has a constant value of 0xb0 for db-type.
  • Number of Subitems:[1b] the number of following Subitems.
  • Subitem:
    • Size:[1b] specifies the number of bytes to read or write from the selected address.
    • DB Number:[2b] the DB where the addressed variable resides.
    • Address:[2b] byte offset of the variable into the given DB.

The fields of the Data Item:

  • Error Code:[1b] the return value of the operation, 0xff signals success.
  • Variable Type:[1b] always set to 0x09 (Octet String).
  • Length:[2b] length of the remaining Subresponse data.
  • Subresponse:
    • Error Code:[1b] the return value associated with the Subitem request.
    • Data: actual data to be read or written, interpreting this requires the corresponding Subitem.
    • 请求项的字段:

      规格类型:[1b]与任何类型寻址相同。
      长度:[1b]此项目其余部分的长度。
      语法ID:[1b]确定寻址模式,db-type的常量值为0xb0。
      子项数:[1b]以下子项的数量。
      分项:
      大小:[1b]指定从所选地址读取或写入的字节数。
      DB编号:[2b]寻址变量所在的DB。
      地址:[2b]将变量的字节偏移量放入给定的DB中。
      数据项的字段:

      错误代码:[1b]操作的返回值,0xff信号成功。
      变量类型:[1b]始终设置为0x09(八位字符串)。
      长度:[2b]剩余子响应数据的长度。
      Subresponse:
      错误代码:[1b]与Subitem请求关联的返回值。
      数据:要读取或写入的实际数据,解释这需要相应的Subitem。

3 Block Up/Download [0x1a-1f]

Pcaps:

  • s300-download-ob1
  • s300-snap7-upload

This is where things start to get messy. First of all, in Siemens terminology a download is when the master sends block data to the slave and upload is the other direction. On the Siemens devices, program code and (most of) the program data are stored in blocks, these blocks have their own header and encoding format, which will not be discussed here in detail. From the protocol’s point of view they are binary blobs that need to be transported (for the interested reader the snap7 sources provide information on the block headers and their encoding).

There are seven different type of blocks recognised by Siemens equipment:

  • OB: Organisation Block, stores the main programs.
  • (S)DB: (System) Data Block, stores data required by the PLC program.
  • (S)FC: (System) Function, functions that are stateless (do not have their own memory), they can be called from other programs.
  • (S)FB: (System) Function Block, functions that are stateful, they usually have an associated (S)DB.

The purpose of these blocks are well described in the Siemens documentation.

These blocks are addressed with a special ASCII filename within the up/download request. This filename is structured in a following way:

  • File Identifier:[1 char] as far as I know this always has the value of ‘_’.
  • Block Type:[2 chars] determines the block types, see the constants.txt for concrete values.
  • Block Number:[5 chars] the number of the given block in decimal format.
  • Destination File System:[1 char] this field can either have the value ‘A’ for Active or ‘P’ for Passive file systems. Blocks copied to the active file system are chained immediately, which means they are in effect as soon as the PLC execution resumes. On the other hand, blocks copied to the passive file system need to be activated first.

An example filename is _0800001P which is used to copy OB 1 to or from the passive file system.

** Let me make a quick note on block encoding and content protection. There are two measures in place to protect the content of programs and data on the devcies and allow the distribution of program libraries. The first one is called know-how protection, which if set prevents STEP7 or TIA showing the actual content of the block. Unfortunately, this is trivial to bypass, as it is just two bits set in the header of the blocks and can easily be cleared. The other protection measure is block “encryption”, which in reality is just an obfuscation with linear transformations (bytewise xoring and rotating with constants), again should be trivial to bypass. So do not rely on these “security” mechanisms to protect your know-how. Otherwise the data blocks contain the raw, initialized image of the memory. Program blocks contain the MC7 (Machine Code 7) binary instructions. **

Uploading and downloading blocks involves 3-3 different types of message pairs. These are listed below with the associated function codes:

  • Request Download - 0x1a
  • Download Block - 0x1b
  • Download Ended - 0x1c
  • Start Upload - 0x1d
  • Upload Block - 0x1e
  • End Upload - 0x1f

The structure of these messages are pretty simple, however the message sequence (especially for download) needs a bit of explaining.

3阻止/下载[0x1a-1f]
Pcaps:

S300下载,OB1
S300-snap7上传
事情开始变得混乱。首先,在西门子术语中,下载是主机将块数据发送到从机并且上载是另一个方向。在西门子设备上,程序代码和(大多数)程序数据以块的形式存储,这些块具有自己的头和编码格式,这里不再详细讨论。从协议的角度来看,它们是需要传输的二进制blob(对于感兴趣的读者,snap7源提供有关块头及其编码的信息)。

西门子设备认可七种不同类型的块:

OB:组织块,存储主程序。
(S)DB :(系统)数据块,存储PLC程序所需的数据。
(S)FC :(系统)功能,无状态功能(没有自己的内存),可以从其他程序调用。
(S)FB :(系统)功能块,有状态的功能,通常有关联的(S)DB。
西门子文档中详细描述了这些块的用途。

这些块在up / download请求中使用特殊的ASCII文件名进行寻址。此文件名的结构如下:

文件标识符:[1 char]据我所知,它总是具有'_'的值。
块类型:[2个字符]确定块类型,具体值请参见constants.txt。
块号:[5个字符]十进制格式的给定块的编号。
目标文件系统:[1 char]此字段的值可以是“A”表示活动,“P”表示被动文件系统。复制到活动文件系统的块会立即链接,这意味着它们会在PLC执行恢复后立即生效。另一方面,需要首先激活复制到被动文件系统的块。
示例文件名是_0800001P,用于将OB 1复制到被动文件系统或从被动文件系统复制OB 1。

**让我快速了解一下块编码和内容保护。有两种措施可以保护程序和数据的内容,并允许分发程序库。第一个称为专有技术保护,如果设置,则会阻止STEP7或TIA显示块的实际内容。不幸的是,这很容易绕过,因为它只是在块的标题中设置了两位并且可以很容易地被清除。另一个保护措施是块“加密”,实际上它只是一个线性变换的混淆(逐字节xoring和旋转常数),再次应该是微不足道的绕过。因此,不要依赖这些“安全”机制来保护您的专有技术。否则,数据块包含存储器的原始初始化图像。程序块包含MC7(机器代码7)二进制指令。 **

上传和下载块涉及3-3种不同类型的消息对。下面列出了相关的功能代码:

请求下载 - 0x1a
下载块 - 0x1b
下载结束 - 0x1c
开始上传 - 0x1d
上传块 - 0x1e
结束上传 - 0x1f
这些消息的结构非常简单,但是消息序列(特别是下载)需要一些解释。

3.1 Upload Block

The upload block sequence is fairly intuitive, it is presented below:

上传块序列非常直观,如下所示:

The Siemens S7 Communication_第6张图片

In the Ack Data - Start Upload message the slaves tells the length of the block and then the master keeps sending Job - Upload Block messages until receives all the bytes. Finally it closes the upload sequence with a Job - End Upload message. The actual data of the block is sent by the slave in the Ack Data - Upload Block messages.

Job - Start Upload Parameter Header:

  • Function Code:[1b] 0x1d for Start Upload.
  • Function Status:[1b] only used in the Upload message, set to 0x01 if more data is to be sent.
  • Unknown:[2b] always 0x0000.
  • Session ID:[4b] a unique id associated with each upload sequence, it is set in the Ack Data - Start Upload message.
  • Filename Length:[1b] length of the following filename.
  • Filename: the filename that identifies the block as introduced above.

Ack Data - Start Upload Parameter Header:

  • Function Code:[1b] 0x1d for Start Upload.
  • Function Status:[1b] same as above.
  • Unknown:[2b] always 0x0100.
  • Session ID:[4b] the Session ID is set here, consecutive messages use the same value.
  • Length String Length:[1b] length of the following Block Length String.
  • Length String: the decimal length of the block encoded as an ASCII C string (don’t ask me why…).

Job - Upload Parameter Header:

  • Contains the Function Code (0x1e), Function StatusUnknown (0x0000) and Session ID fields as discussed above.

Ack Data - Upload Parameter and Data Parts:

  • Function Code:[1b] 0x1e for Upload.
  • Function Status:[1b] set to 0x01 if more data is to be sent.
  • Data part:
    • Length:[2b] the length of the Block Data.
    • Unknown:[2b] always 0x00fb.
    • Block Data: part of the uploaded data block.

Job - End Upload Parameter Header:

  • Contains the Function Code (0x1f), Function StatusUnknown (0x0000) and Session ID fields as discussed above.

Ack Data - End Upload Parameter Header:

  • Simply contains the Function Code (0x1f)
  • 在Ack数据 - 开始上载消息中,从设备告诉块的长度,然后主设备继续发送作业 - 上传块消息,直到接收到所有字节。最后,它使用作业结束上传消息关闭上传序列。块的实际数据由从站在Ack数据 - 上传块消息中发送。

    作业 - 开始上传参数标题:

    功能代码:[1b] 0x1d用于开始上传。
    功能状态:[1b]仅用于上传消息,如果要发送更多数据,则设置为0x01。
    未知:[2b]始终为0x0000。
    会话ID:[4b]与每个上传序列相关联的唯一ID,它在Ack Data - Start Upload消息中设置。
    文件名长度:[1b]以下文件名的长度。
    文件名:标识上述块的文件名。
    确认数据 - 开始上传参数标题:

    功能代码:[1b] 0x1d用于开始上传。
    功能状态:[1b]与上述相同。
    未知:[2b]总是0x0100。
    会话ID:[4b]此处设置会话ID,连续消息使用相同的值。
    长度字符串长度:[1b]以下块长度字符串的长度。
    长度字符串:编码为ASCII C字符串的块的十进制长度(不要问我为什么......)。
    作业 - 上传参数标题:

    包含功能代码(0x1e),功能状态,未知(0x0000)和会话ID字段,如上所述。
    确认数据 - 上传参数和数据部分:

    功能代码:[1b] 0x1e用于上传。
    功能状态:[1b]如果要发送更多数据,则设置为0x01。
    数据部分:
    长度:[2b]块数据的长度。
    未知:[2b]始终为0x00fb。
    块数据:上传数据块的一部分。
    作业 - 结束上传参数标题:

    包含功能代码(0x1f),功能状态,未知(0x0000)和会话ID字段,如上所述。
    确认数据 - 结束上传参数标题:

    只包含功能代码(0x1f)

3.1 Download Block

The key difference between upload and download is that during download the direction of the communication changes and the slave becomes the master (well sort of). After the initial Request Download exchange the slave sends the Job messages and the master replies with Ack Data, this is the only exception to the “slave only replies” rule. After all the bytes are sent the master (the original) sends the Download Ended Job to close the download session. See the sequence diagram below.

上传和下载之间的关键区别在于,在下载过程中,通信方向发生变化,从站成为主站(很好)。 在初始请求下载交换后,从站发送作业消息,主站回复Ack数据,这是“仅从站回复”规则的唯一例外。 发送完所有字节后,主服务器(原始服务器)发送下载结束作业以关闭下载会话。 请参见下面的序列图。

The Siemens S7 Communication_第7张图片

The structure of the actual messages are really similar to the upload messages so I am only going to introduce the differences. For accurate syntax description open the example pcap in wireshark.

The Job - Request Download message contains two extra fields, the Block Length of the downloaded block and the Payload Length (the length without the block header) of the block. Both of these fields are decimal numbers encoded as ASCII strings. The response Ack Data - Request Download simply contains the Function Code.

Another significant difference is that, although the Session ID field is present it is not used (remains 0x00000000) instead the Filename is transmitted in each Job - Download Block. The structure of the rest of the messages is same as discussed before.

实际消息的结构与上传消息非常相似,所以我只介绍差异。 要获得准确的语法描述,请在wireshark中打开示例pcap。

作业 - 请求下载消息包含两个额外字段,即下载块的块长度和块的有效载荷长度(没有块头的长度)。 这两个字段都是编码为ASCII字符串的十进制数字。 响应Ack数据 - 请求下载仅包含功能代码。

另一个显着的区别是,虽然会话ID字段存在但不使用(仍为0x00000000)而是在每个作业 - 下载块中传输文件名。 其余消息的结构与前面讨论的相同。

4 PLC Control [0x28]

Pcaps:

  • s300-control-commands (Copy Ram to Rom, Compress Memory, Start PLC)
  • s300-copy-ram-to-rom
  • s300-activate-blocks
  • s300-delete-blocks (Activate/Delete Block, Start PLC)

(try using the s7comm.param.func == 0x28 wireshark filter to find the PLC Control messages)

PLC control messages are used to execute different routines on the slave device that modify its execution/memory state. Such commands are used to start or stop the PLC control program’s execution, activate or delete program blocks on the device or save its configuration to persistent memory. The structure of these messages are fairly simple, they are going to be explained without discussing the exact details (for that see the attached captures).

The Job - PLC Control message consists of two main parts, the ASCII name of the called method and its parameter (also encoded as an ASCII string). The method name is structured in a similar manner as the file names introduced in the block transfer section. The parameters depend on the method type and they can be thought of as an argument to it. The Ack Data message simply contains the PLC Control function code.

Some example function names and their associated parameters:

  • _INSE: activates a downloaded block on the device, the parameter is the name of the block (e.g. OB1).
  • _DELE: removes a block from the file system of the device, the parameter is again the name of the block.
  • P_PROGRAM: sets the run state of the device (start, stop, mem reset). It is sent without parameter to start the device, however stopping the plc program uses a different function code (see next section).
  • _GARB: compresses PLC memory.
  • _MODU: copy ram to rom, the parameter contains the file system identifiers (A/E/P).
  • Pcaps:

    s300-control-commands(将Ram转移到Rom,压缩内存,启动PLC)
    S300-复制RAM到ROM
    S300激活块
    s300-delete-blocks(激活/删除块,启动PLC)
    (尝试使用s7comm.param.func == 0x28 wireshark过滤器查找PLC控制消息)

    PLC控制消息用于在从设备上执行修改其执行/存储状态的不同例程。这些命令用于启动或停止PLC控制程序的执行,激活或删除设备上的程序块或将其配置保存到永久存储器。这些消息的结构非常简单,它们将在不讨论确切细节的情况下进行解释(有关详细信息,请参见附件)。

    作业 - PLC控制消息由两个主要部分组成,即被调用方法的ASCII名称及其参数(也编码为ASCII字符串)。方法名称的结构与块传输部分中引入的文件名的方式类似。参数取决于方法类型,可以将它们视为参数。 Ack数据消息只包含PLC控制功能代码。

    一些示例函数名称及其相关参数:

    _INSE:激活设备上下载的块,参数是块的名称(例如OB1)。
    _DELE:从设备的文件系统中删除一个块,该参数也是该块的名称。
    P_PROGRAM:设置设备的运行状态(启动,停止,mem重置)。它在没有参数的情况下发送以启动设备,但是停止plc程序使用不同的功能代码(参见下一节)。
    _GARB:压缩PLC内存。
    _MODU:将ram复制到rom,该参数包含文件系统标识符(A / E / P)。

5 PLC Stop [0x29]

Pcap s300-stop-program

The PLC Stop message is essentially the same as the PLC Control message. The only difference is that there is no parameter in the message and the routine part is always set to P_PROGRAM. I have no idea why it has its separate type instead of using a parameter to determine whether it is a start or stop message.

Outro

Well, this blog post grew way longer than I originally planned it to be, but I hope it will be useful for some. This might be obvious now, but the S7 protocol is not a well designed one. It was originally created to simply query register values, which it did kind of all right, but then functionality was kept being added until it became this monstrosity. It is filled with inconsistencies and unnecessary redundancies and it only gets worse with Userdatamessages. These irregularities and design flaws become way more obvious (and annoying) while trying to write a parser for the protocol.

TL;DR

If S7 was a car it would probably look like this:

PCAP S300停止程序

PLC停止消息与PLC控制消息基本相同。 唯一的区别是消息中没有参数,并且例程部分始终设置为P_PROGRAM。 我不知道为什么它有单独的类型而不是使用参数来确定它是一个开始或停止消息。

结尾
好吧,这篇博文的发展时间比我原先计划的要长,但我希望它对某些人有用。 这可能是显而易见的,但S7协议并不是一个设计良好的协议。 它最初是为了简单地查询寄存器值而创建的,它做得很好,但随后功能一直被添加,直到它成为这个怪物。 它充满了不一致和不必要的冗余,而且只会因Userdatamessages而变得更糟。 在尝试为协议编写解析器时,这些不规则性和设计缺陷变得更加明显(并且令人讨厌)。

TL; DR

如果S7是一辆汽车,它可能看起来像这样:

The Siemens S7 Communication_第8张图片

你可能感兴趣的:(工业防火墙)