前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[网关开发] 西门子 S7 通信协议概述2

[网关开发] 西门子 S7 通信协议概述2

作者头像
科控物联
发布2023-09-01 08:08:22
1K0
发布2023-09-01 08:08:22
举报
文章被收录于专栏:科控自动化

S7 PDU 的结构和通用协议标头在上一部分进行了说明。但是,参数标头特定于消息类型,对于作业Ack 数据消息,它以函数代码开头。其余字段的结构取决于此值。此函数代码确定消息的用途,并作为进一步讨论的基础。

1. 设置通信 [0xF0]

pcap:S300 设置通信

此消息对(作业确认数据响应)在每个会话开始时发送,然后才能交换任何其他消息。它用于协商 Ack 队列的大小和最大 PDU 长度,双方声明其支持的值。Ack 队列的长度决定了无需确认即可同时启动的并行作业数。PDU 和队列长度字段都是大端序。

下图显示了参数标头:

1.1 S7 身份验证和保护

pcap:s300 身份验证

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

  • 无保护:正如人们期望不需要身份验证一样。
  • 写保护:对于某些数据写入和配置更改操作,需要进行身份验证。
  • 读/写保护:就像上一个一样,但某些读取操作也需要身份验证。

必须注意的是,即使启用了读/写保护,也允许某些操作,例如读取 SZL 列表或读取和写入标记区域。其他操作(如读取或写入对象/功能/数据块)应返回权限错误。

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

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

在任何人认为这至少提供了一点点安全性之前,让我澄清一下事实并非如此。密码是六个字节,几乎发送 在明文中(用常量进行异或并移位)。它是可重玩的,可以暴力破解。该协议还提供完整性或机密性保护,消息注入和修改是可能的。在S7安全性方面,一般的经验法则是,如果您可以ping设备,则可以拥有它

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

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

帽子:

  • S300-读取变量-简单
  • S300-读-写-变量(具有简单寻址的多变量读写)
  • S400-read-write-variable-db(具有数据库寻址的多变量读写)

当事情开始变得有点复杂时,我强烈建议在阅读本节时查看提供的 pcaps(wireshark2 默认启用 S7 剖析器)。数据读取和写入操作是通过指定变量的内存区域、其地址(偏移量)及其大小或类型来执行的。在详细介绍协议之前,我想简要介绍一下 S7 寻址模型。

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

  • Merker:[M] 任意标记变量或标志寄存器驻留在这里。
  • 数据块:[DB] DB区域是存储设备不同功能所需的数据最常用的位置,这些数据块被编号,这是地址的一部分。
  • 输入:[I]数字和模拟输入模块值,映射到存储器中。
  • 输出:[Q] 类似的内存映射输出。
  • 计数器:PLC 程序使用的不同计数器的 [C] 值。
  • 定时器:PLC程序使用的不同定时器的[T]值。

还有其他不太常见的内存区域(例如本地数据[L]和外设访问[P]等)。

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

  • 位:[X] 单个位。
  • 字:两个字节宽的无符号整数。
  • DINT:四个字节宽的有符号整数。
  • 实数:四个字节宽的IEEE浮点数。
  • 计数器:PLC程序计数器使用的计数器类型。

变量的一个示例地址是 DB123X 2.1,它访问数据块 #123 的第三个字节的第二个位。

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

  • 任何类型:这是默认寻址模式,用于查询任意变量。为每个寻址变量指定所有三个参数(区域、地址、类型)。
  • 数据库类型:这是旨在解决数据库区域变量的特殊模式,它比任何类型的寻址都更紧凑。
  • 符号寻址:S7-1200/1500 系列设备使用此模式,并允许使用预定义的符号名称对某些变量进行寻址。此处不详细介绍此模式。

对于每种寻址模式,参数标头的结构方式相同:

  • 功能代码:[1b] 0x04 的常量值用于读取或0x05用于写入作业和回复。
  • 项目计数:[1b] 以下请求项目结构的数量。
  • 请求项:此结构用于处理实际变量,其长度和字段取决于所使用的寻址类型。这些项仅存在于作业请求中,并且从相应的 Ack 数据发出,无论寻址模式是什么,也不管它是读取还是写入请求。

S7 PDU 的数据部分因消息的类型(读/写)和方向(作业/确认数据)而异:

  • 读取请求:数据部分为空。
  • 读取响应:确认数据消息的数据部分由数据项结构组成,原始请求中存在的每个请求项对应一个结构。这些项包含读取变量的实际值,格式取决于寻址模式。
  • 写入请求:包含与读取响应类似的数据项,参数标头中的每个请求项一个。同样,它们包含要在从设备上写入的变量值。
  • 写入响应:Ack 数据消息的 Data 部分仅包含原始写入请求中每个请求项的一个字节错误代码。有关错误代码值,请参阅常量.txt。

总而言之,请求项始终包含变量的描述,并且可以在作业请求中发送其中的多个变量,而数据项包含所描述变量的实际值。数据项结构必须从偶数字节开始,因此如果它们的长度是奇数并且有后面的数据,则用零字节填充它们。

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

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

下图显示了请求和数据项结构:

请求项的字段:

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

类似地,关联数据项的字段:

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

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

请求项的字段:

  • 规范类型:[1b] 与任何类型的寻址相同。
  • 长度:[1b] 本项目其余部分的长度。
  • 语法 ID:[1b] 确定寻址模式,对于 db 类型具有常量值 0xb0。
  • 子项数:[1b] 以下子项数。
  • 子项目
    • 大小:[1b] 指定从所选地址读取或写入的字节数。
    • 数据库编号:[2b] 寻址变量所在的数据库。
    • 地址:[2b] 将变量的字节偏移量转换为给定的数据库。

数据项的字段:

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

3 屏蔽/下载 [0x1a-1f]

Pcaps:

  • s7-pcaps/tia_s300_downloadOb1.pcapng at master · gymgit/s7-pcaps (github.com)
  • s7-pcaps/snap7_s300_everything.pcapng at master · gymgit/s7-pcaps (github.com)

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

西门子设备可识别七种不同类型的模块:

  • OB:组织块,存储主程序。
  • S)DB:(系统)数据块,存储PLC程序所需的数据。
  • S)FC:(系统)函数,无状态(没有自己的内存)的函数,可以从其他程序调用它们。
  • (S)FB:(系统)功能块,有状态的功能,它们通常具有关联的(S)DB。

西门子文档中详细描述了这些块的用途。

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

  • 文件标识符:[1 个字符] 据我所知,它总是具有“_”的值。
  • 块类型:[2 个字符] 确定块类型,请参阅常量.txt了解具体值。
  • 块号:[5 个字符] 十进制格式的给定块的编号。
  • 目标文件系统:[1 个字符] 此字段的值可以为“A”表示主动文件系统,也可以具有“P”表示被动文件系统的值。复制到活动文件系统的块会立即链接,这意味着一旦 PLC 执行恢复,它们就会生效。另一方面,复制到被动文件系统的块需要首先激活。

一个示例文件名是 _0800001P,用于将 OB 1 复制到被动文件系统或从被动文件系统复制 OB <>。

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

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

  • 请求下载 - 0x1a
  • 下载块 - 0x1b
  • 下载结束 - 0x1c
  • 开始上传 - 0x1d
  • 上传阻止 - 0x1e
  • 结束上传 - 0x1f

这些消息的结构非常简单,但是消息序列(尤其是下载)需要一些解释。

3.1 上传块

上传块序列相当直观,如下所示:

确认数据 - 开始上传消息中,从站告诉块的长度,然后主站继续发送作业 - 上传块消息,直到收到所有字节。最后,它使用作业 - 结束上传消息关闭上传序列。块的实际数据由从站发送在确认数据 - 上传块消息中。

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

  • 功能代码:[1b] 0x1d用于开始上传
  • 函数状态:[1b] 仅在上传消息中使用,如果要发送更多数据,则设置为 0x01。
  • 未知:[2b] 总是0x0000。
  • 会话 ID:[4b] 与每个上传序列相关联的唯一 ID,在 Ack 数据 - 开始上传消息中设置。
  • 文件名长度:[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 下载块

上传和下载之间的主要区别在于,在下载过程中,通信的方向会发生变化,从站成为主站(嗯)。在初始请求下载交换后,从站发送作业消息,主站使用Ack Data回复,这是“仅从站应答”规则的唯一例外。发送所有字节后,主节点(原始字节)将下载结束作业发送到 关闭下载会话。请参阅下面的序列图。

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

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

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

4 可编程控制器控制 [0x28]

Pcaps:

  • s300-控制命令(将内存复制到ROM,压缩内存,启动PLC)
  • S300-复制内存到只读存储器
  • S300-激活块
  • s300-删除块(激活/删除块,启动PLC)

(尝试使用 wireshark 过滤器查找 PLC 控制消息)s7comm.param.func == 0x28

PLC控制消息用于在从设备上执行修改其执行/内存状态的不同例程。此类命令用于启动或停止PLC控制程序的执行,激活或删除设备上的程序块或将其配置保存到持久内存中。这些消息的结构相当简单,将在不讨论确切细节的情况下对其进行解释(有关此,请参阅随附的捕获)。

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

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

  • _INSE:激活设备上下载的块,参数是块的名称(例如OB1)。
  • _DELE:从设备的文件系统中删除一个块,参数又是块的名称。
  • P_PROGRAM:设置设备的运行状态(启动、停止、内存重置)。它不带参数来启动设备,但是停止 plc 程序使用不同的功能代码(请参阅下一节)。
  • _GARB:压缩 PLC 内存。
  • _MODU:将RAM复制到ROM,该参数包含文件系统标识符(A/E/P)。

5 PLC 停止 [0x29]

Pcap s300停止程序

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

尾声

希望它对某些人有用。这在现在可能很明显,但 S7 协议不是一个设计良好的协议。它最初是为了简单地查询寄存器值而创建的,它做得很好,但后来不断添加功能,直到它成为这个怪物。它充满了不一致和不必要的冗余,并且只会因用户数据消息而变得更糟。这些 在尝试为协议编写解析器时,不规则和设计缺陷变得更加明显(和烦人)。

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

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-08-06,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 科控物联 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 设置通信 [0xF0]
    • 1.1 S7 身份验证和保护
    • 2. 读/写变量 [0x04/0x05]
      • 2.1 具有任意类型寻址的项目结构
        • 2.2 具有数据库类型寻址的项目结构
        • 3 屏蔽/下载 [0x1a-1f]
          • 3.1 上传块
            • 3.1 下载块
            • 4 可编程控制器控制 [0x28]
            • 5 PLC 停止 [0x29]
            • 尾声
            相关产品与服务
            多因子身份认证
            多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档