一次练手实战破解某字典--注册机篇
一次练手实战破解某字典--注册机篇
文章紧接上一篇爆破篇
之前的分析锁定了,对用户名和密码的验证就在这个区域中(先不管我的注释)
PS:
通过之前对sub4019d0这个函数的分析可以得到的是将之前存储在注册表中的用户名
取到了v1+1474里面,密码放到了v1+1424里面
为什么是v1+偏移量呢?
因为这玩意儿实际上是c++写的,里面有一个类,类的成员变量有用来存储用户名和密码的
第一个strcmp()里面将v1+1474与v1+1424进行比较。
第二个strcmp()里面将v1+1444与String进行比较
其实就是将用户名与V1+1424进行比较,将密码与String进行比较验证
所以可以得出:
v1+1424是软件内部计算出来的一个要与用户的输入的用户名进行比对的用户名(这里把它叫做真用户名)
跟踪真用户名
静态分析
在锁定的范围里面,与V1+1424有关的函数有sub401A90,先静态分析看下
干,又有一个没接触过的API函数,上网查一查,这有一篇参考
其实就是获取磁盘的序列号到v1+1424里面,然后后续的一系列操作是对这个序列号变形操作,然后得到用户名。
为了进一步确认,直接上调试吧。
在IDA里面看下调用这个函数的地址:

动态分析
然后OD断下来:
执行完毕后生成了一串38904353的字符串,至于栈中其他的信息是?
是我破解之后,注册成功了之后
这个字符串就是打开软件自动生成的用户名。
也就是说真用户就是软件未注册时显示的那个申请号。
其实与v1+1424有关的还有一个函数是:sub_42DD16
为什么说 真用户名就是软件未注册时显示的那个申请号呢?
就是因为这个函数。
简单分析下:
这个函数可能没学过c++的朋友就看不懂了,这个函数程序里面的一个类的成员函数,成员函数里面可以访问类的成员(对这个程序来说),怎么实现访问的呢?就是靠this指针。
这个函数最关键的是lpString就是我们传入的v1+1424。
然后if的分支使用了this指针偏移量的方式访问了一个函数。对我们逆向没用,有兴趣的朋友可以下个断点跟一下你就知道了。
另外一个分支是:将v1+1424的内容设置到一个文本框,就是申请号这个文本框
所以软件默认的用户名是真的用户名就是因为这个原因。
接下来的一个函数就是sub_4027D0
既传入了真用户名的地址还传入了真密码的地址,结合后面验证密码可以分析出这就是根据真用户名算出真密码
所以这个函数真的很关键,接下来就对它进行分析
跟踪密码
静态分析
先用ida看看这个函数的伪码:
注释是我在逆向的过程中加上去的,现在当前阶段应该忽略不看。
接下来过程就比较难了。
看看sub4026e0,静态分析了下,没啥特别的。用od跟了下,确实没啥特别的。
这个函数里面有用到this指针去访问成员所以跟的时候要记好对应的地址。
接下来是sub_402730:
我们可以看到:
传入了v13和a1两个参数,a1是我们的用户名。
所以感觉这个函数会有料。
点进去看了下里面包含的逻辑很复杂。
先暂时略过(等下回来逆向分析的重头戏)
在OD中调试的时候步过就行了。
步过之后的几部之后:
出现了一串字符串(如果敏感的话就知道这是一串md5)这里姑且就以类似md5的字符串来称呼它。
然后紧接着跟完这个函数里面所有的指令。
在调用返回到时会看到这个:
说明这个函数使用了真用户名,然后生成了一个貌似md5的字符串,然后后续了循环操作用这个貌似md5的字符串生成了图中我画红线的东西
然后回到最初始的锁定区域:
看看sub402920()这个函数,传入v1+1444(就是从注册表中读取的我们填的假的注册密码)
填入假密码:123456789
OD下个断点,看看:
在调用我们要看的函数之前栈的情况是这样的。
调用完之后,往后调:
这部分代码是strcmp()比较用户名的对应的汇编实现。
再往回调一点:
取了之前生成的红线的字符串,然也取了另外一个地址,之后就是从这两个地址取字节进行比较,只要不等就Jmp跳出比较,到后面去了,然后这部分还有一个跳
执行这个跳过后来到了这里,我们往上看看跳过了啥?
直接就跳过了:push 注册成功的字符串的地址。
在看看,除了红线字符串的另外一个地址是?
19FC64
我们下一个19FC64的内存访问断点,看看之前那个函数往里面写了内容。
注意在给19FC64下内存断点时,需要确保程序已经运行到我们之前锁定的那个区域处也就是:
在这个范围内下内存访问断点。你可以现在这个片区域下个断点,然后让程序运行到这里,然后下个内存访问断点。不然程序其他部分也有访问这个地址的模块,会触发多程序的多线程机制。然后之间就验证程序了。
断下来发现了这个。
看看这部分代码在那个函数里面
在sub402920里面(就是我们之前说的将假密码传入的函数)
那么到目前为止,之前的分析得出的结论就是:
用户第一次使用软件时,填入了用户名和密码,程序会将用户填入的注册用户名和注册密码填入注册表,下一次程序启动时就会从注册表中读取用户填入的用户名和密码。然后再对用户输入的密码进行变形操作,最后与程序真正的用户名和真正的密码进行比对。
真正的用户名由程序读取用户电脑的磁盘序列号生成,而真正的密码由真正的用户名变形而来。
所以才有了我之前的注释:
之前也分析过了,真正的用户名就是程序打开自动填入的用户名。
所以分析真正的密码是怎么生成的
跟踪真正的密码生成
现阶段的主要矛盾是解决这个截图里面的内容。
点进去看看:
这个函数简略的看看就是对对象成员进行初始化。问题不大。其实v13就是一个对象。
sub_402730这个函数先暂时不看,在OD中调试时步过就行。
在这个函数的内部,发现划线的东西很奇怪。上od看看。
这个函数的作用就是返回一串类似md5的字符串的地址。
调用完毕后:
就开始取这个字符串的成员了。
所以sub_402750(v13)这个函数就是专门返回那个字符串地址的。
后面的一系列操作就是对这个取字符串的成员生成我前面说过的画红线的密码。
ps:如果对c++熟悉的话,可以猜测出,其实v13是一个对象的地址,sub_402750这个函数用来取出这个对象的一个成员。
那么我们来看看这个生成貌似MD5的函数(sub402730)
翠花!上OD!
进入SUB402730这个函数。然后进入sub_402760
这些函数我都逆过。包括这些里面的东西。
看到这个函数里面的这些常量赋值就知道这就是md5加密。
这个软件用的md5算法和类成员相结合起来了。逆向难度很大,所以我在逆向的时候把这些函数都逆了一遍逆到核心部分时,在0x401c50,里面根本不可能把那个算法逆向过来而且很多常量。所以在网上搜了一下这些常量发现就是md5加密。
(因为平常只知道这个算法,用用网上的解密工具,具体特征不清楚,所以把那个算法自己逆向了一边)
这有一篇MD5参考文章:
IDA中的MD5加密特征
所以可以得出:
这些东西。
至此算法逻辑彻底理清楚了:
用真正的用户名进行md5加密,然后将md5加密后的字符串,选其中成员再变形|
下,得到一个16位的中间密码
然后读取用户输入的密码,进行一系列变形,变形的结果与中间密码
一致就通过验证。
注册机编写
将软件启动后自动的用户名MD5加密然后一系列操作得到中间密码,直接把这个函数的代码扣下来,再改改就行。
然后把这个函数给逆向过来就行:
写出注册机,然后得到注册密码
注册并重启函数
注册机代码我上传了
注册完成之后软件中显示的不是注册用的密码。
而是算出来的中间密码
注意:win10请把该软件设置为xpsp2兼容,不然这软件里面的不兼容会影响到用户名的验证感谢Poyoten大叔指点
总结
这个软件逆向涉及windows编程里面的注册表的操作、磁盘信息获取以及MD5算法、C++逆向、OD调试基本功、IDA基本操作、一定的编程能力
这个软件很适合用来做已经入门逆向工程的朋友的自我检验测试!