这道题被大家称为反调试大全,我一开始也是被反调试搞得没有信心了于是就去根据ida静态分析的结果去还原算法了,结果又陷入了苦海中,最后一咬牙把反调试全过了才找到了正解和多解。
用od打开程序后发现进入程序住逻辑后地址不是0x00400000
开始的,所以肯定不是固定基址,打开010Editor修改随机基址标志位(PE
标志下数一行零六个)由0x02
改为0x03
,方便以后调试和分析:
定位窗口回调我是一步步跟的,因为在窗口毁掉之前的都是系统函数,也没有什么好说的
跟到0x0043D39D
那里后程序跑了起来,所以证明窗口回调是在这里注册的-
跟进去后发现了DialogBoxParamA
这个API,这就是在注册窗口回调,根据参数看到注册的窗口回调地址为0x0042E1A3
:
这个地址是一个jmp 00434EF0
说明程序是Debug
版编译的(搞不清楚作者为什么要编译Debug版程序)。废话不多说了,找到了窗口回调了就可以开始分析程序了
ida F5大法分析窗口回调中的代码:
可以看到在窗口回调中有检查环境(sub_42D4F1(); sub_42E428(); sub_42D825()
里面都有检查,这些检查函数返回值如果为1就调用ExitProcess(0);
)这些检查od的反调试插件都可以过掉,但是我发现他是调用ExitProcess
来退出程序的,所以就用010Editor把PE
文件中所有调用这个API的二进制代码FF15CCF34900
改为了0x90 (nop)
,防止其他地方也有调用该API退出进程
这算是过掉了第一步的反调试
在一开始运行程序时(没有开od等调试工具),程序是正常的,但一打开od、peid等工具后程序会在按下验证序列号自动退出。这个比较简单,可以通过od跟、查看导入表中有什么奇怪的API后下断点(我就是在导入表的中看到了FindWindow
这个API)、在ida中点进函数看:
ida看到的:
过这个也很简单,抹掉该函数调用或者改掉字符串,我是在WinHex
中找到字符串直接抹掉
下图中框住的函数中都有反调试代码
看到这么多反调试的代码真的无语了,所以我先不管三七二十一看到这些代码就给右键->二进制->使用nop填充
使其不能生效。(作者没有在这些反调试代码中做结果验证的相关代码真是给足了面子,不然全nop掉肯定拿不到正确结果)
需要注意的是这次用od nop掉反调试代码后无法保存到可执行文件,所以我就用x32dbg nop掉代码后保存补丁
这个是通过之前od调试时发现的
在函数调用0x42DA78->0x42D294->0x42DA7D
中,由于是Debug版函数调用间有jmp
所以我只写了关键部分,最终这段反调试的代码地址在0x431070
那里
这段反调试代码比较经典,将异常处理绑定到自己的处理位置,然后自己造int3
错误和除零
异常然后自己收,都可以用专门写一篇文章来分析,只可惜作者没有在这里面写重要处理代码,所以直接在上层调用中nop
掉就可以过了。
在上面框住的几个是作者的算法函数,下面的memcmp
很显眼
在很早就发现了memcmp
,但是由于反调试太多了同时也懒得过反调试,而且看到了上面的算法函数就想着我都拿到了算法直接破解算法就拿到密钥了(又陷入了第二题的死磕思路中)。于是在分析算法的苦海中遨游了半天受不了了。。。都分析到了摩斯电码那里了,实在分析不下去了,想想还是过反调试更容易些。扯远了回到正题
在memcmp
那里下断点,输入不同的值来观察:
发现问题了没有?输入123456789
和111111111
的结果是一样的、输入abcdefg
和aaaaaaa
的结果也是一样的
令人好奇了,这是不是算法有问题?突然灵机一现,将输入123456789
后传到memcpy
的那个长字符串参数(64位长)重新输进去会发生什么?
奇迹发生了,此时出来的结果是一样的!memcpy
的另一个参数就是刚才的输入,所以这一层验证就过了
然后跑起来:
过了!难道这就是作者构造的密钥?我有些不敢相信!另外还有疑惑没有解答,因为前面输入的不同内容却产生了相同的输出,所以就怀疑有多解了
对多解的怀疑不仅仅是因为上面的原因,还有在前面对该memcmp
比较参数的怀疑:
调试一下就可以发现v5
是输入的字符串指针,v6
是经过算法编码后的字符串长度(就是前面在memcmp
那里断到的64位长度的字符串)
通过下图来理一下逻辑:
所以memcmp
比较的参数是移动后的,同时也解释了为什么之前输入内容后memcpy
拿到的第一个字符串参数为空了,是因为字符串长度不够64位呀
那推理一下如果字符出串长度超过64位呢?继续看图:
看到这里是不是可以发现如果输入的内容超过64位那就会只判断后64位!
再结合前面发现的输入不同的数字出现的是相同的结果、输入不同的字母出的是相同的结果(经过验证,其实是只要以数字开头就是相同的结果、只要以相同字母开头就是相同的结果)。那么就可以把这两点结合起来,先随便输入一个小段字符拿到经过算法加工的内容,将该内容补到刚才输入的字符后面再次输入。比如输入abcdefg
拿到432a34a4946708602bdf52a8b556a3c18ff9ab60c346da83579f149c4f366513
,然后构造出abcdefg432a34a4946708602bdf52a8b556a3c18ff9ab60c346da83579f149c4f366513
再次输入:
于是memcmp
这一层又轻松的过了
但是我们可以发现其实在memcpy
后面还有一个校验函数:
这个校验函数返回1为校验成功、0位校验失败,而在实际测试中,这段校验代码“时灵时不灵”,而这段校验代码校验参考的内存则是一大片0加上一个特殊校验值再加上原输入,但是由于不稳定就没有继续分析了这段校验代码了,暂时把这段代码当作失败的校验,静等作者公开出题思路
这次作者在反调试方面下了很大功法,但是由于意外的Bug导致了多解。
到目前做了两道题了,现在在思考,如果能将作者的反调试思路和昨天Fpc的花指令思路结合起来应该可以造出一个比较强大的CrackMe!
这道题被大家称为反调试大全,我一开始也是被反调试搞得没有信心了于是就去根据ida静态分析的结果去还原算法了,结果又陷入了苦海中,最后一咬牙把反调试全过了才找到了正解和多解。
下图中框住的函数中都有反调试代码
这个是通过之前od调试时发现的
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2019-5-20 10:19
被KevinsBobo编辑
,原因: 修改错误