首页
论坛
课程
招聘
[原创]MysteriousLetter2解题writeup
2019-6-10 22:44 3272

[原创]MysteriousLetter2解题writeup

2019-6-10 22:44
3272

这道题目主要考察异常处理机制,题目刚发布的时候出现多解,我现在分析的是作者修复后的。

1. 查壳,无壳的C++程序。

2. 直接载入OD,看到了异常处理需要的两个函数,SetUnhandledExceptionFilter和UnhandledExceptionFilter。

SetUnhandledExceptionFilter函数的唯一一个参数为异常处理函数指针。当程序发生异常时,且程序不处于调试模式(在VS或者其他调试器里运行)则首先调用该异常处理函数。因此,程序可以主动抛出一个异常来判断当前程序是否正在被调试


3. 我们现在给SetUnhandledExceptionFilter和UnhandledExceptionFilter这两个函数设置断点,运行程序。断在了SetUnhandledExceptionFilter的入口处。我们看下堆栈的情况,正如你所看到的异常处理函数入口地址为00401C8E,我们在命令栏中输入BP 00401C8E给该函数设置断点。


4. 异常处理函数前面已经设置过了,所以我们将对SetUnhandledExceptionFilter设置的断点删除掉,运行程序,找到获取输入的函数,输入序列号401353(篇幅有限,不演示踩坑,这里直接输入的是真码)。


5. 输入的长度必须小于7位才可以继续运行


6. 限定真码的后三位为353


7. 限定前三位的ascii十六进制之和为0x95,也就是十进制的149,我一次做的时候猜的是212353和230353。


8. 把输入的字符串直接转换成整数放到esi


9. 在0040134E处CALL 00401354,我们知道call是一个组合的指令,call 00401354相当于push 00401353然后jmp 00401354,先压入下一行地址作为返回地址,然后再跳转。但是00401354处执行了pop eax,这样就导致返回地址丢失了,这个程序回不到00401353这个地方了。


10. 输入正确这里会触发除零异常,然后走异常处理程序,这里就可以看出程序的这部分代码应该是用内联汇编写的,可见作者的良苦用心,如果错误就继续向下执行,提示error,并且程序卡死,因为最后那条jmp是跳向自己的死循环。


11. 异常处理过程将会断在系统默认的异常处理函数入口处,因为程序有异常发生,并且当前程序正在被调试,所以,并不会首先调用程序之前设置的入口为00401C8E的异常处理函数,而异常转交给调试器处理了,而调试器也无法处理该异常,所以最终调用系统默认的异常处理函数UnhandledExceptionFilter来处理,这个函数里会内嵌ZwQueryInformationProcess函数来检测是否有调试器。


12. 该函数通过将InfoClass参数设置为7,将可以获取到当前进程是否被调试的信息,该信息将保存在Buffer参数指向的缓冲区中。如果该缓冲区返回的是FFFFFFFF的话表示当前程序正在被调试,我们将其四个字节全修改为零就表示没有调试器了。因为我使用的原版OD,没有任何插件,所以这里要改,如果有strongOD等插件,这里插件会帮你过了反调试。

这里看一下程序的整个流程




注意:

1. 此程序直接用IDA可能无法直接F5转换伪代码,因为堆栈不平衡,ida无法正常判断程序的流程,这里需要手动平衡堆栈(用od把pop去掉一个再用ida的F5)

2. 此程序涉及到异常处理,最好用不带插件的原版OD分析,OD需要设置忽略异常。



此文章是我个人的分析过程,如有错误,希望大佬能够帮我改正!



[注意] 招人!base上海,课程运营、市场多个坑位等你投递!

上传的附件:
收藏
点赞2
打赏
分享
最新回复 (2)
雪    币: 63
活跃值: 活跃值 (46)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
hk有缘人 活跃值 2019-7-26 16:45
2
0
关于程序异常处理算是讲的比较清楚的了。
雪    币: 776
活跃值: 活跃值 (501)
能力值: ( LV8,RANK:126 )
在线值:
发帖
回帖
粉丝
Roger 活跃值 1 2019-8-3 18:03
3
0
hk有缘人 关于程序异常处理算是讲的比较清楚的了。
游客
登录 | 注册 方可回帖
返回