吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 7873|回复: 133
上一主题 下一主题
收起左侧

[原创] Modbus模拟工具破解

    [复制链接]
跳转到指定楼层
楼主
iwolf 发表于 2025-2-26 16:48 回帖奖励
本帖最后由 iwolf 于 2025-3-11 16:30 编辑

简介

Modbus是一种通信协议,常用于工业自动化领域,研究工控协议的人应该对此很熟悉。Modbus Poll和Modbus slave分别是Modbus主站模拟器和从站模拟器,提供30天免费试用,然后需注册使用,本教程对其进行注册码破解。从官方网站下载32位安装包,Modbus Poll版本11.0.2,Modbus slave版本9.5.0。教程针对32位程序,64位同理。

Modbus Poll

安装后运行软件,菜单栏没有直接注册的选项,而是当点击连接(按F3)的时候弹出注册窗口,随意输入内容后提示'Error in the registration key',然后弹窗显示剩余试用天数。



直接将Modbus Poll拖入IDA中分析,打开字符串窗口,搜索字符串,双击进入,可以看到sub_4762C0()函数引用此字符串:

查看该函数反编译的伪代码,可知注册码的判断应在函数sub_475DD0()中,其结果可能是0、1、4、5、6,通过switch case语句检查返回值来执行相应流程。根据提示字符串,case 0表示错误的注册码,刚开始随便输入的注册码即为此种情形;case 1表示似乎输入了订单号;case 4表示许可证是用于版本4的,不适用于新版本;case 5表示许可证用于版本5-7;case 6中没有出错的提示字符串,猜测该处为注册成功的流程。

查看函数sub_475DD0()伪代码,其第一个参数是输入的注册码字符串。首先查找字符串中是否含有”WIT”,若有则函数返回1,进入case 1的流程。然后与”TXAUTOSYS”比较,根据字符串提示内容可知”TXAUTOSYS”是有期限的用于教育目的的临时注册码,若临时码在有效期内返回6,否则返回0,分别进入相应的case流程。


sub_475DD0()中第70行的if语句进行一个判断,若sub_477430()返回0,则进入判断体内,只有在这个判断体内变量v4会被赋值为6,即整个函数返回6,注册成功;若sub_477430()返回1,跳出if判断,v4赋值为4,函数返回4,提示注册码用于版本4。我们可以简单看一下函数sub_477430(),看版本4的注册验证逻辑。若注册码长度不是24字节,则函数直接返回0。长度若是24字节,将前20字节进行CRC-16(Modbus)的校验,结果格式化后与注册码最后4字节比较,若相同则函数返回1,否则返回0。可以试验一下,计算20字节的CRC-16(Modbus)结果,将结果拼接在后面作为注册码,最后软件弹出对应的错误提示。

此时,若要成功注册,需sub_477430()返回0(注册码长度不为24即可),重点分析if判断体内71行至181行的内容。首先,注册码长度要不低于31字节,否则验证失败。然后,判断体内后半部分有查找子字符串的操作以及一些函数调用,那么猜测82行处的sub_476B80()函数是需要重点分析的内容。
查看sub_476B80()伪代码,ArgList字段是一个硬编码0x5D028CD,即十进制数97528013(下文中称“密钥”),将该十进制数格式化为字符串,用于与后续变换的注册码进行异或操作。sub_46DB80()函数:若参数为数字,返回相应的0x0~0x9;若参数字符A~F,返回byte(arg)-0x37;否则,返回 0x0。该函数返回结果集为0x0~0xf,即16进制的范围。sub_46DCD0()函数:两个字节的参数进行高低位的合并。sub_46DB80()和sub_46DCD0()调用后的结果是将注册码的字符两两合并成一个字节,如字符串“1234ab”变换为0x12、0x34、0xab这3个字节。注册码合并成字节序列后,逐字节与格式化成字符串的数字(97528013)异或,但是从’7’开始往后循环,即752801397528…。用ByteSequence表示合并后的字节序列,大概可表示成如下形式:

for(int i=0;i<length(ByteSequence-1);i++)    { ByteSequence[i] xor str75280139[i] }

(此代码不严谨,理解意思即可)。此次异或操作只进行ByteSequence长度减1次(ByteSequence的最后一字节是校验位),然后写入到MultiByteStr以及WideCharStr中。MultiByteStr中的逐个字节再依次进行异或,最后得到1字节,此1字节要等于ByteSequence的最后一字节,也即校验位,否则注册码验证出错。然后,MultiByteStr前6字节应是”mbpoll”,否则验证出错。
接着返回到sub_475DD0()中,继续往下看。87行处的::Str是注册码经异或等操作后,除去前6字节"mbpoll"后的字符串。分别对该字符串进行子字符串”\nWIT”和”\n# WIT”的查找,如果都找不到,函数返回5,进入case 5的流程。因此,MultiByteStr中必须包含有”\nWIT”或者”\n# WIT”。所以,最简单的构造就是注册码为32个字符,MultiByteStr[15]是15个字节且前10字节是” mbpoll\nWIT”,剩余字节随机补全。构造出MultiByteStr的15个字节后,这15字节相互异或得到1字节,拆分为两个字符,就是注册码的最后两个字符。MultiByteStr的15字节按位置逐个与字符串”752801397528013”异或,得到的15个字节拆分为30个字符,加上最后用于校验的两个字符,形成的32个字符即为注册码。
经测试,MultiByteStr中除去前6字节的”mbpoll”,剩余字符串是注册名称,该内容显示在“关于”的窗口中。了解验证逻辑后,注册码的构造就比较简单。其中,MultiByteStr = ”mbpoll”+LicenseName(含”\nWIT”或”\n# WIT”子串),MultiByteStr与密钥的对应位置异或,结果拆分,末尾两字符校验,保证长度至少为32,即生成注册码。

Modbus slave

Modbus slave虽然与Modbus Poll的版本不同,但分析后可知其验证逻辑是一样的。不同处是硬编码的密钥和异或后的前7字节是”mbslave”。此处的硬编码密钥为0x1C59D0D,即十进制数29728013,将该十进制数格式化为字符串,用于与后续变换的注册码进行异或操作(同样是延后1位,从数字9开始,” 97280132…”)。

简易代码

以下是简易python代码,提供两个字符串参数,一个是软件名称+注册名称的组合,一个是密钥,输出结果是注册码(缺失最后两字符的校验位)。然后,将第一个参数字符串的每一位进行异或运算得出十六进制值即为校验位。两部分拼接就是最后的注册码。

def xor_strings(s1, s2):
    # 将字符串转换为字节序列
    b1 = s1.encode()
    b2 = s2.encode()

    # 检查长度是否相同
    if len(b1) != len(b2):
        raise ValueError("输入字符串长度必须相同")

    # 逐字节异或并转换为十六进制
    xor_bytes = bytes([a ^ b for a, b in zip(b1, b2)])
    return xor_bytes.hex()

# 示例
s1 = "abc"
s2 = "123"
result = xor_strings(s1, s2)
print(f"异或结果:{result}")

更新补充

当poll软件完成破解后,出现一个严重的bug:poll中的数据无法刷新显示!通过显示流量功能可以看到poll和slave双方能够正常通信,poll中修改的数据可以被slave接收并显示,但是poll读取的数据显示不出来。起初以为是没有正确安装的问题,后来切换回试用注册码或非注册状态都可以正常的运行。所以前面的教程相当于半成品,尽管可以通过修改相关软件注册表项达到长期试用目的,但注册码破解还未全部完成。猜测与数据的读取刷新显示有关,可能软件某处存在校验机制,非正常注册的软件不显示数据。比较繁琐的方法是找到一个合适的暂停点,通过动态调试一步步往前回溯,确定出数据显示的大致流程,比较破解版本和原始版本的执行路径,查看最终导致分歧的点在何处。确定出何种逻辑导致了执行的不同,以及是否可以修改或者跳过这种逻辑。
首先使用IDA动态调试试用版poll。通过猜测及测试,我使用DrawTextW()作为暂停点,在slave中写入数据或修改poll中数据,下条件断点,触发断点后判断是否是自己需要的数据,然后调试确定刷新出数据的代码。例如,在slave中03功能码,地址0处写入数字9,DrawTextW()条件断点为get_wide_byte(get_wide_dword(ESP+8))==0x39,当成功触发且运行正确的情况下,函数返回后的地址为0x0042ed00(针对不同的数据刷新情况,该处地址有所不同,但代码类似)。从而可以确定出下图中的DrawTextW()执行时,参数内容是需要显示出的数据,当前函数执行完返回上层调用后,在BitBlt()执行完,数据将刷新到poll中的界面。(调试时注意线程的自动切换,有一个线程是与slave通信的线程,在不需要时可暂时将其挂起)


通过这个断点,逐步往前回溯,经过漫长的查找,找到一处代码,poll中的数据刷新应该对应于下图中部分,当破解后,0x0047515c代码地址处的取值数据一直是0,若手动修改数据,会显示出来(测试于03功能码)。

分析代码,查看数据来源,断点命中暂停后,双击0x0047515C处word ptr []中的内容,进入到数据区域,在该处下硬件读写断点(F2),查看内存地址中的数据是何时被读写的。因该内存地址是运行中生成,动态变化不固定(比如程序申请的临时变量),所以要先命中0x0047515C断点,然后下内存读写断点,并且假定下次的刷新数据写入到内存的地址是不变的,否则要重新寻找到内存地址。继续运行程序,写入新的数据等待poll刷新,此时程序会中断在硬件断点处,对应于下图中的代码。

寄存器ebx为硬件断点的地址,ax的值即为数据,写入到内存中,ax来源于[edx],根据图中汇编码,edx=0x6191e8+1*0x7e0=0x6199c8,即0x6199c8的内存处是待刷新数据。所以在0x6199c8处下硬件读写断点。当命中断点后,返回上层函数,往前回溯,最终可以确定到下图中的代码。

块中调用的是 _memmove(arg,Src,Size);内存拷贝,参数Src是从slave中接收到的数据,应该是原始的将要刷新显示的数据,Size是总字节数,arg就是地址0x6199c8,后续将从该地址处获取刷新数据并显示在界面上。该地址0x6199c8就是刚才层层回溯分析出来的结果。确定到该处后就可以调试运行破解版,查看执行流程的异同,对比分析。经对比,正常版执行0x 0047FB0F处的基本块,破解版跳过该基本块的执行,导致刷新时取到的数据全是0,也即界面不显示数据。查看IDA的基本块流程图,定位到0x0047FB02处的语句” cmp dword_6391E8, 0”, 正常版的dword_6391E8处的值为0,而破解版dword_6391E8的值为1,导致跳过_memmove()的内存拷贝。此时需要查看dword_6391E8是如何被修改的,双击dword_6391E8来到数据段,使用交叉引用列表,除了刚才的比较语句外,只有一处赋值1的语句,双击进去,是只有一条赋值语句的函数,继续交叉引用列表。在析构处的调用不用管,双击进入另一个函数的调用处。

此时你会惊奇地发现调用处所在的函数就是最开始分析的sub_475DD0(),调用赋值1的函数位于sub_475DD0()的末尾,起初分析时并没有分析到,有一些判断语句会进入到该流程,当时并不清楚逻辑,也就跳过了分析,才导致数据刷新显示的问题。现在就好处理了,可以将sub_47F4A0()函数的赋值1语句改为赋0,这样就能正常刷新数据。直接使用IDA中的修补程序功能,或者其他编辑工具,修改相应位置的字节码。


至此,分析完毕,结果图如下:

最后,本篇仅作技术交流分析。支持使用正版软件。

免费评分

参与人数 27吾爱币 +25 热心值 +22 收起 理由
zklkk + 1 + 1 我很赞同!
wdj500 + 1 + 1 热心回复!
houge52 + 1 + 1 我很赞同!
gsh123china + 1 + 1 谢谢@Thanks!
netle8 + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
blvhop + 1 用心讨论,共获提升!
W5566 + 1 + 1 很实用
Jasonzh + 1 + 1 用心讨论,共获提升!
1071978963 + 1 谢谢@Thanks!
xiazai + 1 我很赞同!
笙若 + 1 + 1 谢谢@Thanks!
zhczf + 1 + 1 我很赞同!
DIYS + 1 + 1 我很赞同!
风子09 + 1 + 1 鼓励转贴优秀软件安全工具和文档!
inix312 + 1 热心回复!
wjd2002 + 1 谢谢@Thanks!
Eric98 + 1 + 1 谢谢@Thanks!
woaipojie2014 + 1 modbuspoll注册成功 无法刷新
YC256743 + 1 热心回复!
stilt6642 + 1 + 1 谢谢@Thanks!
ogli324 + 1 + 1 谢谢@Thanks!
Clarence210 + 1 + 1 我很赞同!
weidechan + 1 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
asky360 + 1 + 1 谢谢@Thanks!
XMax + 1 + 1 我很赞同!
天堂的风 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!
yp17792351859 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
benyazibing 发表于 2025-2-27 21:03
摩尔信使(MThings) 功能会更好用点,可以试试

点评

听说这个也有注册机?  详情 回复 发表于 2025-3-3 08:33

免费评分

参与人数 1吾爱币 +1 热心值 +1 收起 理由
yangliu9420 + 1 + 1 热心回复!

查看全部评分

推荐
zzzznl 发表于 2025-2-28 23:54
分析这个挺好的,基本是技术流,对9-10版的软件依然无法使用,后面的没试过。
modbus Poll这软件,注册成功很容易,但是9-10版注册成功后会导致数据无法正常刷新,基本是用不成的,我之前就没执着于注册,就改了下注册表,去除了30天限制,爆破了里面的计时器,去除了10分钟限制,然后以试用版用着了。
modbus slave倒是没那么多毛病,之前版本注册成功没发现问题。
沙发
动寒川 发表于 2025-2-26 19:03
3#
Sandyang 发表于 2025-2-26 19:57
分析的不错,虽然这个软件针对性强,但思路值得分享心得,点赞.对注册表判断这个方法还是不错的思路
4#
sktao 发表于 2025-2-26 20:17
很不错  这个软件工作中也用过  确实需要方便才好
5#
massagebox 发表于 2025-2-26 20:17
原来有这玩意,自己还费劲白咧写了一个modbus模拟工具....
6#
Orima 发表于 2025-2-26 21:35
感谢分享!矛和盾会同时升级的。。。
7#
Amour778 发表于 2025-2-27 07:55
有趣有趣,甚是有趣,感谢大佬
8#
1sina 发表于 2025-2-27 08:19
有新版本的Modbus Poll version 9.3.1这个好用
9#
不苦小和尚 发表于 2025-2-27 09:25
1sina 发表于 2025-2-27 08:19
有新版本的Modbus Poll version 9.3.1这个好用

在哪里下载
10#
hummel 发表于 2025-2-27 09:56
工控电子正好用的上,感谢分享!
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-3-25 06:02

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表