在国家包吃包住的路上又艰难迈进一小步【doge】
省流助手:啰嗦至极菜鸡学习笔记,多图警告
首先拖进PEiD查壳,发现未加壳
点击注册,出现“未注册版本”。
可以输入注册码,随便输入一串字符然后点击确认,软件退出,没有特殊提示。
随后自动再次打开,仍为未注册版本
既然目前为“未注册版本”,那么自然有“已注册版本”或者“注册版”,所以,而且这个提示应该是在软件已经确认注册码有效之后才会出现,所以不妨从已确认的结果向前反推认证的过程,所以首先在OD中搜索“注册”字符串,找到程序判断注册是否成功的位置
双击跳转到相关代码,发现在将“已注册版本”压入寄存器中操作前,存在着一个跳转,直接跳过了赋值语句
那么显而易见地,想要使得程序成功注册,我们就需要让上述跳转不执行,而关键的判断就是变量ds:0x579F24的值是否为0,所以这里我们搜索与这个地址有关的赋值和判断语句(右键->查找->所有常量)
在Reference窗口中可以看见相关的搜索结果,保险起见,我们把相关的语句全部下一个断点,然后重载并运行函数
第一个在0x541650处的断点被触发,观察代码,发现该语句给目标地址赋值为1,而我们的目的是让目标地址不被赋值为0,与目标相符。
再仔细查看赋值语句是否有前后文跳转关系,结果发现了一个跳转,使得mov dl, 0x1
的语句被跳过,所以为了目标地址被顺利赋值为1,需要使上文的无条件跳转不实现,此时观察该语句
想要使得该语句不执行,则需要在前面的两个je跳转语句成功跳转,所以此时为了到0x54164E语句的跳转顺利执行,可以把0x541648处的跳转改为无条件跳转jmp。处理完毕后,删除断点,重载并执行程序
程序执行到了0x54169E——直接跳过了对al的赋值,执行目标地址值的判断,观察到eax寄存器值为0,故此时目标地址将被赋0。观察前文跳转,可以看见0x541698处将eax寄存器置零,随即直接跳转至当前地址。
为了使该跳转不实现,将无条件跳转指令填充为NOP指令,随后取消相关断点,重载并重新运行程序
这次程序停在了 cmp byte ptr ds:[0x579F24],0x0
处,该语句的前一条语句是将目标地址赋值为零,但是该语句并未执行,输入command d 0x579F24
在数据窗口中查看当前目标地址的值,发现目标地址对应值已经为0,于是查看上下文,发现并没有跳转语句能使该语句与前一条赋值语句不被执行,所以认为此处的跳转与目标不冲突,继续执行程序
此时程序直接开始运行,于是点击程序中的注册按钮,程序重新暂停,暂停位置为已注册版本前方的目标地址值表语句,此时在数据窗口中观察目标地址的值为0,故此处需要阻止下方的je跳转,于是使用NOP填充
至此,注册去除完毕
虽然已经成功注册,但是程序还有第二道验证——联网验证
尝试连接服务器结合机器码判别注册有效性,如果未联网,则弹窗
由于程序在联网前的功能已经正常,所以此处直接把联网相关代码段绕过即可
搜索**“正在验证”**的字样,查看相关代码段
下文中还有验证失败等字样,故判断当前函数即为联网验证函数,所以尝试把函数段首语句改为retn,保存查看是否还有联网验证
成功绕过,但这个联网验证属实有点。。。emmmmmm,只能说聊胜于无,而且这个绕过多少有点运气成分,因为不知道那个联网验证中是否还有其他的暗桩,到时可以仔细看看有没有别的方式绕过,尽量少地改动源程序
patch后的程序在插入随机数字或者随机字母的时候会出现乱码
这个可以说是这个程序最难绕过的校验了,首先触发时不会有任何提示,其次不知道触发原因。但52破解的大佬之前破解这个程序时,发现了当使用补丁进行破解时,这个暗桩不会被触发,但是如果直接在源程序的基础上patch,那就会触发乱码暗桩,所以这里不难推测,这个程序应该是进行了完整性或者正版的校验
所以我们把程序拖到IDA里,使用find crypt插件查看是否有加密或者校验算法,结果确实在程序中发现了CRC和MD5算法
目前,我们已知的为数不多的信息是:
在点击插入随机字符按钮时,暗桩会被触发
在查壳的时候,我们知道了这个程序是用Delphi写的
执行MD5或者CRC算法时会执行文件读的操作
所以,我们尝试在程序所有的按钮事件上下断点,然后把校验的区间缩短到点击按钮到输出字符这个范围内
这里选择使用ollydbg脚本进行按钮事件的断点布置
然后让程序运行起来,并尝试插入随机字符,从程序停下来的位置开始调试
首先单击**“插入其他”**按钮,程序中断,删除当前断点,继续运行程序
然后点击**“插入随机字母”**按钮,程序中断,随后可以从当前位置开始搜寻程序校验点
但是要在密密麻麻的call语句中搜寻无异于海底捞针,所以计划进行关键函数的定位以进一步减小搜寻范围
首先在IDA里看看程序用到了哪些API,先筛选一下其中嫌疑比较大的,这时,读文件的API ReadFile就映入眼帘
在按钮事件断点被触发后,激活该断点,继续运行函数,程序果然停下来了
(题外话,这个代码写的也太恶心了,每次插入随机元素的时候都要读一次文件做一次校验,感觉没有任何意义呀,总不能说我破解个程序一边运行MD5值还会一直变吧,读文件的开销那么大,属于是初见雏形的shit山代码了)
此时运行到readfile函数结束,跳出到父函数,没有发现有用信息,继续跳出,持续此过程
一直到这个位置找到了MD5的计算结果,而下方的循环就是将原版程序的MD5与当前程序的做对比,要是想要通过当前校验,需要将local.6(ebp-0x18)中的当前MD5改为原版程序的MD5。
所以此处需要使用mov指令将原版MD5移到指定位置,但这样的语句自然是不可以在当前代码的基础上patch,因为长度不相符,所以需要将当前代码在程序的其他位置进行重写,然后使用jmp指令进行无条件跳转执行
一直到这一步其实要是我自己做的话肯定找不到,这部分的MD5校验属于是知道了答案找题目
找到一块代码段的空地址,将判断段代码搬过去,并且用MD5原值提前将现MD5值覆盖(保险起见,可以做一下栈平衡)
注意0x56B0D8处循环跳转地址需要改成新代码段的地址
在原代码段加上到新代码段的跳转
这波啊,这波是狸猫换太子
复现样本、工具下载
本博文仅以学习交流为目的,侵删