前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[ffffffff0x] 工控协议:S7COMM协议分析(上)

[ffffffff0x] 工控协议:S7COMM协议分析(上)

原创
作者头像
r0fus0d
修改2021-01-19 10:30:23
3.7K0
修改2021-01-19 10:30:23
举报
文章被收录于专栏:ffffffff0x

前言

在上一篇文章中,我们通过模拟器环境实现了S7-300的启停实验。本次文章,我们将详细介绍S7comm协议的S7Comm Header和Job 和 Ack_Data机制并抓包分析其请求和相应报文。


S7Comm

S7Comm(S7 Communication)是西门子专有的协议,是西门子 S7 通讯协议簇里的一种。

S7 协议的 TCP/IP 实现依赖于面向块的 ISO 传输服务。S7 协议被封装在 TPKT 和 ISO-COTP 协议中,这使得 PDU(协议数据单元)能够通过 TCP 传送。

它用于 PLC 编程,在 PLC 之间交换数据,从 SCADA(监控和数据采集)系统访问 PLC 数据以及诊断目的。

S7Comm 以太网协议基于 OSI 模型,从 wireshark 协议分级可以看出排列。

S7Comm 数据作为 COTP 数据包的有效载荷,第一个字节总是 0×32 作为协议标识符。

S7Comm 协议包含三部分:

  • Header
  • Parameter
  • Data

根据实现的功能不同,S7 comm 协议的结构会有所不同。


S7Comm Header

S7Comm 的头,定义了该包的类型、参数长度、数据长度等。

S7Comm Header的格式为:

  • 0 (unsigned integer, 1 byte): Protocol Id,协议 ID,通常为 0×32;
  • 1 (unsigned integer, 1 byte): ROSCTR,PDU type,PDU 的类型,一般有以下值:
    • 0×01 - JOB(Request: job with acknowledgement):作业请求。由主设备发送的请求(例如,读/写存储器,读/写块,启动/停止设备,设置通信);
    • 0×02 - ACK(acknowledgement without additional field):确认响应,没有数据的简单确认(未遇到过由 S7 300/400 设备发送得);
    • 0×03 - ACK_DATA(Response: acknowledgement with additional field):确认数据响应,这个一般都是响应JOB的请求;
    • 0×07 - USERDATA:原始协议的扩展,参数字段包含请求/响应 ID(用于编程/调试,读取 SZL,安全功能,时间设置,循环读取…)。
  • 2~3 (unsigned integer, 2 bytes): Redundancy Identification (Reserved),冗余数据,通常为 0×0000;
  • 4~5 (unsigned integer, 2 bytes): Protocol Data Unit Reference,it’s increased by request event。协议数据单元参考,通过请求事件增加;
  • 6~7 (unsigned integer, 2 bytes): Parameter length,the total length (bytes) of parameter part。参数的总长度;
  • 8~9 (unsigned integer, 2 bytes): Data length,数据长度。如果读取 PLC 内部数据,此处为 0×0000;对于其他功能,则为 Data 部分的数据长度;

其中最重要的字段就是 ROSCTR,它决定了后续参数的结构

在响应数据包中,还有可能存在错误信息,其错误信息结构为:

  • 10 (unsigned integer, 1 bytes): Error class,错误类型:
  • 11 (unsigned integer, 1 bytes): Error code,错误代码;流量包分析

下载 wireshark 官网公开的pcap包 https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=s7comm_downloading_block_db1.pcap

COTP Connection Packet

  • COTP 连接请求包
  • COTP 请求确认包

COTP Fuction Packet

  • 数据传输包

S7Comm Header

其中最重要的字段就是 ROSCTR,它决定了后续参数的结构

在响应数据包中,还有可能存在错误信息

可见图中的错误类型就是 No error


Job 和 Ack_Data

S7Comm 中 Job(作业请求) 和 Ack_Data(确认数据响应) 中的 Parameter 项的第一个字段是 function(功能码),其类型为 Unsigned integer,大小为 1 byte,决定了其余字段的结构、消息的目的。

建立通信(Setup communication 0xF0)

建立通信在每个会话开始时被发送,然后可以交换任何其他消息。它用于协商 ACK 队列的大小和最大 PDU 长度,双方声明它们的支持值。ACK 队列的长度决定了可以同时启动而不需要确认的并行作业的数量。PDU 和队列长度字段都是大端。

当 PDU 类型为 Job 时,具体的 Parameter 结构,如下:

  • 1 (Unsigned integer, 1 byte): Parameter part: Reserved byte in communication setup pdu,保留字节;
  • 2 (Unsigned integer, 2 bytes): Max AmQ (parallel jobs with ack) calling;
  • 3 (Unsigned integer, 2 bytes): Max AmQ (parallel jobs with ack) called;
  • 4 (Unsigned integer, 2 bytes): Parameter part: Negotiate PDU length。协商 PDU 长度。

读取值(Read Var 0x04)

数据读写操作通过指定变量的存储区域,地址(偏移量)及其大小或类型来执行。

当 PDU 类型为 Job 时,item的结构如下:

  • 0 (Unsigned integer, 1 byte): Variable specification,确定项目结构的主要类型,通常为 0×12,代表变量规范;
  • 1 (Unsigned integer, 1 byte): Length of following address specification,本 Item 其余部分的长度;
  • 2 (Unsigned integer, 1 byte): Syntax Ids of variable specification,确定寻址模式和其余项目结构的格式;
  • 3(Unsigned integer, 1 byte): Transport sizes in item data,确定变量的类型和长度:
  • 4~5 (Unsigned integer ,2 byte): Request data length,请求的数据长度;
  • 6~7 (Unsigned integer, 2 byte): DB number,DB 模块的编号,如果访问的不是 DB 区域,此处为 0×0000;
  • 8 (Unsigned integer, 1 byte):: Area,区域类型:
  • 9~11(Unsigned integer, 3 byte): Address,地址。

PDU 类型为 Ack_Data 时,Data 结构如下:

  • 0 (Unsigned integer, 1 byte): Return code,返回代码:
  • 1 (Unsigned integer, 1 byte): Transport size,数据的传输尺寸:
  • 2~3 (Unsigned integer, 2 bytes): Length,数据的长度;
  • 4~4+length (?): Data,数据;
  • ? (Unsigned integer, 1 byte): Fill byte,填充字节。

写入值(Write Var 0x05)

Write Var 中 Parameter 的结构跟读取值(Read Var0x04)一样,但是 Write Var 还需写入值,所以 Write Var 比 Read Var 多了一个 Data 项。

Data 的结构为:

  • 0 (Unsigned integer, 1 byte): Return code,返回代码,这里是未定义,所以为 Reserved(0×00);
  • 1 (unsigned integer, 1 byte): Transport size,确定变量的类型和长度:
  • 2-3 (unsigned integer, 2 bytes): Length,写入值的数据长度;
  • 4 (1 byte): Data,写入的值;
  • 5 (unsigned integer, 1 byte): Fill byte,填充字节,如果数据的长度不足 Length 的话,则填充;

PDU 类型为 Ack_Data 时,Parameter 也只有 function、item count 两个字段。而 Data 中也只有一个 Return code 字段,其结构如下:

  • 0 (Unsigned integer, 1 byte): Return code,返回代码:

下载

下载Step7 发送块数据给 PLC.在西门子设备上,程序代码和(大部分)程序数据存储在块中,这些块有自己的头和编码格式。

在西门子设备中有8种不同类型的功能块,这些块在上/下载请求中用特殊的ASCII文件名寻址。这个文件名的结构如下:

  • 1 (1 byte): File identifier(ASCII),文件标识符。其有_ (Complete Module)、$ (Module header for up-loading)两种文件标识符;
  • 2 (2 bytes): Block type,块类型。
  • 3 (5 bytes): Block number,块编号;
  • 4 (1 byte): Destination filesystem(ASCII),目标的文件系统。其有三种文件系统:
    • P (Passive (copied, but not chained) module):被动文件系统
    • A (Active embedded module):主动文件系统
    • B (Active as well as passive module):既主既被文件系统

下载有3种不同的功能类型:

  • 请求下载(Request download 0x1A)

当 PDU 类型为 Job 时,Request download 0x1A 没有 Data,其 Parameter 的结构,如下

  • 1 (1 byte): Function Status,功能码状态;
  • 2 (2 bytes): for all unknown bytes in blockcontrol;
  • 3 (4 bytes): 无意义,一般为0x00000000;
  • 4 (1 byte): filename length,文件名长度;
  • 5 (? bytes): filename, default is 9 byte,文件名,长度一般为9个字节;
    • 1 (1 byte): File identifier(ASCII),文件标识符。其有_ (Complete Module)、$ (Module header for up-loading)两种文件标识符;
    • 2 (2 bytes): Block type,块类型。
    • 3 (5 bytes): Block number,块编号;
    • 4 (1 byte): Destination filesystem(ASCII),目标的文件系统。其有P(Passive (copied, but not chained) module)、A (Active embedded module)、B (Active as well as passive module)三种文件系统;
  • 6 (1 byte): Length part 2 in bytes,参数的第二部分长度,也就是接下来的字段长度;
  • 7 (1 byte): Unknown char(ASCII);
  • 8 (6 bytes): Length load memory in bytes(ASCII);
  • 9 (6 bytes): Length of MC7 code in bytes(ASCII)。 PDU 类型为 Ack_Data 时,Request download 0x1A 的 Parameter 中只有一个 function。

PDU 类型为 Ack_Data 时,Request download 0x1A 的 Parameter 中只有一个 function。

  • 下载块(Download block 0x1B)

下载是 Step7 发送块数据给 PLC。当 PDU 类型为 Job 时,Download block 0x1B 也没有 Data,其 Parameter 的结构,如下

  • 1 (1 byte): Function Status,功能码状态;
  • 2 (2 bytes): for all unknown bytes in blockcontrol;
  • 3 (4 bytes): 无意义,一般为0x00000000;
  • 4 (1 byte): filename length,文件名长度;
  • 5 (? bytes): filename, default is 9 byte,文件名,长度一般为9个字节;
    • 1 (1 byte): File identifier(ASCII),文件标识符。其有_ (Complete Module)、$ (Module header for up-loading)两种文件标识符;
    • 2 (2 bytes): Block type,块类型。
    • 3 (5 bytes): Block number,块编号;
    • 4 (1 byte): Destination filesystem(ASCII),目标的文件系统。其有P(Passive (copied, but not chained) module)、A (Active embedded module)、B (Active as well as passive module)三种文件系统;

Download block 0x1B 的 Parameter 与 Request download 0x1A 的 Parameter 的第一部分相同

那 PDU 类型为 Ack_Data 时,Download block 0x1B 有 Parameter 和 Data,其 Parameter 的结构,如下

  • 1 (1 byte): Function Status,功能码状态;
    • 1 (Unsigned integer, 2 bytes): Length,数据长度;
    • 2 (Unsigned integer, 2 bytes): Unknown byte(s) in blockcontrol,未知字节;
    • 3 (Label,data_length-4 bytes): Data,数据;
  • 下载结束(Download ended 0x1C)

当 PDU 类型为 Job 时,Download ended 0x1C 也没有 Data,其 Parameter 的结构,如下:

  • 1 (1 byte): Function Status,功能码状态;
  • 2 (2 bytes): for all unknown bytes in blockcontrol;
  • 3 (4 bytes): 无意义,一般为 0x00000000;
  • 4 (1 byte): filename length,文件名长度;
  • 5 (? bytes): filename, default is 9 byte,文件名,长度一般为9个字节;
    • 1 (1 byte): File identifier(ASCII),文件标识符。其有_ (Complete Module)、$ (Module header for up-loading)两种文件标识符;
    • 2 (2 bytes): Block type,块类型。
    • 3 (5 bytes): Block number,块编号;
    • 4 (1 byte): Destination filesystem(ASCII),目标的文件系统。其有P(Passive (copied, but not chained) module)、A (Active embedded module)、B (Active as well as passive module)三种文件系统;

PDU 类型为 Ack_Data 时,Download ended 0x1C 的 Parameter 中只有一个 function。

上传

上传是 PLC 发送块数据给 Step7

在上传过程中,先是 Step7 向 PLC 发送一个开始上传的 Job,PLC 收到后则回复一个 Ack_Data,并告诉 Step7 块的长度、上传会话 ID。然后 PLC 继续上传块数据到 Step7,直到 Step7 收到所有字节。最后,Step7 发送结束上传的作业请求来关闭上传会话。

上传有3种不同的功能类型

  • 开始上传(Start upload 0x1D)

当 PDU 类型为 Job 时,Start upload 0x1D 没有 Data,其 Parameter 的结构,如下

  • 1 (1 byte): Function Status,功能码状态;
  • 2 (2 bytes): for all unknown bytes in blockcontrol;
  • 3 (4 bytes): 上传的会话ID,此时为0x00000000;
  • 4 (1 byte): filename length,文件名长度;
  • 5 (? bytes): filename, default is 9 byte,文件名,长度一般为9个字节;
    • 1 (1 byte): File identifier(ASCII),文件标识符。其有_ (Complete Module)、$ (Module header for up-loading)两种文件标识符;
    • 2 (2 bytes): Block type,块类型。
    • 3 (5 bytes): Block number,块编号;
    • 4 (1 byte): Destination filesystem(ASCII),目标的文件系统。其有P(Passive (copied, but not chained) module)、A (Active embedded module)、B (Active as well as passive module)三种文件系统;

那 PDU 类型为 Ack_Data 时,Start upload 0x1D 的 Parameter 的结构,如下

  • 1 (1 byte): Function Status,功能码状态;
  • 2 (2 bytes): for all unknown bytes in blockcontrol;
  • 3 (4 bytes): 上传的会话ID,告诉Step7上传会话ID;
  • 4 (Unsigned integer, 1 byte): Blocklengthstring Length;
  • 5 (Character string): Blocklength,块的长度;
  • 上传(Upload 0x1E)

当 PDU 类型为 Job 时,Upload 0x1E 也没有 Data,其 Parameter 的结构,如下

  • 1 (1 byte): Function Status,功能码状态;
  • 2 (2 bytes): for all unknown bytes in blockcontrol;
  • 3 (4 bytes): 上传的会话ID,告诉Step7上传会话ID;

PDU 类型为 Ack_Data 时,Upload 0x1E 有 Parameter 和 Data,其 Parameter 的结构,如下

  • 1 (1 byte): Function Status,功能码状态;
    • 1 (Unsigned integer, 2 bytes): Length,数据长度;
    • 2 (Unsigned integer, 2 bytes): Unknown byte(s) in blockcontrol,未知字节;
    • 3 (Label,data_length-4 bytes): Data,数据;
  • 上传结束(End upload 0x1F)

上传结束的过程,即为所有数据上传完成后,Step7 发送结束上传的作业请求,PLC 收到后就关闭会话,然后返回一个响应。

当 PDU 类型为 Job 时,End upload 0x1F 也没有 Data,其 Parameter 的结构,如下

  • 1 (1 byte): Function Status,功能码状态;
  • 2 (2 bytes): Error code,错误代码:
  • 3 (4 bytes): 上传的会话ID,告诉 Step7 上传会话 ID; 那 PDU 类型为 Ack_Data 时,End upload 0x1F 的 Parameter 中只有一个 function。

程序调用服务(PI service 0x28)

程序调用是用于在 PLC 执行修改执行/内存状态的日常工作。这些命令可以用于启动或停止 PLC 控制程序、激活或删除程序块。

当 PDU 类型为 Job 时,PI service 0x28 没有 Data,只有 Parameter,那 Parameter 的结构,如下:

  • 1 (7 bytes): Unknown;
  • 2 (Unsigned integer, 2 bytes): Parameter block length;
  • 3 (?bytes): Parameter block,参数;
  • 4 (Unsigned integer, 1 byte):String length,PI service的字符串长度;
  • 5 (Character string, ASCII):PI (program invocation) Service name,程序调用服务名

Parameter 包含两个主要部分:

  • 服务名称
  • 参数:取决于方法类型,可以将它们看作是它的参数

服务名称及其相关参数的示例:

  • _INSE:激活设备上下载的块,参数是块的名称(比如:OB 1)。
  • _DELE:从设备的文件系统中删除一个块,该参数也是该块的名称。
  • P_PROGRAM:设置设备的运行状态(启动、停止、复位)。
  • _GARB:压缩 PLC 内存。
  • _MODU:将 ram 复制到 ROM,参数包含文件系统标识符(A/E/P)。

如果服务调用的参数是块的话,那么 Parameter block 的结构如下:

  • 1 (1 byte): Number of block;
  • 2 (1 byte): Unknown,默认为 0x00;
  • 3 (? bytes): filename,文件名:
  • 1 (2 bytes, ASCII): Block type,块类型。
  • 2 (5 bytes, ASCII): Block number,块编号;
  • 3 (1 byte, ASCII): Destination filesystem(ASCII),目标的文件系统。其有 P(Passive (copied, but not chained) module)、A (Active embedded module)、B (Active as well as passive module)三种文件系统;

PLC STOP 0x29

PLC STOP 基本上跟程序调用服务(PI service 0x28)一致,唯一的区别就是它没有 Parameter block,而它的 PI service 为 P_PROGRAM。

流量包分析

下载 wireshark 官网公开的pcap包 https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=s7comm_downloading_block_db1.pcap

建立通信(Setup communication 0xF0)

  • 请求
  • 响应

其协商结果为:ACK 队列的大小为 1;最大 PDU 长度为 240。

请求下载(Request download 0x1A)

  • 请求
  • 响应

下载块(Download block 0x1B)

  • 请求
  • 响应

下载结束(Download ended 0x1C)

  • 请求
  • 响应

程序调用服务(PI service 0x28)

  • 请求
  • 响应

然后再下载这个流量包 https://github.com/ITI/ICS-Security-Tools/blob/master/pcaps/s7/snap7_s300_everything.pcapng

开始上传(Start upload 0x1D)

  • 请求
  • 响应

上传(Upload 0x1E)

  • 请求
  • 响应

上传结束(End upload 0x1F)

  • 请求
  • 响应

然后再下载这个流量包 https://wiki.wireshark.org/SampleCaptures?action=AttachFile&do=get&target=s7comm_varservice_libnodavedemo.pcap

读取值(Read Var 0x04)

  • 读值操作的作业请求
  • 响应

写入值(Write Var 0x05)

  • 向地址为 0×000020 的 Flags(M)写入 0×0103 的作业请求
  • 向地址为 0×000020 的 Flags(M)写入 0×0103 的确认响应

总结

本文,我们分析了S7comm协议的S7Comm Header、Job 和 Ack_Data机制,并通过wireshark抓包分析其请求和相应报文。下一篇文章,我们将继续学习S7comm协议Userdata 协议拓展部分。


本文作者 r0fus0d

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • S7Comm
  • S7Comm Header
  • Job 和 Ack_Data
    • 流量包分析
    • 总结
    相关产品与服务
    数据保险箱
    数据保险箱(Cloud Data Coffer Service,CDCS)为您提供更高安全系数的企业核心数据存储服务。您可以通过自定义过期天数的方法删除数据,避免误删带来的损害,还可以将数据跨地域存储,防止一些不可抗因素导致的数据丢失。数据保险箱支持通过控制台、API 等多样化方式快速简单接入,实现海量数据的存储管理。您可以使用数据保险箱对文件数据进行上传、下载,最终实现数据的安全存储和提取。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档