[re]无需脱壳dump内存来静态分析
ctf逆向中遇到加壳的程序,其实大部分情况下无需脱壳,因为我们的目的是解题的到flag,只需分析出题目的算法,而不必要将壳完整的脱下来。所以我们可以采取动态调试等壳程序运行结束之后直接将解密后的源代码从内存中dump下来静态分析的方法来解题,下面以一道题目进行说明:
链接:https://pan.baidu.com/s/1lmNP32Bcnv9QfYLLESbQAg
提取码:4r06
静态分析
IDA打开之后发现只有一个start函数:
查看段,发现有vmp0和vmp1段,怀疑有可能是VMP壳,或者其他壳伪装的,不确定,因为PEinfo等查看PE文件的工具没有分析出是什么壳:
![image-20200302210418666](https://i-blog.csdnimg.cn/blog_migrate/aaf8b3d919e74d0942f308dc48e6b21a.png)
vmp壳是一种将代码加密之后启动vmp虚拟机然后解密代码在vmp虚拟机中运行的壳,具体可以查看52破解或者谷歌,这里不详细介绍(毕竟还不确定是否是vmp壳),而且这道题也没必要将壳脱下来。
静态看代码start处,发现是一些没有卵用的指令,然后接一个大跳转:
![image-20200302210557102](https://i-blog.csdnimg.cn/blog_migrate/2ca954e115976a76263f401f0232035a.png)
跟进大跳转跳转的地方:
![image-20200302210647276](https://i-blog.csdnimg.cn/blog_migrate/3249f97f9c50d62d57bfcf0cb9ba3c64.png)
是很长的一段壳代码,但看到了pushad,那么根据esp定律法,找到对称的popad基本就是壳程序的结束地方了,向下拉这段代码就会发现popad,然后紧跟着有一个大跳转:
![image-20200302210758885](https://i-blog.csdnimg.cn/blog_migrate/b7e5d5c8726cefb2cc2b273ab813ef29.png)
那么有理由相信这里就是壳程序的结束位置,这个跳转应该就是跳到程序真实OEP的跳转。
动态调试
将程序拖到OD里,根据代码末尾的地址和加上偏移找到运行时的地址下断点,然后执行到断点。或者单步执行法执行到这里也可以(单步执行,遇到往回跳的跳转直接执行到下一条指令):
![image-20200302211309135](https://i-blog.csdnimg.cn/blog_migrate/1435efc3020d6d0f9fad531b03208f45.png)
然后单步执行跟到跳转之后的地方:
![image-20200302211429231](https://i-blog.csdnimg.cn/blog_migrate/7c34d32d25c92154f59cb2730fb6ceda.png)
有经验已经看出这里是vs编译的c++代码的入口点该有的样子了,但即便没看出来也没关系,因为之前我们分析的时候就怀疑这里是真正的OEP所在,现在验证一下,ctrl+D查看字符串:
![image-20200302211528966](https://i-blog.csdnimg.cn/blog_migrate/10d02eba660722e7c315990b74a7995f.png)
**可见我们已经看见了程序的关键字符串,说明这里源代码已经解码完成,我们也进入了程序真正的源码领域了。**接下来的汇编代码就是程序的原本逻辑了,但看汇编毕竟头大,我们将代码从内存中dump下来然后使用IDA进行反汇编静态分析。
dump内存
使用OllyDbg的OllyDump工具,首先要确定内存的起始地址,再OD的M窗口中:
![](https://i-blog.csdnimg.cn/blog_migrate/6553f790cd34dde55c2b8a0c939ace64.png)
这是我的地址,不同环境每次运行都不一样,这里可以看出test.exe是从内存地址0x870000的地方开始的,所以我们打开OD的插件OllyDump:
![image-20200302212037026](https://i-blog.csdnimg.cn/blog_migrate/2b62fcece4c25b8d5bf7159f82da61ed.png)
只需改一下这两项就可以了,其他的什么OEP啊重建IAT表啊啥的都没用,毕竟我们又不是脱壳,dump下来之后又不用它运行,点击脱壳之后保存为test2.exe:
继续静态分析
用IDA打开刚才dump下来的test2.exe(不能运行的,不用试了)可以看到里面已经有很多函数了:
![image-20200302212238327](https://i-blog.csdnimg.cn/blog_migrate/3f6d4fb5ddb34c702cff70b8b0e086d9.png)
还是从字符串开始入手,查看字符串:
![image-20200302212333718](https://i-blog.csdnimg.cn/blog_migrate/79b6f8896ed29143bdfb5f017380f796.png)
和OD中看到的差不多,直接到关键字符串引用的位置看:
![image-20200302212439226](https://i-blog.csdnimg.cn/blog_migrate/59e1b727a8d949b2fb087ffef201d3f0.png)
找到这部分代码了,但前面地址部分是红色的,说明不在函数之中,那么现在也没法f5,凭经验判断应该有一些花指令、垃圾指令等等的扰乱静态分析,所以往前看,没多远就找到了:
![image-20200302212609229](https://i-blog.csdnimg.cn/blog_migrate/af7f485a8ec9a4b4c6173a4a174428a7.png)
看到函数到jmp eax的地方没了,本不应该这么突兀的结束,仔细分析这里代码发现端倪:
![image-20200302212834837](https://i-blog.csdnimg.cn/blog_migrate/0d16037467d708897006639f8d121f1c.png)
xor eax, eax //eax异或自己,eax=0
mov [eax], eax //将eax的值传给eax所指向的地址,地址0肯定是无法访问的,一定会报错
jmp eax //再跳转到地址0更加无法理解
整个代码就是个垃圾代码,完全没用,让IDA不能明确分析出函数结构,干脆nop掉:
![image-20200302212948083](https://i-blog.csdnimg.cn/blog_migrate/57dc1a790427d4f19cecf5a537c0d33e.png)
然后这时还是不可以f5的,还需要编辑一下函数结构,首先要找到函数真实的结束地址,一般retn地址就是函数结束的地方,总之往下来吧:
![image-20200302213044494](https://i-blog.csdnimg.cn/blog_migrate/cd5324d827fb352ac791cf8acc41d981.png)
可以看到这里不止有retn还是下一个函数开始的地方,所以我们有理由相信这里就是这个函数结束的地方,所以回到上面函数的区域邮件edit function编辑函数:
![image-20200302213147135](https://i-blog.csdnimg.cn/blog_migrate/3097cddcff6e75871edda6e2e81e5cdf.png)
这时可以尝试f5了,发现可以:
![image-20200302213215182](https://i-blog.csdnimg.cn/blog_migrate/308be66e7a2778b98b88b96013192d22.png)
分析
进行到这里已经完全可以静态分析了,首先简单判断一下程序逻辑:
![image-20200302213327813](https://i-blog.csdnimg.cn/blog_migrate/473121a718904efaa5533d6ff04b181e.png)
输入内容的结构体其实从初始化就能看出来(也不重要),v2[0]就是存放输入字符串的指针,v2[4]是长度,其他没用。能看出flag长度是38,进入校验flag函数查看逻辑:
![image-20200302213705142](https://i-blog.csdnimg.cn/blog_migrate/ae6eebd2c62dc0a09b22b280ab0410d3.png)
逻辑非常简单,将两个字符串拼起来,然后江里面的y换成7,z换成8就是flag了。
![image-20200302213840394](https://i-blog.csdnimg.cn/blog_migrate/fb4a3b3eba9faf7281682d5fc7047204.png)
补充
如果一定要调试的话, 需要使用OD在调试时修改代码以绕过反调试,先把xor eax,eax那里nop掉,因为会访问到不可访问地址报异常退出:
![image-20200302214030370](https://i-blog.csdnimg.cn/blog_migrate/12f82e3751ccf804a9f9ad56bf332874.png)
![image-20200302214057843](https://i-blog.csdnimg.cn/blog_migrate/daae47c505d0cff596fb319722744b82.png)
然后后面还有个判断debug的地方,可以直接把判断跳转改为jmp直接跳转:
![image-20200302214136777](https://i-blog.csdnimg.cn/blog_migrate/ae7beed947d527fc702a3c4c15594018.png)
![image-20200302214157925](https://i-blog.csdnimg.cn/blog_migrate/03dbe6a167dcaf25e7f7d2fbaa52531e.png)
然后就可以正常调试了,但由于是壳解密的代码,每次调试都要修改一次,相对麻烦一些,建议能静态分析就静态分析。