资讯动态

PLC动态加密计时授权码设计:破解设备验收拖款难题

发布时间:2026/10/21 10:21:46 来源:尧图企业网站定制
设备调试完成、触摸屏上面所有数值都正常就是没人来签验收单钱压在对方账户里一个月、两个月、三个月。干工控的应该都懂这种憋屈程序写得再漂亮收不到尾款就是零。去年我在一个单机设备项目里被客户拖了将近四个月现场人员天天在设备天天能跑可对方一句“再观察观察”就打发了。后来我去掉了一开始那种“到某一天就停机”的土办法换成了一套西门子PLC上的动态加密计时逻辑这才真正把对方拉回谈判桌。今天把这套东西完整拆开讲一遍包括为什么静态日期没用、动态加密计时怎么设计、博途里怎么落地、授权码怎么生成以及甲方最常见的绕法和对应防守。准备做设备远程授权、被验收拖款折磨的同行可以照着这个思路搭一套。1. 为什么我不建议直接“写死一个到期日期”1.1 我吃过静态到期日的亏最朴素的做法是在PLC里写死一个日期比如“2025年3月31日零点停机”。第一版我确实这么干的在OB1里读系统时间到了日期就把自动流程的M区位置位设备只能手动点动。结果没用现场操作工把触摸屏里的系统时间改到了2099年PLC一上电程序一对比发现“还没到日期”锁机逻辑根本没机会触发。后来客户更直接在HMI的校准界面里把PLC的RTC时间也调了等于我这套逻辑成了摆设。这事的本质是静态到期日把系统时钟当成了唯一可信源而PLC和触摸屏的时间权限如果没控制好甲方工程师完全可以顺手改掉。更尴尬的是如果设备出厂前忘记刷新RTC锂电池没电导致时间回退软件可能把自己误锁还得售后跑现场解锁白白浪费差旅费。1.2 动态加密计时解决的核心问题我后来总结真正靠谱的“收款保护锁”要解决三件事时间改不了、程序抄不走、授权码不可复制。这三件事单靠一个日历日期做不到必须让“锁机条件”本身变成一个多维度的计算值。具体来说动态加密计时不再依赖“系统时间到没到某一天”这一个条件而是同时参考三类信号自然日周期、累计通电时长、累计运行状态再叠加一个带随机盐的授权码体系。所谓“动态”有两个层次第一锁机阈值不是固定常量而是由设备序列号、解锁阶段、运行时长等多个参数实时算出来的第二每次解锁拿到的授权码都不一样同一台设备同一个阶段两次生成的授权码也可能不同甲方不能靠截获一次授权码就永久破解。1.3 这套方案适合什么场景先说适用范围免得有人拿去做不该做的事。动态加密计时最典型的应用场景是非标自动化设备、单机设备、或者已经发货但验收款被长期拖延的项目。设备本身已经交给客户使用你保留的是一个“不带破坏性的授权校验机制”目的是促成商务谈判不是让设备报废。不建议用在安全关键设备、医疗/消防类设备、或者任何对连续运行有强监管要求的场合。这类设备一旦因为商务纠纷触发停机造成安全或合规问题责任可能远超尾款本身。做技术保护之前先评估设备类别这是底线。2. 动态加密计时的三层设计系统时间、运行时长和授权码2.1 时间锚点自然日怎么读才不会被假时钟骗自然日周期仍然要保留但要有防篡改的设计。S7-1200/1500读取系统时间用博途指令RD_SYS_T输出类型是DTL结构体里面有year、month、day、hour这些字段。PLC的RTC由内部电池维持断电也不会重置这是它的优势。但问题是很多触摸屏都有“设置系统时间”的页面操作工或甲方电工完全可以从HMI改到PLC。所以我在HMI组态里会把“设置时间”这个权限从操作员组里移除只保留给管理员组而且管理员密码不交付给现场只有我方售后才知道。如果是老设备没权限分组至少在HMI脚本里加一道校验只允许日期在当前时间前后7天内调整超过这个范围就拒绝写入。2.2 运行时长为什么比系统时间更靠谱如果只有自然日客户把时间往回调锁机日就永远到不了。所以必须有第二条腿累计通电时长或者更进一步累计“设备实际运行时长”。累计通电时长在S7-1200里很容易做用循环中断OB10设置成1秒执行一次每次给一个保持性DB的DINT变量加1同时存一份到掉电保持区。考虑到PLC断电期间不计时还需要在OB100启动时把“上次开机累计值”读出来这样就算客户停机两三个月再开机累计值也不会归零。更好的做法是叠加设备运行状态。比如一台包装机可以在触摸屏或PLC里用一个M区信号表示“自动模式正在执行”这个信号为TRUE的每一秒也累加。为什么要这一步因为有些客户很鸡贼不停机让设备空转但就是不跑产品让“通电时长”涨得很慢。如果锁机条件只看通电时长他可以一直开着电拖一两个月再谈。有了“实际运行时长”维度空转也算一部分而且空转和通电是并行计时两条线都到红线才算结束。2.3 授权码在整体架构里的位置不能只有计时还得有“开锁”机制。每台设备出厂时程序里写入一个设备序列号例如“SIM2025-0021”这个序列号不来自CPU模块的物理ID而是我们自己的程序DB里的一组字符串下载程序时烧进去。每次授权会经历这几个阶段阶段0设备通电首次运行进入倒计时试用期比如30个自然日或200个运行小时哪个先到算哪个。阶段1倒计时结束前7天HMI会一直显示“剩余授权时间”让客户有预期。阶段2倒计时耗尽自动流程被禁止启动手动模式保留。阶段3客户把HMI上显示的8位数字授权码发给我们我们拿到设备序列号、当前阶段号、要解锁的天数用后台工具生成一个新授权码客户输入后校验通过阶段号1倒计时重新开始。注意关键点授权码是“设备序列号 当前阶段 新解锁天数 随机盐”算出来的不是固定密码。客户就算拿到这一阶段的授权码也只能解锁对应阶段下个阶段还得等新码。而且授权码里不包含明文天数PLC端要自行解算。2.4 整体判定逻辑整个判断可以用一个状态机描述。为避免被单点篡改我把锁定标志分散到三个地方一个在受保护DB里一个在OB100启动时计算出的保持M区一个在用于HMI显示的普通DB里。主程序启动自动流程前同时检查三处标志只要有一处不通过自动循环使能就无法置位。伪代码如下// 伪代码示意 IF (stage 0) THEN lock : FALSE; ELSE CASE current_state OF 0: // 正常 IF natural_days_used auth_days THEN lock : TRUE; IF run_hours_used auth_hours THEN lock : TRUE; 1: // 预警 IF remain_days 7 THEN hmi_alarm : 剩余授权时间不足7天; 2: // 锁定 allow_auto : FALSE; allow_manual : TRUE; hmi_text : 自动模式已暂停输入授权码继续运行; END_CASE; END_IF;这种设计下即使甲方很熟悉PLC想把锁机时间清零也必须同时处理自然日、运行时长、授权阶段校验和分散位的状态复杂度比改一个日期高得多。3. 博途里的落地实现从读取系统时间到锁机动作3.1 推荐硬件和软件组合我用的硬件组合是S7-1200 CPU 1214C加KTP700触摸屏软件是TIA Portal V15.1。S7-1500当然也能跑而且算力和安全功能更强但S7-1200已经完全够用。如果客户现场有上位机或服务器可以把授权状态同步给上位机但没必要为了锁机而引入复杂上位机。硬件选型给个表格方便对照项目推荐配置说明PLCS7-1200 1214C DC/DC/DC带10KB保持DB足够存放计时数据和授权状态触摸屏KTP700 Basic支持管理员/操作员权限可隐藏时间设置存储介质原装存储卡卡内只放程序不放源码和密码工程软件TIA Portal V15.1及以上过低版本在SCL指令支持上有差异3.2 读取系统时间的正确姿势在TIA中新建FC或FB后在指令树里找到“日期和时间”类别拖入RD_SYS_T。这个指令需要分配一个实例DB输出引脚DTL_OUT连接到DTL类型变量。下面是一个简化代码片段// 读取系统时间 RD_SYS_T_DB(REQ : TRUE, DTL_OUT #dtNow); // 把日期转成整形便于比较 #today : INT_TO_DINT(#dtNow.year) * 10000 INT_TO_DINT(#dtNow.month) * 100 INT_TO_DINT(#dtNow.day);为什么做成YYYYMMDD整数因为SCL里比较DTL结构体不方便转成整数后直接和“基准日期”比较大小即可。基准日期可以是PLC首次上电时写入的“开始计时日”也可以是出厂程序里的常量。3.3 累计运行时长的两种实现第一种用OB10循环中断设置执行周期为1秒。在里面写#runSeconds : #runSeconds 1; // 换算成小时取整后单独显示 #runHours : #runSeconds / 3600;这个DB必须勾选“保持性”否则断电清零。保持性DB在TIA中的设置方法右键DB属性把“保持性”选择为“保持”并定义断电保持区域大小。S7-1200默认最多可以分配2KB保持存储器注意全局DB保持设置要写在DB属性里别漏。第二种用TIME_TCK读取CPU系统时钟的运行时间。这个指令返回从CPU启动以来的毫秒值做变量累加会更稳定但断电就会丢掉。我的做法是OB100里用TIME_TCK把上一次断电前的保持累计值加上本次上电以来的值一起作为总运行时长这样既不用每秒任务也不怕断电。3.4 锁机动作怎么设计才干净这是整个方案里最容易做错的地方。锁机不是“咔一下切断所有输出”而是只限制自动循环的启动。具体做法是在OB1里把“自动模式允许”这个中间变量M10.0作为自动流程的开门狗M10.0 TRUE时自动流程正常执行M10.0 FALSE时所有自动步停止报警文本提示“请联系设备服务商获取授权码”紧急停止、手动点动、安全回路、温度监控这些功能一律不受锁机影响。这样做的好处是即使客户恶意不付款设备也不会突然停机造成危险但也没法正常批量生产。生产停了客户才有压力坐下来聊验收。3.5 几个容易写错的细节读DTL字段时要注意DTL内部的year是INT类型而month和day也都是INT直接用INT_TO_DINT转换即可SCL里不能用DINT直接赋值给INT否则编译过不去。HMI输入授权码的字符串变量长度建议设置成10位PLC端使用SCL的FIND指令去掉首尾空格再做强制长度校验。如果不校验客户在输入框里复制粘贴时可能会带入换行符导致解密比对失败。我在现场调试时遇到过三次都是授权码本身正确但字符串长度被空格撑爆了后来加了一个TRIM逻辑才解决。4. 授权码生成端离线给客户开锁也要保证对方算不出来4.1 思路重活留在PC端PLC端只做查表和校验PLC的算力做不了高强度的非对称加密所以不需要在PLC里跑AES、SHA这些。合理分工是PC端/手机端生成授权码可以用任何强算法PLC端只做“查表CRC32比对截断码”这样S7-1200也能流畅跑。授码体系的核心是校验值AuthCode由设备序列号、当前阶段、解锁天数、随机盐四部分组成。其中解锁天数不是明文写在授权码里的而是用“校验码后三位”间接编码的。4.2 生成器端的算法示例我用Python写了一个简单的7位数字授权码生成器方便理解。工程上建议用公司内部后台但原理一样import zlib def gen_auth_code(device_sn, stage, days, salt): raw f{device_sn}|{stage}|{days}|{salt} crc zlib.crc32(raw.encode()) 0x7fffffff code_part crc % 1000000 days_part days return f{code_part:06d}{days_part:03d} # 示例 print(gen_auth_code(SIM2025-0021, 3, 30, W8k2P))输出的授权码是9位数字PLC端收到后先取后三位得到解锁天数再拼上约定的盐值重算CRC32最后比对前6位。如果一致就授权成功。这里的W8k2P是固定的盐值如果担心被甲方暴力穷举就定期更换固件里的盐值。4.3 PLC端校验代码骨架PLC接收授权码后用SCL解析字符串提取后三位并重组字符串再用查表CRC32计算比对。核心判断是这样// 伪代码示意 IF LEN(#sInput) 9 THEN #bValid : FALSE; ELSE // 提取后三位 #iDays : STRING_TO_INT(LEFT(#sInput, 3)); // 本示例用后三位实际项目自行设计 // 根据序列号阶段天数盐重算 #strRaw : CONCAT(#sDeviceSN, |); ...省略字符串拼接... #iNewCRC : FC_CRC32(#strRaw); #iCodePart : #iNewCRC MOD 1000000; IF DINT_TO_STRING(#iCodePart) MID(#sInput, 1, 6) THEN #bValid : TRUE; END_IF; END_IF;最终项目里我建议把第7-9位作为“天数编码校验位”上面是一个演示结构真正商用时要防止客户逆向。比如CRC32只保留16位、再增加一段查表置换这样对方即使拿到固件也不容易直接还原算法。不过话说回来工程设备的破解难度远超普通软件甲方一般不会为此专门养一个逆向工程师。4.4 后台管理要留痕授权码不能随手发每个授权记录都要留档。我用一个Excel都可以管理字段如下设备编号序列号当前阶段授权天数授权码日期备注DT-01SIM2025-00213304352980302025-06-12验收谈判前临时授权DT-02SIM2025-00221151892340152025-06-11首次授权有了这个表售后人员不会乱也能在商务会上拿出“每次授权都有记录”的证据让客户明白不是设备坏了是验收卡住了。5. 甲方会怎么破解我踩过的和听说过的绕法5.1 最常规的改系统时间这是甲方电工最本能的操作。他们会打开HMI设置页把PLC时钟改到很久以前或者直接断电一段时间再上电。应对手段就是运行时长维度。就算你把系统时间改回2024年运行时长累计还在一秒一秒涨倒计时仍然会耗尽。我还遇到过一个特殊情况某现场的操作工把PLC时间改错改到了2099年导致本来还有20天才锁机的设备变成了“已过期”触发了我们的锁定。这个能把人气笑但也说明判断逻辑里必须留一个容错——比如允许“当前日期出现异常向后跳变”时以运行时长为准而不是直接锁机以免误杀。5.2 下载空程序覆盖/换CPU理论上客户可以买一套新PLC把原来的程序下载到新硬件里因为授权DB里的序列号是在DB里不是CPU物理参数。换CPU后序列号没变锁机逻辑照样跑。真正想换整套PLC的客户很少因为设备所有逻辑都在原程序里他换掉等于把正常的设备线路重新抄一遍风险极大。更常见的是尝试在线下载空程序把设备弄停再让技术人员去现场“修复”。遇到这种情况我只能说别怕锁机部分和主程序是同一个工程他清空程序等于整台设备都停了这是破坏不是绕过客户自己也不敢轻易这么干。5.3 在线监控修改锁定标志位懂行的人会在线连上PLC找到自动流程的使能位比如M10.0强制置位让自动流程绕过锁机判断。这是我最在意的破解路径因此专门做了分散校验自动流程使能位M10.0由FB_LicenseCheck输出驱动同时OB10每个扫描周期都重新计算“自动允许”条件关键锁定标志分散在受保护DB的三个不同地址主程序中有一个一致性校验三个地址不一致时强制锁定并报警。其中一个地址放在DB的保护区域就算甲方通过监控表修改了普通DB的某个位启动OB时一致性校验会把这个错误检测出来自动流程仍然无法启动。5.4 反编译/提取存储卡程序TIA打开受保护程序需要密码而且PLC属性里可以启用“禁止上传”功能。S7-1200的固件升级后允许组态工程师设置“不能从设备上传程序”甲方即使插上编程线也只能看到在线诊断信息提取不出完整源码。存储卡选原装程序卡卡里放的是加密后的工程不会直接暴露SCL源码。5.5 我的最大教训把厂家自己锁死了这套方案在第一台设备出厂前调试时我忘了先切到“测试模式”结果设备在厂内跑了三天验证生产节拍正常倒计时早就归零第四天去试机时自动流程无法启动车间主任以为程序坏了。后来我在授权逻辑里加了一个“维护模式”开关只有通过加密的维护密码才能进入调试阶段不计时出厂前再把维护模式关掉并清零运行计时。这个细节很关键不然你会被自己的锁机方案锁两次。6. 什么时候能用、什么时候别碰合规边界和商务操作建议6.1 边界一保留手动和安全功能无论客户欠款多少设备的安全保护功能绝不能作为锁机对象。急停、门锁开关、电机过载、安全光幕、紧急泄压这些回路永远不应该进入锁机判断。锁机只作用在自动流程的使能端手动点动和单步操作保留。客户如果确实需要把设备停在安全位置再谈判那是合理诉求不该被技术手段拦截。还有一点不要在锁机后把触摸屏锁定得完全不可操作至少要留给操作员一个可以联系售后的界面和一段友好提示。锁机本身已经够让对方难受了没必要把用户体验做成敌对模式。6.2 边界二合同和技术协议怎么写我建议这类保护机制在设备交付前就写进技术协议但措辞要中性不要直接用“锁机”两个字而是写“设备内置软件授权时效校验功能质保期内不影响使用质保期外需联系供应商获取授权延续”。这样既不影响设备正常销售也为后续收款留了一道闸门。协议样本可以这样参考设备运行软件包含授权时效校验机制设备在无有效授权码情况下自动流程将暂停手动运行不受影响。授权码由供应商远程提供用于确认设备服务状态。当然具体条款建议让法务或懂合同的人把关这里只是技术视角的提醒不构成法律意见。6.3 边界三留缓冲不做法外操作最危险的错误用法是凌晨三点突然锁机、设备正在高速运行直接急停。这不是保护自己的权益是把自身置于安全风险中。正确做法是剩余7天提示剩余3天提升报警等级剩余0天禁止自动流程启动但当前正在运行的一批任务允许完成或停在当前位置。我在实际项目里用的是“禁止启动”而非“强制停止”因为设备如果正在运行中被强行打断可能会导致产品报废或人员风险。“不启动”永远比“强制停”安全。6.4 心态上把它当商务工具而不是技术炫技我自己的体会是动态加密计时真正的作用不是“困住客户”而是把双方拉回谈判桌。客户其实也知道原理大致如此但没法轻易绕过去所以只能选择正面解决验收条款。整套方案最大的价值在于你有底气说出“设备不是不转是你需要先跟我谈清楚验收”而不是低声下气地一遍遍催促付款。如果你要在项目里加类似功能我最想叮嘱的还是那句话永远保留一个绝对安全的手动模式和一个能联系到你的界面别把自己推到客户的对立面。设备是客户的资产但方案是你应得的回报。技术和商务之间差的往往就是这一层分寸。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑