0.开场吐槽。
xxx到此一游。
写此帖子,心态一样,搞技术的都爱炫耀,身怕老板同事不知道。
其实经历的多了,这些都是忌讳。
步科在我没用过也没听过是什么之前,总跟科比关联起来。
后来有一年,有几个老设备,客户找上门说要改造升级,我才在网络找些资料了解。
设备控制,屏是步科的触摸屏,触摸屏连接的是台达的PLC。
两者连上电脑一上传,好家伙,都给禁止了,这是要重写的节奏啊?
台达的PLC倒是有见过也用过,破解早也有研究过,小意思,禁止上传捣鼓一个硬件分分钟钟的事。
小日本的东西,或是台湾的产品,这些工程师在设置硬件保护功能时都不太了解中国人智商,
总觉得自己技术牛的一逼或是啥原因,总爱留一手(比如留个超级密码),也不知是为好售后服务还是啥,
结果在中国市场,不管是触摸屏也好,还是PLC也摆,产品全线沦丧,一 一被破解。
中国人但到是很了解中国人,国产的品牌在保护方面基本都是把后路做死。
比如禁止上传,你尝试几次密码错误,直接硬件锁死无法用,寄厂维修。
比如禁止反编译,直接将全部工程文件,图片啥的删除,仅留下几KB的二进制文件给你下载到硬件。
比如加密的,算法直接用老美军用的,算法不可逆,结果不可逆,只能一个个输入密码试,
密码错误超过几次,直接提示都不弹,就把你硬件锁死。
1.步科是什么?
步科是什么?网络上一查,步科也就是一个中国的公司。
它自己给自己取了个英文名叫Kinco。
可以找到官网,说明还是挺正规的。
看公司图片,也就一栋楼,占地不大,给人印象就是一个小老板开的。
网上介绍说早期是台湾威纶的代理商,后面自己独立出来做了硬件研发与销售。
其触摸屏编程软件在使用上都跟威纶的相似, 我后面自己用了后,
软件灰头土脸的,XP时代的产品。
控件属性倒是有威纶影子,我对威纶倒是挺熟悉,在软件设计使用上,这点可以对比对比。
熟悉威纶,反过来再使用步科,可以很快上手。
下面是官网上对它自己的介绍:
上海布克自动化有限公司专注于工业自动化设备控制核心部件,
和工业物联网/互联网软硬件的研发、生产、销售及相关技术服务,为客户提供设备自动化控制,
数字化工厂和工业互联网解决方案,是中国为数不多的机器自动化和工厂智能解决方案供应商之一。
公司自动化设备控制核心部件主要包括工业人机界面、伺服系统、步进系统、可编程控制器、变频器等,
广泛应用于物流设备、机器人、包装设备、食品设备、服装设备、医疗设备等,
环保设备、轨道交通设备等自动化设备行业。
工业物联网/互联网软硬件产品主要包括现场智能终端、网关、数据采集器、SaaS软件、数据中心等,
主要用于食品、服装等行业的数字化化工厂建设和产销协同制造。
本想多找些步科触摸屏的相关资料,比如编程软件,用户手册,视频教程,通讯线制作,编程手册啥的。
发现很少,基本都是没用信息,编程软件也只在官网找到,旧一点的也看不见。
看到一些帖子也是网友早些年发的。
比如让我眼睛一亮的标题:
步科触摸屏如何破解-CSDN论坛(回复:2019年3月2日 抓时序,看数据)
步科文件反编译pkg反编译步科文件解密步.
INCO解密【plc解密吧】 - 百度贴吧.
步科触摸屏解密软件_步科破解,步科触摸屏破解软件-互联网
有没有步科MT4300C触摸屏密码锁破解软件啊?跪求! - 百度知道.
步科触摸屏解密软件_步科触摸屏解密-互联网工具类资源-CSD.
点击进去,
是提问的帖子基本没人回,或是回复无解。
是破解软件下载站的,下载下来,不是报毒就是不能用,
想想也是,这年头谁都唯利是图,做啥事都要成本,做公益都得饿死。
是文章的,直接空空如也,都是黄牛发的广告,
什么西门子可破啊,三菱可破啊的标题,唯独没找到步科相关信息,
看来只有靠自己花时间来研究了。
2.先熟悉步科工程目录。
开始编程或破解研究,先建立一个Kinco触摸屏的程序,了解一下程序文件夹结构。
我打开步科触摸屏编程软件HMIWare v2.5。
步科触摸屏编程软件HMIWare v2.5
再新建立一个项目程序:gkbc8。
组态进步科触摸屏SZ7E,三菱PLC可编程控制器FX2N,串口通讯线。
组态好后,直接编译查看有没错误。
编译没问题后打开刚才创建的程序文件夹。
科触摸屏程序文件夹介绍
会看到很多文件与文件夹。
gkbc8.wpj是步科的工程文件,双击它可以打开触摸屏程序进行编辑。
gkbc8.pkg是编译后生成的二进制机器码,可直接下载到触摸屏使用或离线模拟。
gkbc8.bak,PLCGEDefaultProperties.xml是一些编译或保存时的中间过程临时文件,没用。
vg文件夹放置矢量类型的图片用,
temp文件夹备份整个工程文件用,这是怕你程序误操作,给你留一颗后悔药。
tar文件夹编译过程中生成的临时二进制文件,没用。
image文件夹放置位图类型的图片用。
HMI0文件夹一个触摸屏工程对应,放置屏工程文件,
打开还会发现有
HMI0.lg日志文件,
HMI0.whe屏程序文件。
文件夹macro放置此屏的宏相关文件。
其实上面乱七八糟的文件,通过双击工程文件gkbc8.wpj,
就可以按规则打开进行程序设计。
3.开始研究步科加密破解。
0>步科触摸屏加密破解。
步科用过一段时间后,发现可以通过加密保护的地方很多,
有些做的真不错,有些就如虚设一样,咱们做设备写程序的,建议都用上就对了。
首先是工程文件加密,也就是对上边那个文件gkbc8.wpj进行加密保护。
打开编程软件菜单,文件,工程密码保护,可以进行设置。
如下图:
步科触摸屏工程密码保护
步科工程文件加密搞的很好,
密码忘记了,一点后悔机会都不会给你。
如上图的注意提示:
密码为空,则不加密,请牢记密码,密码一旦丢失,工程将无法打开!!
刚开始我也不以为然,按以往破解其他品牌的经验,密码加密了,你自己软件在解密时总要用吧。
于是我进一步研究编程软件是如何使用密码的。
0.可能打开加密的文件时,先从文件读取密码,再与用户输入的密码对比?
那我来偷窥一个,你进行比对时,我就瞄一眼,就一眼。
测试发现它是将两密码对相同内容如:工控编程吧网址是gkbc8.com专注工控领域编程与破解进行加密后,
将加密的结果以字节为单位逐一对比,完全一致才表示密码相同,我干。
1.那密码对比结果可以拿来做文章吧?
密码错误结果为0,我给你搞成1,那编程软件不就当密码正确了么。
结果我一试,编程软件直接奔溃,汗。
其实想想也对。
用一个规则保存好的文件,你用其他乱七八糟的规则打开,那结果肯定随机。
2.既然简单的不行,那你研究你算法总可以了吧?
你算法是将数据+密码1+1=2,那我2-1=1不就得出原始的被加密的工程文件gkbc8.wpj了。
于是乎我花了个把星期研究算法,发现好复杂啊,好像也没法反推算算法啊。
加密过程总的步骤是这样的:
定义一个常量int KeyLenMulBlckLen=0xff,表示循环生成加密用数据的次数。
定义16个长度为0xff的常量数组,因为密码最长为16位,用于生成对应一位密码。
然后再获取用户输入的密码,循环迭代生成加密用的数据,进行文件的间接加密。
因为用户输入的密码是随机,所以生成的解密用的数据也是随机,
循环这么多次,它爹妈都不认识了根本没法反向,
真够恶心。
其实算法与WINRAR压缩文件,WORD文档相似,都是代码都是公开的。
开源的加密库都可以下载来研究。
下面是我几个星期的研究结果,真是浪费时间。
-
- v2 = (unsigned __int16 *)this;
- if ( ~*(_BYTE *)(Archivea2 + 0x18) & 1 )
- {
- v3 = *(_WORD *)this;
- v4 = *(_DWORD *)(Archivea2 + 0x28) + 2;
- if ( v4 > *(_DWORD *)(Archivea2 + 0x2C) )
- CArchive::Flush((CArchive *)Archivea2);
- v5 = *(_WORD **)(Archivea2 + 0x28);
- v84 = v4;
- *(_DWORD *)&v85[1] = &v84;
- *v5 = v3;
- *(_DWORD *)(Archivea2 + 40) += 2;
- ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
- &v84,
- v2 + 2);
- v100 = -1;
- WriteStringAndLength_45EBE0((CArchive *)Archivea2);
- *(_DWORD *)&v85[1] = &v84;
- ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
- &v84,
- v2 + 4);
- v100 = -1;
- WriteStringAndLength_45EBE0((CArchive *)Archivea2);
- *(_DWORD *)&v85[1] = &v84;
- ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
- &v84,
- v2 + 6);
- v100 = -1;
- WriteStringAndLength_45EBE0((CArchive *)Archivea2);
- v6 = *((_DWORD *)v2 + 5);
- if ( !(~*(_BYTE *)(Archivea2 + 24) & 1) )
- {
- v7 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v7);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 4) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_DWORD **)(Archivea2 + 40) = v6;
- v8 = *(_DWORD *)(Archivea2 + 24);
- *(_DWORD *)(Archivea2 + 40) += 4;
- v9 = *((_BYTE *)v2 + 24);
- if ( !(~(_BYTE)v8 & 1) )
- {
- v10 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v10);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 1) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- v11 = *(_BYTE **)(Archivea2 + 40);
- v84 = 80;
- *v11 = v9;
- ++*(_DWORD *)(Archivea2 + 40);
- CArchive::Write((CArchive *)Archivea2, v2 + 14, v84);
- v12 = v2[54];
- if ( !(~*(_BYTE *)(Archivea2 + 24) & 1) )
- {
- v13 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v13);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 2) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_WORD **)(Archivea2 + 40) = v12;
- v14 = *(_DWORD *)(Archivea2 + 24);
- *(_DWORD *)(Archivea2 + 40) += 2;
- v15 = v2[55];
- if ( !(~(_BYTE)v14 & 1) )
- {
- v16 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v16);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 2) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_WORD **)(Archivea2 + 40) = v15;
- v17 = *(_DWORD *)(Archivea2 + 24);
- *(_DWORD *)(Archivea2 + 40) += 2;
- v18 = v2[56];
- if ( !(~(_BYTE)v17 & 1) )
- {
- v19 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v19);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 2) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_WORD **)(Archivea2 + 40) = v18;
- *(_DWORD *)(Archivea2 + 40) += 2;
- sub_7BEF50((int)(v2 + 58), (CArchive *)Archivea2);
- v20 = *((_BYTE *)v2 + 1912);
- if ( !(~*(_BYTE *)(Archivea2 + 24) & 1) )
- {
- v21 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v21);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 1) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_BYTE **)(Archivea2 + 40) = v20;
- v22 = *(_DWORD *)(Archivea2 + 24);
- ++*(_DWORD *)(Archivea2 + 40);
- v23 = *((_BYTE *)v2 + 1913);
- if ( !(~(_BYTE)v22 & 1) )
- {
- v24 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v24);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 1) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_BYTE **)(Archivea2 + 40) = v23;
- v25 = *(_DWORD *)(Archivea2 + 24);
- ++*(_DWORD *)(Archivea2 + 40);
- v26 = *((_BYTE *)v2 + 1914);
- if ( !(~(_BYTE)v25 & 1) )
- {
- v27 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v27);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 1) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_BYTE **)(Archivea2 + 40) = v26 != 0;
- v28 = *(_DWORD *)(Archivea2 + 24);
- ++*(_DWORD *)(Archivea2 + 40);
- v29 = v2[958];
- v30 = ~v28;
- if ( !(v30 & 1) )
- {
- v31 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v31);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 2) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- v32 = *(unsigned __int16 **)(Archivea2 + 40);
- v84 = v30;
- *(_DWORD *)&v85[1] = &v84;
- *v32 = v29;
- *(_DWORD *)(Archivea2 + 40) += 2;
- ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
- &v84,
- v2 + 960);
- v100 = -1;
- WriteStringAndLength_45EBE0((CArchive *)Archivea2);
- v33 = *((_BYTE *)v2 + 1924);
- if ( !(~*(_BYTE *)(Archivea2 + 24) & 1) )
- {
- v34 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v34);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 1) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- v35 = *(bool **)(Archivea2 + 40);
- *v35 = v33 != 0;
- v36 = *(_DWORD *)(Archivea2 + 24);
- ++*(_DWORD *)(Archivea2 + 40);
- v37 = *((_DWORD *)v2 + 482);
- if ( !(~(_BYTE)v36 & 1) )
- {
- v38 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v38);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 4) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- v39 = *(_DWORD **)(Archivea2 + 40);
- v84 = (int)v35;
- *(_DWORD *)&v85[1] = &v84;
- *v39 = v37;
- *(_DWORD *)(Archivea2 + 40) += 4;
- ATL::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>::CStringT<wchar_t,StrTraitMFC_DLL<wchar_t,ATL::ChTraitsCRT<wchar_t>>>(
- &v84,
- v2 + 8);
- v100 = -1;
- WriteStringAndLength_45EBE0((CArchive *)Archivea2);
- v40 = *((_DWORD *)v2 + 483);
- if ( !(~*(_BYTE *)(Archivea2 + 24) & 1) )
- {
- v41 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v41);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 4) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_DWORD **)(Archivea2 + 40) = v40;
- v42 = *(_DWORD *)(Archivea2 + 24);
- *(_DWORD *)(Archivea2 + 40) += 4;
- v43 = *((_DWORD *)v2 + 484);
- if ( !(~(_BYTE)v42 & 1) )
- {
- v44 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v44);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 4) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_DWORD **)(Archivea2 + 40) = v43;
- v45 = *(_DWORD *)(Archivea2 + 24);
- *(_DWORD *)(Archivea2 + 40) += 4;
- v46 = *((_DWORD *)v2 + 485);
- if ( !(~(_BYTE)v45 & 1) )
- {
- v47 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v47);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 4) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_DWORD **)(Archivea2 + 40) = v46;
- v48 = *(_DWORD *)(Archivea2 + 24);
- *(_DWORD *)(Archivea2 + 40) += 4;
- v49 = *((_DWORD *)v2 + 486);
- if ( !(~(_BYTE)v48 & 1) )
- {
- v50 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v50);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 4) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_DWORD **)(Archivea2 + 40) = v49;
- v51 = *(_DWORD *)(Archivea2 + 24);
- *(_DWORD *)(Archivea2 + 40) += 4;
- v52 = *((_BYTE *)v2 + 1948);
- if ( !(~(_BYTE)v51 & 1) )
- {
- v53 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v53);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 1) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_BYTE **)(Archivea2 + 40) = v52 != 0;
- v54 = *(_DWORD *)(Archivea2 + 24);
- ++*(_DWORD *)(Archivea2 + 40);
- v55 = *((_DWORD *)v2 + 488);
- if ( !(~(_BYTE)v54 & 1) )
- {
- v56 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v56);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 4) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_DWORD **)(Archivea2 + 40) = v55;
- v57 = *(_DWORD *)(Archivea2 + 24);
- *(_DWORD *)(Archivea2 + 40) += 4;
- v58 = *((_BYTE *)v2 + 1956);
- if ( !(~(_BYTE)v57 & 1) )
- {
- v59 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v59);
- }
- if ( (unsigned int)(*(_DWORD *)(Archivea2 + 40) + 1) > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_BYTE **)(Archivea2 + 40) = v58 != 0;
- v60 = *(_DWORD *)(Archivea2 + 24);
- ++*(_DWORD *)(Archivea2 + 40);
- v61 = *((_DWORD *)v2 + 490);
- if ( !(~(_BYTE)v60 & 1) )
- {
- v62 = (const wchar_t *)ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(Archivea2 + 20);
- AfxThrowArchiveException(2, v62);
- }
- result = *(_DWORD *)(Archivea2 + 40) + 4;
- if ( (unsigned int)result > *(_DWORD *)(Archivea2 + 44) )
- CArchive::Flush((CArchive *)Archivea2);
- **(_DWORD **)(Archivea2 + 40) = v61;
- *(_DWORD *)(Archivea2 + 40) += 4;
- }
- else
- {
- Read2Byte_405E20(Archivea2, this);
- ReadString_45EC50(Archivea2, (int)(v2 + 2));
- ReadString_45EC50(Archivea2, (int)(v2 + 4));
- ReadString_45EC50(Archivea2, (int)(v2 + 6));
- ReadOneDWORD_4082D0(Archivea2, (int)(v2 + 10));
- ReadOneByte_405DD0(Archivea2, (int)(v2 + 12));
- if ( *v2 >= 6u )
- {
- if ( *v2 >= 0xDu )
- v84 = 80;
- else
- v84 = 32;
- CArchive::Read((CArchive *)Archivea2, v2 + 14, v84);
- }
- else
- {
- CArchive::Read((CArchive *)Archivea2, &v86, 0x20u);
- v84 = *((_DWORD *)v2 + 5);
- v64 = ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(v2 + 6);
- v65 = ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(v2 + 4);
- v66 = GetPlcType(v65, v64, v84);
- if ( v66 >= 0 && (unsigned __int16)GetLinkType(v66) )
- {
- v67 = v88;
- v68 = v87;
- *((_DWORD *)v2 + 14) = v86;
- v69 = v89;
- *((_BYTE *)v2 + 34) = v67;
- v70 = v91;
- *((_BYTE *)v2 + 35) = v69;
- v71 = v92;
- v2[27] = v68;
- *((_BYTE *)v2 + 36) = v90;
- v2[16] = v70;
- *((_DWORD *)v2 + 7) = v71;
- }
- else
- {
- v72 = v86;
- v73 = v93;
- v2[17] = v87;
- v74 = v88;
- v2[16] = v72;
- LOBYTE(v72) = v94;
- *((_BYTE *)v2 + 36) = v74;
- *(unsigned __int16 *)((char *)v2 + 37) = v92;
- v75 = v95;
- *((_BYTE *)v2 + 40) = v72;
- LOBYTE(v72) = v97;
- *((_BYTE *)v2 + 39) = v73;
- v76 = v96;
- *(_DWORD *)((char *)v2 + 41) = v75;
- LOBYTE(v75) = v98;
- *(_DWORD *)((char *)v2 + 45) = v76;
- LOBYTE(v76) = v99;
- *((_BYTE *)v2 + 49) = v72;
- v77 = HIWORD(v86);
- *((_BYTE *)v2 + 50) = v75;
- *((_BYTE *)v2 + 51) = v76;
- *((_DWORD *)v2 + 7) = v77;
- }
- }
- result = *v2;
- if ( (_WORD)result )
- {
- if ( (unsigned __int16)result < 5u )
- {
- ReadOneByte_405DD0(Archivea2, (int)v85);
- v84 = (int)(v2 + 55);
- v2[54] = (unsigned __int8)v85[0];
- Read2Byte_405E20(Archivea2, v84);
- ReadOneByte_405DD0(Archivea2, (int)v85);
- result = (unsigned __int8)v85[0];
- v2[56] = (unsigned __int8)v85[0];
- }
- else
- {
- Read2Byte_405E20(Archivea2, (int)(v2 + 54));
- Read2Byte_405E20(Archivea2, (int)(v2 + 55));
- result = (int)Read2Byte_405E20(Archivea2, (int)(v2 + 56));
- }
- }
- if ( *v2 > 1u )
- result = sub_7BEF50((int)(v2 + 58), (CArchive *)Archivea2);
- if ( *v2 > 2u )
- {
- ReadOneByte_405DD0(Archivea2, (int)(v2 + 956));
- ReadOneByte_405DD0(Archivea2, (int)v2 + 1913);
- ReadOneByteAsBool_408320(Archivea2, (int)(v2 + 957));
- Read2Byte_405E20(Archivea2, (int)(v2 + 958));
- ReadString_45EC50(Archivea2, (int)(v2 + 960));
- }
- if ( *v2 > 3u )
- result = (int)ReadOneByteAsBool_408320(Archivea2, (int)(v2 + 962));
- if ( *v2 > 6u )
- result = (int)ReadOneDWORD_4082D0(Archivea2, (int)(v2 + 964));
- if ( *v2 < 9u )
- {
- v84 = *((_DWORD *)v2 + 5);
- v78 = ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(v2 + 6);
- v79 = ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(v2 + 4);
- result = GetPlcType(v79, v78, v84);
- if ( result >= 0 && (result = (unsigned __int16)GetLinkType(result), (_WORD)result) )
- {
- LOWORD(result) = 100 * *((unsigned __int8 *)v2 + 34);
- v2[25] = result;
- }
- else
- {
- v2[29] = 100 * *((unsigned __int8 *)v2 + 34);
- }
- }
- if ( *v2 >= 0xAu )
- ReadString_45EC50(Archivea2, (int)(v2 + 8));
- if ( *v2 >= 0xBu )
- {
- ReadOneDWORD_4082D0(Archivea2, (int)(v2 + 966));
- ReadOneDWORD_4082D0(Archivea2, (int)(v2 + 968));
- ReadOneDWORD_4082D0(Archivea2, (int)(v2 + 970));
- ReadOneDWORD_4082D0(Archivea2, (int)(v2 + 972));
- v84 = *((_DWORD *)v2 + 5);
- v80 = ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(v2 + 6);
- v81 = ATL::CSimpleStringT<wchar_t,1>::operator wchar_t const *(v2 + 4);
- v82 = GetPlcType(v81, v80, v84);
- v83 = v82;
- result = BlkSizesProgrammable(v82);
- if ( (_BYTE)result )
- {
- SetMaxBitBlkSize(v83, *((_DWORD *)v2 + 483) / 16);
- result = SetMaxWordBlkSize(v83, v2[968]);
- }
- }
- if ( *v2 >= 0xCu )
- {
- ReadOneByteAsBool_408320(Archivea2, (int)(v2 + 974));
- ReadDWORD_40DB30(Archivea2, (int)(v2 + 976));
- ReadOneByteAsBool_408320(Archivea2, (int)(v2 + 978));
- result = (int)ReadDWORD_40DB30(Archivea2, (int)(v2 + 980));
- }
- *v2 = 13;
- }
复制代码
其实研究过程中我是有发现一些加密算法相关的关键字,
加之也买有一些密码学资料,
一搜索,这个算法还有个学名AES。
高级加密标准(英语:Advanced Encryption Standard,缩写:AES),
在密码学中又称Rijndael加密法,是美国联邦政府采用的一种区块加密标准。
这个标准用来替代原先的DES,已经被多方分析且广为全世界所使用。
看算法主要是生成加密用的数据时死循环了N多次,生成的数组也长,数据量大,根本没法反向推出密码。
何况最后还有执行一次,通过用户输入的密码结合解密用中间变量,生成最终文件。
主要还是中间数据量大,我这高配电脑一秒也只能生成几千次。
工程密码任何可输入字符都支持,如中文符号,数字,字母,密码长度16位。
那么密码是什么就有N个可能了,简单拿ASCII表的255个编译来举例,
密码就有255的16次方种可能,普通计算器没法显示结果,可以网络找些计算器计算。
所以在我们设置好密码后还是建议备份好,
如上图官方提示的,忘记了,工程就真将无法打开了。
那么有人要问了,我公司设备真要改造,技术员,设备厂家都不在了,炸整?
寄给步科官方能给找回么?
官方已经做出提示了,你花钱官方也搞不了啊,人家都解释很清楚了,没有预留超级密码。
你只能根据设备厂家,技术员等能找到的相关信息,或通过社会工程,一个个输入试。
我06年从事工控行业的,使用步科也很长时间,在专业上,效率与技巧会比那些只有兴趣的多些吧。工控相关脑力,苦力活可以找我。
步科触摸屏加密保护方式还是有很多的,都是使用了相同算法,只是密码字符和长度会有所不同。
比如
允许上传的上传密码,
使用下载密码,
允许反编译的反编译密码。
分期付款的每期密码。
32个用户权限的密码。
16个用户等级密码。
这些密码设置都可以在触摸屏组态界面,双击触摸屏打开窗口设置。
站在咱们做设备写程序的同行角度讲,程序设计好,能保护的设置都建议设置上。
密码一律使用最长,数字+字母+字符+其他,再做好密码备份。
为什么?因为想盗取你劳动成果的人都舍得请技术破解。
触摸屏组态界面设置密码
1>步科触摸屏反编译破解。
步科触摸屏程序设计好后是要进行反编译,生成二进制的机器码下载到触摸屏供硬件使用的。
有很多时候需要再将此二进制文件还原成可二次编辑设计的文件,用编程软件打开编辑。
所以就出现了两个专业名称,编译与反编译。
一般反编译都是从触摸屏读取机器码后才有需要,也就是使用者会有反编译需求,
因为如果程序是自己设计,直接双击工程文件进行编辑就好。
所以反编译加密保护其实意义不大,加上官方搞的密码长度相对工程文件都减半,不建议使用此功能。
步科触摸屏针对反编译提供两种保护方法:
反编译加密保护与禁止反编译保护。
反编译加密保存的设置如上图,组态界面双击触摸屏可弹出屏属性设置窗口,就可进行设置。
和工程文件加密相似,只是密码长度少了很多。
也是建议能够多复杂就多复杂,再设置成禁止反编译多重保护。
我们再继续研究禁止反编译保护方法。
同样在HMI属性设置窗口(也就是上边的图),触摸屏扩展属性设置标签页下,
去除<允许反编译>勾选,完成禁止反编译保护设置。
那么允许反编译勾选与不勾,是不是只是一个标识不同呢?
比如编程软件在执行反编译时,先读取一下这个标识。
标识为1,执行反编译,验证反编译密码,标识为0不执行反编译,提示禁止反编译。
如果是这样,那我搞定这个标识不就好。
于是我验证了一下。
发现真有这个标识,设置禁止反编译了,这个标识真为0。
设置允许反编译,这个标识不为0,但也不为1,而是很大的一个数值。
我继续验证,设置禁止反编译,将这个标识搞成1,假想着让编程软件执行反编译。
不想编程软件直接奔溃。
汗,怎么什么都来个奔溃啊。
按我多年经验,这么大的数据不是随机数,就是地址。
于是我设置允许反编译,又多次编译观察此标识,每次不一样,还真有随机的感觉,但相差不大。
于是我双将禁止反编译的文件,与没有禁止反编译的文件,进行属性对比。
会发现两者文件大小相差几KB。
于是乎我又往工程里添加大量大尺寸图片再对比。
编译后的文件相差不是一点的大啊,
总结萌生:刚才的那标识其实是工程文件数据地址,禁止反编译的PKG文件不带工程文件。
为了验证这一想法。
我特意做了几天的测试。
发再加密反编译保护的,只是将工程文件夹内非临时文件全部统一压缩加密打包。
一并保存于PKG文件中,刚才那标识就是这数据包的地址,地址有略微变化。
因为官方使用了大量随机长度不一干扰数据。
如果禁止反编译了,直接就不打包加密了,数据地址为0。
我给它搞成1了,编程软件不奔溃才怪。
我干,真是简单粗暴又高效。
看来禁止反编译的,破解的机会都不留,
不像三菱的,绕一绕,改一改,编程软件就可正常打开程序。
那么真的需要程序怎么办呢?
那只能找搞技术的了,搞工控编程的老油条。
步科的PKG文件可以在电脑模拟,也可以直接在触摸屏上一页页操作。
然后技术的事就交给搞技术的了。
你一个工控爱好或老板出身,半个月完成,我工控数十载的半个小时搞成。
2>步科触摸屏禁止上传。
要研究禁止上传就得有硬件了。
我手上千百块买的屏没舍得试,是拿公司老旧的,坏了可以寄修,修的理由随意写。
我先是也是网络找帖子看。
有人验证上传密码三次错误会锁机的,我没敢试。
已经有很多人在打广告,接禁止上传的活了。
都是要寄送,折机读取芯片数据几百M,再提取出出程序文件几M;
技术活就不多说了,那些花钱投广告的也不容易。同行相互尊重,工控产品成千上万,总有互补合作的时候。
步科的研究过程就说到这里吧。
对步科总的印象不是很好,使用时内心是抵制的。
编程软件工具栏图标,菜单栏与工作区文字,都没法一眼见其意,
字体太小,界面灰白丑陋。
宏界面都极不友好,宏编程时,你删除一字符,会给你多出一字符,真是无语。
编写程序多了,在使用中你还会发现有大量的图形文字,点阵文字,
以及很多控件如管道等等都搞成图片形式编译到屏,
可以试试管道控件,属性全部打勾,会发现工程文件夹多了三张管道图片。
编译也是直接压缩加密全部工程文件到PKG中,反编译时再解密解压缩。
可以猜测步科触摸屏可能是运算能力不足,然后用存储空间来弥补。
当然这只是猜测。
我也都是看在客户钱的份上才用它一用。
我06年开始从事工控编程,技术活可以找我合作。
什么工业视觉,C语言上位机,PLC,触摸屏编程啥的。
合作共赢。
当前这步科也可以找我编程。
|