首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[ffffffff0x] 工控协议:S7COMM协议分析(下)

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

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

前言

在上一篇文章中,我们介绍了S7Comm协议的S7Comm Header和Job 和 Ack_Data机制。本篇文章,我们将继续介绍S7Comm协议的Userdata 协议拓展并结合pcap流量包实际分析。


Userdata 协议拓展

UserData 用于编程/调试、读取 SZL、安全功能、时间设置,循环读取等。

Parameter 结构如下:

  • 1 (3 bytes):参数头(Parameter head);
  • 2 (1 byte):参数长度(Parameter length),它的可能是8字节或12字节;
  • 3 (1 byte):未知定义;
  • 4 (1/2 byte,高位):参数类型(Type);
  • 5 (1/2 byte,Low nibble):功能组(Function group);
  • 6 (1 byte):子功能码(SubFunction);
  • 7 (1 byte):序号。

转换工作模式(Mode-transition 0x0)

当功能组为转换工作模式(Mode-transition)时,请求报文中是没有 Data 部分的,而主要起作用的是子功能码(Subfunction),常见的子功能码有:

  • STOP(0x00):STOP 模式;
  • Warm Restart(0x01):暖启动;
  • RUN(0x02):RUN 模式;
  • Hot Restart(0x03):热启动;
  • HOLD(0x04):HOLD 模式;
  • Cold Restart(0x06):冷启动;
  • RUN_R (H-System redundant)(0x09):H-System 冗余运行;
  • LINK-UP(0x0B):LINK-UP 模式;
  • UPDATE(0x0C):UPDATE 模式。

程序员命令(Programmer commands 0x1)

程序员命令(Programmer commands)主要是工程师用于编程或调试,比如:监视/修改变量、读取修改诊断数据。所有的子功能码有:

  • 请求诊断数据(Request diag data (Type 1)):0x01;
  • 变量表(VarTab):0x02;
  • 读取诊断数据(Read diag data):0x0c;
  • 移除诊断数据(Remove diag data):0x0e;
  • 清除(Erase):0x0f;
  • 强制(Forces):0x10;
  • 请求诊断数据(Request diag data (Type 2)):0x13;

请求报文的结构如下:

  • 1 (1 byte) : 返回码;
  • 2 (1 byte) :Transport sizes,指的数据类型,通常有 bit、byte等;
  • 3 (2 bytes) : 往后的数据长度;
  • 4 (1 byte) : Unknown;
  • 5 (1 byte) : 报文类型(type of data),分为请求(0x14)、响应(0x04);
  • 6 (2 bytes) : Item count和Item data的长度(Byte count);
  • 7 (20bytes) : Unknown;
  • 8 (2bytes) : Item 个数;
  • 9 (varibalebytes) : Item 1;
    • 1 (1 byte) : 区域(Area);
    • 2 (1 byte) : 长度(Length (repetition factor));
    • 3 (2 bytes) : 模块号(DB number);
    • 4 (2 bytes) : 偏移地址(Startaddress)。
  • n (varibalebytes) : Item n;

响应报文结构如下:

  • 1 (1 byte) : 返回码;
  • 2 (1 byte) :数据类型(Transport sizes),通常有 bit、byte 等;
  • 3 (2 bytes) : 往后的数据长度;
  • 4 (1 byte) : Unknown;
  • 5 (1 byte) : 报文类型(type of data),分为请求(0x14)、响应(0x04);
  • 6 (2 bytes) : Item count 和 Item data 的长度(Byte count);
  • 7 (4bytes) : Unknown;
  • 8 (2bytes) : Item 个数;
  • 9 (varibalebytes) : Item 1;
  • 1 (1 byte) : 返回码;
  • 2 (1 byte) :数据类型(Transport sizes),通常有 bit、byte 等;
  • 3 (2 bytes) : 往后的数据长度;
  • 4 (varibale bytes) : Data。
  • n (varibalebytes) : Item n;

块功能(Block functions 0x3)

块功能(Block functions)是用于操作块,所有的子功能码有:

  • 0x01:列举所有块(List blocks);
  • 0x02:列举块类型(List blocks of type);
  • 0x03:读取块的信息(Get block info)。

CPU功能(CPU functions 0x4)

CPU 功能(CPU functions)是用于操作块,所有的子功能码有:

  • 0x01:读系统状态列表(Read SZL);
  • 0x02:消息服务(Message service);
  • 0x03:诊断消息(Diagnostic message),PLC 的诊断消息;
  • 0x05:ALARM_8 显示(ALARM_8 indication), PLC 使用ALARM_8 SFBs 来显示报警消息;
  • 0x06:NOTIFY 显示(NOTIFY indication),PLC 使用 NOTIFY SFBs 来显示 NOTIFY 消息;
  • 0x07:ALARM_8 锁定(ALARM_8 lock), 需要通过 HMI/SCADA 锁定ALARM 消息;
  • 0x08:ALARM_8 取消锁定(ALARM_8 unlock), 需要通过 HMI/SCADA 取消锁定 ALARM 消息;
  • 0x09:SCAN 显示(SCAN indication),PLC 显示 SCAN 消息;
  • 0x0b:ALARM 确认(ALARM ack),报警信息已在 HMI/SCADA 中得到确认;
  • 0x0c:ALARM 确认显示(ALARM ack indication), 从 CPU 到 HMI 的确认报警显示;
  • 0x0d:ALARM 锁定显示(ALARM lock indication),从 CPU 到 HMI 的锁定报警显示;
  • 0x0e:ALARM 取消锁定显示(ALARM unlock indication),从 CPU 到 HMI 的取消锁定报警显示;
  • 0x11:ALARM_SQ 显示(ALARM_SQ indication),PLC 使用 ALARM_SQ/ALARM_DQ SFCs 来显示 ALARM 消息;
  • 0x12:ALARM_S 显示(ALARM_S indication),PLC 使用 ALARM_S/ALARM_D SFCs 来显示 ALARM 消息;
  • 0x13:ALARM 查询(ALARM query),HMI/SCADA 查询 ALARM;
  • 0x16:NOTIFY_8 显示(NOTIFY_8 indication)。

子功能码有4种不同的功能类型:

  • 系统状态列表(SZL)

系统状态列表(德语:System-ZustandsListen,英语:System Status Lists)用于描述可编程逻辑控制器的当前状态。SZL的内容只能通过信息功能进行读取,而不能修改。换言之,部分列表是虚拟列表,只在有特殊请求时由CPU的操作系统所创建。

系统状态列表包含下列内容的有关信息:

  • 系统数据
  • CPU 中的模块状态数据
  • 模块的诊断数据
  • 诊断缓冲区

如果要读取系统状态列表,则需要使用参数 SZL-ID 和 INDEX 指定要读取的内容。比如:读取 PLC 的名称,那 SZL-ID 是 W#16#011C,INDEX 是 W#16#0001

每个部分系统状态列表都有一个编号。可以根据编号输出完整的部分列表或摘录。预定义了可能的部分列表摘录,并由一个数字标识。SZL-ID 由部分列表的编号、部分列表摘录的编号和模块等级组成。

请求报文的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (2 bytes):SZL-ID;
  • 5 (2 bytes):SZL-Index;

响应报文 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (2 bytes):SZL-ID,部分列表摘录的 SZL-ID,以 W#16#xy1C 为例,常见的 SZL-ID 如下:
    • W#16#001C:所有组件的标识;
    • W#16#011C:一个组件的标识;
    • W#16#021C:H系统中一个CPU的所有组件的标识;
    • W#16#031C:H系统中所有冗余CPU的一个组件的标识;
    • W#16#0F1C:仅限SSL部分列表报头信息;
  • 5 (2 bytes):SZL-Index,不同的 SZL-ID 那 SZL-Index 不一样。以 W#16#011C 和 W#16#031C 的部分列表摘录的组件标识:
    • W#16#0001:自动化系统的名称;
    • W#16#0002:模块名称;
    • W#16#0003:模块的设备标识;
    • W#16#0004:版权;
    • W#16#0005:模块的序列号;
    • W#16#0007:模块类型名称;
    • W#16#0008:存储卡的序列号在不能插入存储卡的模块中,不提供 数据记录;
    • W#16#0009:CPU 模块的制造商和配置文件;
    • W#16#000A:模块的 OEM ID(仅限 S7-300);
    • W#16#000B:模块的位置指定;
  • 6 (2 bytes):部分列表的长度(SZL partial list length in bytes),不同的 SZL-ID 那长度不一样;
  • 7 (2 bytes):部分列表的个数(SZL partial list count);
  • 8 (34 bytes):SZL 1;
  • n (34 bytes):SZL n;
  • 消息服务(Message service)

消息服务(Message service)主要用于订阅事件,比如:切换工作模式事件、系统诊断事件等。

请求报文的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (1 byte):订阅事件(Subscribed events),常见的事件有:
    • 0x01(MODE):切换工作模式;
    • 0x02(SYS):系统诊断;
    • 0x04(USR):用户定义的诊断消息;
    • 0x08:未知;
    • 0x10:未知;
    • 0x20:未知;
    • 0x40:未知;
    • 0x80(ALM):程序块消息,附加字段中的消息类型;
  • 5 (1 byte):未知(Unknown);
  • 6 (varibale bytes):用户名(Username);

响应报文 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (1 byte):订阅的结果:
  • n (4 bytes):预留(Reserved 2)
  • 诊断消息(Diagnostic message)

诊断消息(Diagnostic message)通常是诊断缓冲区中的数据

请求报文的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (2 bytes):事件 ID(Event ID);
  • 5 (1 byte):优先级(Priority class);
  • 6 (1 byte):OB 编号(OB number);
  • 7 (2 bytes):DatID;
  • 8 (2 bytes):附加信息(Additional information 1);
  • 9 (4 bytes):附加信息(Additional information 2);
  • 10 (8 bytes):时间戳;

每个事件都分配有事件 ID,而事件 ID 的结构如图

那事件 ID 的内容,包括:

  • 0-7位:事件编号(Event Number);
  • 8-11位:识别(IDs),标识符用于区分事件的类型。
  • 12-15位:事件等级(Event Class)
  • 告警消息及告警查询

在这里,把 ALARM_8 显示(0x05)、NOTIFY 显示(0x06)、ALARM_8 锁定(0x07)、ALARM_8 取消锁定(0x08)、SCAN 显示(0x09)、ALARM 确认(0x0b)、ALARM 确认显示(0x0c)、ALARM 锁定显示(0x0d)、ALARM 取消锁定显示(0x0e)、ALARM_SQ 显示(0x11)、ALARM_S 显示(0x12)、ALARM 查询(0x13)、NOTIFY_8 显示(0x16)共13个子功能归纳为告警信息。

  • ALARM 查询(0x13)

请求报文的 Data 结构如下:

* 1 (1 byte) : 返回码(return code);
* 2 (1 byte) : 数据传输大小(Transport sizes);
* 3 (2 bytes) : 以此往后的数据长度;
* 4 (1 byte):功能标识(Function identifier);
* 5 (1 byte):消息对象个数(Number of message objects);
* 6 (varibale byte):Message Object 1;
  * 1 (1 byte):Variable specification;
  * 2 (1 byte):以下规范地址的长度(Length of following address specification);
  * 3 (1 byte):Syntax Id;
  * 4 (1 byte):Unknown;
  * 5 (1 byte):查询类型(Querytype),类型有:
    * 0x01:告警类型(ByAlarmtype);
    * 0x03:事件ID(ByEventID);
    * 0x08:Unknown;
    * 0x09:Unknown;
  * 6 (1 byte):Unknown;
  * …
* …

响应报文 Data 结构如下:

* 1 (1 byte) : 返回码(Return code);
* 2 (1 byte) : 数据传输大小(Transport sizes);
* 3 (2 bytes) : 以此往后的数据长度;
* 4 (1 byte):功能标识(Function identifier);
* 5 (1 byte):消息对象个数(Number of message objects);
* 6 (1 byte) : 数据传输大小(Transport sizes);
* 7 (2 bytes) : 完整数据长度,也就是以此往后的数据长度;
* 8 (varibale byte):Message Object 1;
  * 1 (1 byte) :长度(Length of dataset);
  * 2 (2 bytes):Unknown;
  * 3 (1 byte):告警类型(Alarmtype);
  * 4 (4 bytes):事件ID;
  * 5 (1 byte):Unknown;
  * 6 (1 byte):事件状态(EventState);
  * 7 (1 byte):AckState going;
  * 8 (1 byte):AckState coming;
* …
* n (varibale byte):Message Object n;ALARM 显示、ALARM 锁定/解锁、ALARM 确认、NOTIFY 显示

往往这类报文都是以PUSH的形式存在, Data 结构如下:

* 1 (1 byte) : 返回码(Return code),具体的可参考6.6;
* 2 (1 byte) : 数据传输大小(Transport sizes),具体可参考6.4.2;
* 3 (2 bytes) : 以此往后的数据长度;
* 4 (8 bytes):事件时间,如果subfunc是0x09,那长度为2 bytes;
* 5 (1 byte):功能标识(Function identifier);
* 6 (1 byte):消息对象个数(Number of message objects);
* 7 (varibale byte):Message Object 1;
  * 1 (1 byte):Variable specification;
  * 2 (1 byte):长度(Length of following address specification);
  * 3 (1 byte):Syntax Id,常见的结构标识可参考6.5;
  * 4 (1 byte):相关值数目(Number of associated values);
  * 5 (4 bytes):事件ID;
  * `6 (1 byte):事件状态(EventState);`
  * `7 (1 byte):状态(State);`
  * `8 (1 byte):AckState going;`
  * `9 (1 byte):AckState coming;`
  * `10 (varibale bytes):Associated value 1;`
    * `1 (1 byte) : 返回码(Return code);`
    * `2 (1 byte) : 数据传输大小(Transport sizes);`
    * `3 (2 bytes) : 长度;`
    * `4 (varibale bytes):Data;`
  * `...`
  * `n (varibale bytes):Associated value n;`
* …
* n (varibale byte):Message Object n;

安全功能(Security 0x5)

安全功能(Security)是用于安全设置,比如:设置 PLC 密码,所有的子功能码有:

  • 0x01:PLC 密码(PLC password);
  • 0x02:清除密码(Clear PLC password)。

请求报文的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 数据长度;
  • 4 (varibale byte):Data;

响应报文 Data 结构如下:

  • 1 (1 byte) : 返回码(Return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes);
  • 3 (2 bytes) : 以此往后的数据长度;

PBC BSEND/BRECV 0x6

  • PBC:Programmable Block Functions,可编程块函数,比如:SFB/FB;
  • BSEND/BRCV:到通信伙伴的固定数据块传送。也就是说,在通信伙伴中的接收函数(BRCV)接受该数据之前,数据传送不会结束。

时间功能(Time functions 0x7)

时间功能(Time functions)是用于时间设置,比如设置时间,所有的子功能码有:

  • 0x01:读时间(Read clock);
  • 0x02:设置时间(Set clock);
  • 0x03:读时间(Read clock (following));
  • 0x04:设置时间(Set clock)。

读取时间的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes),通常有 bit、byte 等;
  • 3 (2 bytes) : 以此往后的数据长度。

设置时间的 Data 结构如下:

  • 1 (1 byte) : 返回码(return code);
  • 2 (1 byte) : 数据传输大小(Transport sizes),通常有 bit、byte 等;
  • 3 (2 bytes) : 以此往后的数据长度;
  • 4 (10 bytes):时间戳。流量包分析

这里我们使用snap7本地模拟相应的请求流量,并抓包查看。

块功能(Block functions 0x3)

  • 列举所有块(List blocks)
    • 请求
  • 响应
  • 列举块类型(List blocks of type)
    • 请求
  • 响应
  • 读取模块的信息(Get block info)
    • 请求

CPU功能(CPU functions 0x4)

  • 系统状态列表(SZL)
    • 请求
  • 响应

安全功能(Security 0x5)

  • PLC密码(PLC password)
  • 请求

Data 是 64 67 02 06 62 65 17 10

* 第1位:0x64 ^ 0x55 = 0x31,则值是1;
* 第2位:0x67 ^ 0x55 = 0x32,则值是2;
* 第3位:0x02 ^ 0x55 ^ 0x64 = 0x33,则值是3;
* 第4位:0x06 ^ 0x55 ^ 0x67 = 0x34,则值是4;
* 第5位:0x62 ^ 0x55 ^ 0x02 = 0x35,则值是5;
* 第6位:0x65 ^ 0x55 ^ 0x06 = 0x36,则值是6;
* 第7位:0x17 ^ 0x55 ^ 0x62 = 0x20,则值是 (空);
* 第8位:0x10 ^ 0x55 ^ 0x65 = 0x20,则值是 (空);
  • 响应

时间功能(Time functions 0x7)

  • 读时间(Read clock);
    • 请求
  • 响应

总结

本文,我们分析了S7Comm协议的Userdata 协议拓展部分。通过与pcap流量包的结合分析,可以更加直观的了解其原理和交互过程,学习S7Comm协议对于工控安全非常重要,在之后的文章里,我们还将继续学习modbus和Ethernet/IP协议相关内容。


本文作者 r0fus0d

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • Userdata 协议拓展
  • 总结
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档