了解最新技术文章
PLC(可编程逻辑控制器)是专门用于控制具有实时处理要求的工业系统的计算机。它们接受传感器提供的输入并为执行器生成输出。作为可编程设备,它们执行用户提供的软件,因此容易受到某些类别的软件攻击。最广为人知的演示是 Stuxnet 恶意软件,其最终目标是控制、损坏和摧毁铀浓缩厂中的离心机阵列。事实证明,对恶意 PLC 有效负载的分析是一条漫长而乏味的道路2,到目前为止,与这些系统相关的工具和知识相对于 x86 或 arm 等广为人知的架构而言仍然有限。
我们试图通过为 JEB Pro 提供 S7 分析模块来弥补这一差距。本文展示了如何使用它们来获取、分析、反汇编和反编译旨在在 Siemens Simatic S7-300 和 S7-400 设备上运行的 PLC 程序块,这是用于操作工业过程的非常流行的 PLC 系列。
在本文档的其余部分,术语PLC、S7或S7 PLC可互换使用,指代 S7-300 或 S7-400 PLC 设备。此 JEB 扩展不支持 S7 产品线中较新的设备,即 S7-1200 和 S7-1500,因此此处不予考虑。
用于编程S7 PLC的官方IDE称为Step 7。步骤 7 可以按原样使用,也可以作为更大的软件套件全集成自动化(TIA) 的一部分使用。
PLC程序由块组成,例如数据块、功能块和组织块。在本文档中,术语程序可以理解为(集合)块。
程序从Programming Station下载到PLC ,即运行 Step 7 编辑器的基于 Windows 的计算机。当从 PLC 检索程序时,将其上传到编程站。
汇编语言STL(语句列表)及其对应的字节码MC7有时可以互换使用。
最后,名称Simatic、Step 7和Totally Integrated Automation是 Siemens AG(“Siemens”)的商标。
本节简要介绍了 S7 程序是什么、它们的结构以及从逆向工程的角度需要了解的较低级别的详细信息。
S7 PLC 使用 Step 7 或 TIA 的 Step 7 进行编程(TIA 是对最新的 S7 设备进行编程所需的平台),在 Windows 计算机上运行的 IDE 称为编程设备。程序编写完成后,可以下载到物理 PLC 或仿真程序(例如 PLCSIM,第 7 步的一部分)。
PLC 程序是块的集合。块有一个类型(数据、代码等)和一个数字。
数据块:
如果用户数据块由所有代码共享,则称为DB ,如果属于代码块,则称为DI
系统数据块命名为SDB
代码块,也称为逻辑块:
主 OB 是程序的主入口点 OB1。它由固件重复执行。
其他 OB 可以在中断发生、异常发生、定时器关闭等情况下被编程和调用。
组织块 ( OB ) 是程序入口点,由固件调用
功能块 ( FB ) 和系统功能块 ( SFB ) 是在提供的数据块上运行的例程,称为背景数据块 ( DI )
函数 ( FC ) 和系统函数 ( SFC ) 是不需要数据块来操作的例程
FB 和 FC 之间的区别很微妙。任何 FB 都可以编写为等效于 FC,反之亦然。它们作为一种简单的方法来区分按原样工作的函数,如 C 例程 (FC),以及处理伪封装属性集合的函数,如 C++ 类方法 (FB)。
编写 PLC 代码有多种方法。程序员可以选择编写梯形图(LAD)或功能块图(FBD);复杂的过程可以用语句列表 (STL) 或高级类 Pascal 语言 (SCL) 更好地表达。无论源语言如何,程序都编译为 MC7 字节码,其规范不公开。
一段 MC7 字节码与一些元数据(创作信息、标志等)和块的接口一起打包在一个块中。数据块的接口是块定义本身,一种结构类型。逻辑块的接口是它的一组输入、输出、局部变量,以及在 FB 情况下的静态变量,或在 FC 情况下的返回值。
可以使用多种方法对 PLC 进行编程,例如:
梯形逻辑 (LAD)
功能块图 (FBD)
类汇编语句列表 (STL)
结构化控制语言(SCL,一种高级的类 Pascal 语言)
存在其他方法
第 7 步将所有源代码编译为 MC7 字节码,MC7 字节码将由运行在 PLC 上的虚拟机翻译和执行。
在 S7-400 3之前, STL 的文档相对完善。但是,在撰写本文时,二进制规范尚未公开。4
MC7 指令映射 STL 语句,有几个值得注意的例外(例如,在 FC/SFC 的情况下,STL 的 CALL 被转换为 UC/CC,并带有额外的代码来准备地址寄存器指针、打开数据块、在 Locals 存储区设置参数打电话等)。
MC7字节码的执行环境如下:
内存区域:
一个特殊的区域V引用了调用者方法的本地内存,即如果函数f1调用了函数f2,f2中的V就是f1的L
数字输入,称为I(0 到 65536 个可寻址字节)
数字输出,称为Q(0 到 65536 个可寻址字节)
全局内存,称为M(0 到 65536 个可寻址字节)
本地内存,称为L(0 到 65536 个可寻址字节)
通过 DB1 寄存器共享数据块字节,称为DB
通过 DB2 寄存器的背景数据块字节,称为DI
定时器,称为T(256 个可寻址 16 位定时器)
计数器,称为C(256 个可寻址 16 位计数器)
寄存器:
地址寄存器保存一个 MC7 4 字节指针(参见 MC7 类型部分)。指针的区域部分可以被忽略(用于区域内部访问),或者可以被使用(用于区域交叉访问)
两个 32 位地址寄存器 ( AR1/AR2 )
两个或四个 32 位累加器(ACCU1/ACCU2、ACCU3/ACCU4可选)
两个数据块寄存器,不可直接访问
FC: First-Check:如果为0,表示要执行的布尔指令是要执行的逻辑运算序列中的第一个(“逻辑运算串”)
RLO:逻辑运算结果:保存最后执行的位逻辑运算的结果
STA:状态:当前布尔地址的值
OR:确定二元与和二元或的组合方式
操作系统:溢出存储:OV 位的副本
OV:溢出:在溢出时由整数/浮点指令设置
CC0/CC1:条件代码:由算术指令和比较指令更新(有关如何设置和使用 CC0/CC1 的详细信息,请参见算术和分支指令)
BR:二进制结果:可用于存储 RLO(通过 SAVE);由系统功能 (SFC/SFB) 用作成功 (1)/错误 (0) 指示器
PC由程序内分支指令修改(JU/JL/JC/…)
程序计数器PC , 不可直接访问
一个 16 位状态字寄存器(仅使用低 9 位),从 #0 到 #8:
JEB 的 MC7 插件镜像执行环境,并添加了几个合成(人工)寄存器,以帮助 MC7 代码表示和代码转换为反编译器的 IR。处理器详细信息可以在 GUI 客户端中检查(菜单Native,处理程序Processor Registers)。
熟悉 STL 是 PLC 逆向工程师需要熟悉的主题。但是,一般 STL 编程的完整而详细的指南超出了本文档的范围。具体的 STL 指令将根据需要进行讨论。
这些指令分为以下几类:
位逻辑:not/and/or/xor/and-not/or-not/xor-not、RLO 访问等。
词逻辑:和/或/异或词
整数运算:add/sub/mul/div/mod,在 16 位或 32 位整数上
移位/旋转:不言自明
浮动操作:iee754 fp32 操作
比较:比较并设置 CC0/CC1
转换:int 到 float、float 到 int、有符号扩展等。
数据块:打开数据块作为共享/实例等。
加载/传输:读取和写入 accus 和 address regs
accumulator : 特定的累加器指令
逻辑控制:跳跃、无条件或基于 CC0/CC1
程序控制:对 FB/FC/SFB/SFC 的子程序调用
counter/timer : 操作定时器和计数器