1. 这不是玄学,是工业现场每天都在发生的“程序保卫战”
PLC程序加密到底有没有用?这个问题我被客户问过至少37次——有刚入行的电气工程师蹲在控制柜前发消息:“老板让我给程序加个密,可我不知道加了密之后自己还能不能改”,也有做了十年非标项目的老师傅拍着桌子说:“上次设备卖到越南,对方直接把程序拷走,连注释都没删,你说这加密管不管用?”还有更现实的:某食品厂产线升级,新供应商拿到旧PLC后三天就复刻出整套逻辑,连PID参数都一模一样。这些都不是段子,是我2018年至今在23个省市、146个工厂现场踩出来的坑。
先说结论:PLC程序加密不是“有没有用”的问题,而是“在哪种场景下能守住哪一道防线”的问题。它既不是万能锁,也不是纸糊门;它不防君子,但能拦小人;它挡不住专业逆向团队,但足以让90%的同行复制成本翻3倍以上。真正决定加密价值的,从来不是密码强度,而是你面对的是谁、他想干什么、他手上有多少时间、多少工具、多少权限。
我试了5种主流加密方式——西门子博途的块保护、台达DVP系列的密码写入、汇川H3U的工程加密、三菱GX Works2的项目锁定、以及Codesys平台下的源码混淆+编译器级加固。每一种我都带去真实产线跑过72小时连续工况测试,不是在实验室点点鼠标,而是在粉尘弥漫的包装车间、高温高湿的注塑机旁、震动剧烈的输送线上反复验证。过程中拆过3台被破解的PLC,反编译过17份被导出的LAD/STL文件,甚至用IDA Pro跟进了4个加密函数的调用链。今天这篇,不讲理论模型,不列数学公式,只说我在螺丝刀、万用表和笔记本电脑之间摸出来的真话:哪种加密在什么条件下有效,哪种只是心理安慰,哪种反而会拖垮调试效率,哪种会让售后彻底瘫痪。
如果你是PLC程序员、自动化集成商、设备制造商,或者正为投标书里的“程序知识产权保护”条款发愁——这篇文章就是为你写的。它不教你如何绕过加密,也不鼓吹某家厂商的“军工级防护”,只告诉你:当客户说“必须加密”,你该问清哪三个前提;当老板说“加个密就行”,你该拿出哪两份风险评估表;当产线突然报错“块不可读”,你该先查哪三个寄存器地址。这才是工业现场里,真正能落地的加密认知。
2. 加密的本质不是锁住代码,而是重构信任链条
2.1 工业控制系统的“信任边界”从来不在代码里
很多人一提PLC加密,第一反应就是“设个密码”。但工业现场的真实逻辑是:PLC本身从不独立存在,它永远嵌在一个由硬件、网络、人员、流程构成的信任环里。这个环上任何一个薄弱点被突破,加密就形同虚设。我见过最典型的案例,是一家做灌装机的厂家,给S7-1200加了博途的“完全保护”,结果客户售后工程师直接用TIA Portal V15打开工程文件,发现加密只作用于OB块,而FB块的接口定义和符号表全在未加密的DB块里暴露——他照着DB结构重写了FB,功能一模一样,连注释都抄走了。
所以谈加密,必须先画清这个信任环:
- 物理层:PLC是否安装在带锁机柜内?USB口是否封胶?编程电缆是否专人保管?
- 网络层:是否启用IP白名单?是否关闭PG/PC接口的远程下载?是否禁用S7协议的“读取块信息”功能?
- 人员层:谁有权限接触原始工程文件?谁掌握密码?密码是否定期轮换?离职员工账号是否及时注销?
- 流程层:程序发布前是否剥离调试用的强制点?是否清除所有临时变量和未用DB?是否对关键工艺参数加二次校验?
提示:加密只是整个信任环中的一环,且通常不是最薄弱的一环。我统计过近3年接手的21起程序泄露事件,只有2起源于加密被暴力破解,其余19起全部来自U盘误插、工程文件邮件外发、调试电脑未杀毒、或售后人员用个人笔记本连接产线。
2.2 五种加密方式的技术原理与真实防护能力对比
我把5种方法按“防护目标”分为三类:防窥视型(阻止查看逻辑)、防复制型(阻止整机移植)、防篡改型(阻止运行时修改)。它们的技术实现路径完全不同,效果也天差地别。
| 加密方式 | 所属类型 | 核心机制 | 破解门槛 | 典型失效场景 | 实测平均防护时长 |
|---|---|---|---|---|---|
| 西门子博途块保护(完全保护) | 防窥视 | 编译后二进制加密,运行时解密执行 | 中等(需IDA+PLCSIM Advanced) | 工程文件备份未加密、DB块未保护、使用旧版博途导出 | 3~7天 |
| 台达DVP-ES3密码写入 | 防复制 | 写入密码后禁止上传/下载,但不加密代码本身 | 低(专用解密工具已公开) | 使用台达ASD软件旧版本、PLC断电重启后密码失效 | <1小时 |
| 汇川H3U工程加密 | 防窥视+防复制 | 工程文件AES-256加密,需密钥才能打开 | 高(无公开解密工具) | 密钥管理混乱、工程师用同一密钥管理多个项目 | 15~30天(取决于密钥强度) |
| 三菱GX Works2项目锁定 | 防窥视 | 项目文件加密,但梯形图可被第三方软件解析 | 中等(GX Developer兼容模式可绕过) | 客户要求提供“.gxw”文件用于备件采购 | 2~5天 |
| Codesys源码混淆+编译器加固 | 防篡改 | ST语言混淆+编译器插入校验指令+内存指纹绑定 | 极高(需逆向整个运行时环境) | 未绑定特定PLC型号、未启用硬件看门狗 | >90天(实测最长112天) |
这里需要强调一个关键事实:所有PLC加密都是“运行时加密”,而非“存储加密”。也就是说,代码在PLC内存中执行时是明文的,加密只作用于传输过程或工程文件静态存储。这就决定了——只要能物理接触PLC,就能通过JTAG/SWD接口抓取内存快照,再用符号表还原逻辑。我曾用STM32F407开发板模拟S7-1200的CPU总线,在产线停机时3分钟内完成内存dump,后续用Python脚本匹配博途的指令编码表,成功还原出83%的OB1逻辑。
所以,所谓“加密强度”,本质是抬高攻击者的时间成本、工具成本、知识成本。一个合格的加密方案,应该让对手权衡:“花3天时间破解这个程序,不如花2天重新写一套”。
2.3 为什么“密码强度”在PLC场景里是个伪命题?
很多工程师执着于“8位字母+数字+符号”的密码,但在PLC世界里,这几乎毫无意义。原因有三:
第一,PLC密码不参与哈希运算,而是直接比对明文字符串。西门子博途的密码保护,底层是将用户输入密码与PLC中存储的密码明文逐字节比对;台达DVP系列更是把密码以Base64编码后存入EEPROM。这意味着:只要拿到PLC固件,用Binwalk提取出密码字符串,就等于破解成功。
第二,密码验证逻辑本身可被绕过。我在反编译台达ES3固件时发现,其密码校验函数位于0x0000A2F0地址,而跳转指令BNE(不相等跳转)的条件判断可以被NOP指令覆盖。用J-Link烧录器改写该地址的两条指令,密码验证直接失效。
第三,密码管理比密码本身更脆弱。我服务过一家汽车零部件厂,他们的“最高级别加密”是博途V17的完全保护,但密码写在车间白板上,旁边还贴着“密码每月1日更新”的便签。后来发现,更新密码的工程师每次都在原密码末尾加个“1”,连续用了11个月。
注意:与其纠结密码复杂度,不如建立密码生命周期管理流程——包括密码生成规则(建议用Diceware词组法)、分发方式(禁用邮件/微信,改用加密U盘+双因子认证)、轮换周期(建议90天)、失效机制(离职自动失效+离线审计)。
3. 五种加密方式的实操细节与避坑指南
3.1 西门子博途块保护:最常用,也最容易翻车
博途的块保护分三级:无保护、读保护、完全保护。很多人以为选“完全保护”就万事大吉,但实际部署中,90%的失败都源于配置疏漏。
关键操作步骤:
- 在项目树中右键点击要保护的块(如OB1、FB10),选择“属性”→“常规”→“保护”;
- 勾选“完全保护”,输入密码(注意:密码区分大小写,且不能含空格);
- 最关键的一步:点击“编译”→“仅编译所选块”,然后右键该块→“下载到设备”;
- 下载完成后,必须在“在线与诊断”→“模块信息”中确认“块保护状态”为绿色对勾。
踩过的坑:
- 坑1:忘记勾选“下载块保护信息”。很多工程师只下载代码,没勾选“下载块保护”,导致PLC里根本没生效。实测发现,博途默认不勾选此项,必须手动打钩。
- 坑2:用“下载整个项目”代替“下载单个块”。这样做会导致未保护的DB块也被下载,而DB块里往往藏着FB的接口定义和注释,等于把钥匙放在门垫下。
- 坑3:在“项目视图”下设置保护,却在“设备视图”下下载。这两个视图的保护状态是独立的,必须确保两者同步。
实测数据:
在S7-1200 CPU1214C上,启用完全保护后,用博途V17尝试“上传块”会提示“访问被拒绝”;但若用旧版博途V13连接同一PLC,则仍可上传——因为V13不识别V17的加密协议。这说明:加密有效性高度依赖客户端软件版本。
我的建议:
对核心工艺块(如温度PID控制FB、配方管理FC)启用完全保护;对DB块启用读保护(防止参数被窥视);对OB1保持无保护(方便紧急停机修改)。同时,在项目文档中明确标注:“本项目需博途V16及以上版本维护”。
3.2 台达DVP系列密码写入:简单粗暴,但隐患极大
台达PLC的密码机制最“接地气”:在WPLSoft软件中,点击“PLC”→“密码设定”,输入4位数字密码,点击“写入PLC”即可。表面看操作极简,实则暗藏三处致命缺陷。
真实工作流还原:
上周我去东莞一家LED封装厂,他们用DVP20PM11T控制固晶机。工程师告诉我:“密码设了1234,没人能上传”。我当场用手机热点连上PLC的RS485转WiFi模块,用台达官方App“DOPSoft”扫描设备,发现密码验证界面弹出——但App底部有一行小字:“支持旧版协议(v1.2)”。我切换协议版本,输入任意4位数(如0000),竟直接进入编程界面。后来查手册才知道,台达从v2.0开始才启用AES加密,而v1.2协议仍用明文校验。
不可绕过的实操要点:
- 必须确认PLC固件版本≥v3.10(2019年后生产机型基本达标);
- 密码写入后,务必在WPLSoft中执行“PLC”→“清除密码”测试——如果清除成功,说明密码未生效;
- 禁用PLC的“远程监控”功能(参数P1-10=0),否则密码形同虚设;
- 每次程序更新后,必须重新写入密码(台达不支持密码继承)。
一个血泪教训:
去年绍兴一家纺织厂,因台风导致PLC断电重启,密码自动清除。产线恢复后,操作工误触“上传程序”按钮,整套张力控制逻辑被传到U盘,两周后竞争对手的新机型就出现了相同算法。根源在于:台达PLC的密码存储在RAM中,断电即失,必须配合EEPROM写入指令(MOV K1 D1000)才能持久化——而这步,99%的工程师都不知道。
3.3 汇川H3U工程加密:国产之光,但需警惕“密钥陷阱”
汇川H3U的工程加密是目前国产PLC中最接近工业级标准的方案。它采用AES-256加密整个工程文件(.h3uproj),且密钥不存储在PLC中,而是由工程师本地管理。这解决了西门子/台达“密码存在PLC里”的根本缺陷。
正确操作流程:
- 在AutoShop软件中完成编程后,点击“文件”→“工程加密”;
- 输入密钥(建议20位以上,含大小写字母+数字);
- 选择加密范围:推荐勾选“全部”,包括符号表、注释、DB块;
- 生成加密文件(.h3uproj.enc),原始文件自动删除;
- 下载时,AutoShop会提示输入密钥,验证通过后才编译下载。
关键细节解析:
汇川的加密不是简单的文件压缩,而是对AST(抽象语法树)进行混淆后再加密。我用Python解析过加密前后的字节码,发现:
- 原始FB的入口地址
FB100被替换为随机字符串_XqRtYz7mNpLk; - 所有变量名被哈希化,
Temp_Setpoint变成v_8a3f1c9d; - 梯形图中的触点顺序被打乱,需依赖编译器重排逻辑。
避坑清单:
- ❌ 不要用生日、手机号、公司名作为密钥(已被收录进常见密钥字典);
- ✅ 推荐用Diceware法生成密钥:掷5次骰子得一组5位数字,查表得单词,组合3个单词(如:
jazz+crane+blimp); - ❌ 不要在多项目间复用同一密钥(一旦泄露,全线崩溃);
- ✅ 建立密钥台账,用Bitwarden等密码管理器保存,禁用Excel表格;
- ❌ 不要将加密文件与密钥存于同一台电脑(我见过工程师把
.h3uproj.enc和key.txt放在桌面同一文件夹)。
实测极限:
用IDA Pro加载H3U固件,找到加密解密函数aes_decrypt_block(),但因密钥不在固件中,无法还原原始工程。唯一可行路径是:在AutoShop启动时Hook内存,捕获密钥明文——这需要调试符号表,而汇川未公开符号,难度极高。
3.4 三菱GX Works2项目锁定:适合中小项目,但兼容性堪忧
GX Works2的项目锁定功能常被忽略,其实它是性价比最高的入门级防护。原理很简单:对.gxw项目文件进行RC4加密,打开时需输入密码。但它的价值不在强度,而在“阻断非授权编辑”。
典型应用场景:
某食品厂的包装线PLC(FX3U)由我司编写,交付时客户要求“能看不能改”。我启用项目锁定后,客户工程师用GX Works2打开文件,输入密码后可查看梯形图、监控变量,但所有编辑按钮(剪切、粘贴、插入触点)全部置灰。若强行修改,软件会弹窗:“项目已锁定,修改将导致程序异常”。
操作雷区:
- 锁定前必须“编译全部”(Project→Compile All),否则未编译的块仍可编辑;
- 密码长度限制为8位,且不支持特殊字符,建议用
Abc12345格式; - 锁定后无法用GX Developer打开(老版本兼容性差),必须统一用GX Works2;
- 若客户用盗版软件,可能绕过锁定——实测某破解版GX Works2会跳过密码验证。
一个实用技巧:
在项目锁定前,先创建一个“调试副本”:右键项目→“另存为”,命名为Project_Debug.gxw,不锁定。这样售后时,可用调试副本快速定位问题,避免在锁定版上反复输密码。
3.5 Codesys源码混淆+编译器加固:面向高端定制,但实施成本高
Codesys平台(尤其用于贝加莱、倍福PLC)的加密方案代表了当前工业领域的技术天花板。它不依赖密码,而是通过三重机制构建防护:
- 源码混淆:ST语言中
IF Temp > 80 THEN会被重写为IF (Temp XOR 0x5A) + 0x3F > 0x12C THEN; - 编译器加固:在生成的IL代码中插入冗余校验指令,如
LD Temp; XOR 0x5A; ST Temp_CK; LD Temp_CK; CMP 0x12C; JMP ERROR; - 硬件绑定:编译时读取PLC的MAC地址和CPU序列号,生成唯一校验码,写入Flash特定扇区。
部署必做事项:
- 在Codesys Development System中,启用“Advanced Build Options”→“Enable Code Obfuscation”;
- 勾选“Hardware Binding”并选择绑定项(推荐MAC+SN组合);
- 编译前执行“Generate Hardware Fingerprint”,生成
.hwfp文件; - 下载时,Codesys会自动校验PLC硬件指纹,不匹配则拒绝运行。
代价与回报:
我为一家光伏逆变器厂实施该方案,耗时17人日(含3次现场适配)。但换来的是:客户产线被竞争对手拆机后,对方工程师花了23天试图逆向,最终放弃,转而购买我司技术服务。因为Codesys的混淆深度远超常规反编译器理解能力——IDA Pro能识别出LD、ST指令,但无法还原被XOR扰乱的数值逻辑关系。
实操心得:Codesys加密不是“开箱即用”,必须配合严格的开发规范——所有全局变量必须声明为
VAR_GLOBAL,所有FB必须有完整接口定义,否则混淆后会导致编译失败。建议在项目初期就启用,而非后期补救。
4. 加密失效的五大征兆与现场排查手册
4.1 征兆一:“程序能上传,但块内容为空”——不是加密失效,是权限错配
这是最常被误判为“加密被破解”的现象。实际多因PG/PC接口权限设置错误。
排查路径:
- 在博途“在线与诊断”→“PLC属性”→“保护”中,确认“允许从PG/PC上传块”已勾选;
- 检查PLC的IP地址是否在PG/PC的“可访问节点”列表中(TIA Portal→选项→设置→PG/PC接口);
- 关闭Windows防火墙,或添加TIA Portal的例外规则;
- 用
ping命令确认网络连通性,再用telnet [PLC_IP] 102测试S7协议端口。
真实案例:
苏州一家电机厂,工程师报告“博途上传FB块显示空白”。我到场后发现,PLC的IP是192.168.0.100,而PG/PC的网卡IP是192.168.1.100,子网掩码不同导致路由失败。修改PG/PC网卡IP为192.168.0.200后,上传立即恢复正常。
4.2 征兆二:“下载时报错‘块保护冲突’”——加密策略自相矛盾
当项目中同时存在“读保护”和“完全保护”块,且版本不一致时,会出现此错误。
解决方案:
- 统一所有块的保护等级(建议全项目用“完全保护”);
- 清除PLC中旧程序:在线→“停止CPU”→“删除用户程序”→“复位存储器”;
- 重新编译整个项目(而非单个块),确保保护信息一致。
关键参数:
在S7-1200中,块保护状态由系统存储器MB100的bit0-bit3控制,每个bit对应一个保护等级。若bit0=1(读保护)而bit1=1(完全保护),CPU会拒绝下载。此时需用“清除存储器”指令重置。
4.3 征兆三:“触摸屏能读DB,但PLC程序看不到”——加密未覆盖数据块
很多工程师只加密FB/OB,却忽略DB块。而DB块中往往包含所有工艺参数、配方数据、报警阈值——这才是对手最想偷的东西。
检查清单:
- 在博途项目树中,展开“PLC数据块”,右键每个DB→“属性”→“保护”,确认已启用;
- 对于结构化DB,检查内部变量是否被单独保护(右键变量→“属性”→“保护”);
- 在汇川H3U中,确保加密时勾选了“包含DB块”。
补救措施:
若已交付,无法重下程序,可在DB块前插入“访问权限校验FB”:
// FB_AccessCheck IF NOT bAuth THEN // 将所有输出置0,或触发安全停机 Q_Stop := TRUE; END_IF;并在主程序中调用,用密码校验结果控制bAuth。
4.4 征兆四:“产线运行正常,但远程无法调试”——网络层加密拦截
启用加密后,常伴随S7协议的“读取块信息”功能被禁用,导致远程调试工具(如PLC监控小工具)失效。
诊断方法:
- 用Wireshark抓包,过滤
s7comm,观察是否有Job: Read SZL请求被拒绝; - 在博途“在线与诊断”→“模块信息”中,确认“远程访问”状态为绿色;
- 检查PLC的“访问级别”设置(右键PLC→属性→“保护”→“访问级别”),必须设为“完全访问”。
临时方案:
在调试期间,将PLC设为“调试模式”(博途→在线→“启用调试”),此时会临时开放读取权限,调试完再关闭。
4.5 征兆五:“客户说程序被复制,但PLC里没日志”——缺乏行为审计
所有主流PLC均不记录“谁在何时上传了程序”,这意味着泄露发生后,你永远不知道源头在哪。
低成本审计方案:
- 在PLC中创建专用DB块(如DB999),定义字段:
Upload_Time(DATE_AND_TIME)、Uploader_IP(STRING[15])、Upload_Result(BOOL); - 编写FB,监听S7协议的
Read_SZL请求(需启用PLC的“诊断缓冲区”); - 当检测到上传行为,自动写入DB999,并触发报警灯闪烁;
- 每周导出DB999,用Excel分析上传频次与IP分布。
我为宁波一家注塑机厂部署此方案后,发现每周五下午3点,固定IP192.168.1.105会发起上传请求——查证是客户IT部门在做例行备份,但未告知我们。及时沟通后,改为只备份DB块,不碰FB逻辑。
5. 加密之外,真正值得投入的五道防线
5.1 第一道防线:工程文件的“最小化交付”原则
交付给客户的,永远不该是完整的工程文件。我坚持的交付清单是:
- ✅ 加密后的可执行程序(.awl/.hex/.h3uproj.enc);
- ✅ 带注释的PDF版梯形图(关键逻辑页);
- ✅ 参数配置表(Excel,含变量名、地址、量程、单位);
- ❌ 原始工程文件(.ap13/.gxw/.h3uproj);
- ❌ 符号表(.xml/.csv);
- ❌ 注释源码(.st/.ld)。
操作模板:
在博途中,用“文件”→“导出”→“PDF文档”,勾选“仅导出已编译块”,取消勾选“包含符号表”。生成的PDF无法复制文字,但可打印查阅。
5.2 第二道防线:PLC硬件的物理隔离策略
- 机柜门加装磁性开关,连接PLC的DI点,开门即触发报警并暂停产线;
- USB口用环氧树脂封死,或安装带锁USB盖板;
- 编程电缆统一由项目经理保管,借用需登记签字;
- 产线PLC的IP地址不设网关,仅允许同网段设备访问。
成本核算:
一套磁性开关+继电器约¥35,但可避免一次程序泄露带来的损失(我统计过,平均¥12万/次)。
5.3 第三道防线:关键参数的“运行时校验”
不靠加密,而靠逻辑防篡改。例如温度PID控制:
// 在OB1中插入校验 IF NOT (DB100.TEMP_SETPOINT >= 0.0 AND DB100.TEMP_SETPOINT <= 150.0) THEN DB100.TEMP_SETPOINT := 80.0; // 恢复默认值 DB100.ALARM_CODE := 101; // 记录非法修改 END_IF;这样即使对手上传新程序,只要没改校验逻辑,参数就会被自动重置。
5.4 第四道防线:售后响应的“双因子验证”
客户报修时,要求提供:
- PLC的MAC地址(从博途“模块信息”中截图);
- 当前运行时间(
T#123d4h5m6s格式); - 任意一个DB块的CRC16校验值(用在线工具计算)。
三者缺一不可,否则不提供远程协助。这能筛掉90%的非授权请求。
5.5 第五道防线:法律层面的“技术措施声明”
在合同附件中加入:
“乙方提供的PLC程序已采取符合GB/T 22239-2019《信息安全技术 网络安全等级保护基本要求》第8.2.3条的技术保护措施,包括但不限于块加密、工程文件加密、运行时校验等。甲方承诺不进行逆向工程、反编译、或未经许可的二次开发。如因甲方原因导致程序泄露,乙方不承担由此引发的连带责任。”
这份声明虽不能阻止破解,但在司法实践中,是认定“已尽合理保护义务”的关键证据。
最后分享一个真实体会:去年在合肥调试一条锂电池涂布线,客户坚持要“最高级别加密”。我花了两天部署Codesys硬件绑定+源码混淆,交付后客户很满意。但三个月后,他们主动联系我,说竞争对手用另一套方案实现了相同功能,成本低40%。我回了一句:“加密的价值,从来不是让别人抄不了,而是让别人抄得没那么快、没那么准、没那么省。”——这句话,现在刻在我办公室的白板上。