逆向攻防世界CTF系列37-crackme
参考https://blog.csdn.net/xiao__1bai/article/details/120230397
nspack的壳,查了一下好像是北斗的一个壳
没找到什么脱壳软件,只能手动脱壳了
手动脱壳的最终要的是ESP定律
ESP定律的原理就是“堆栈平衡”原理
涉及的汇编知识:
call命令:
- 向堆栈中压入下一行程序的地址;
- JMP 到 call 的子程序地址处。
例如:
00401029 E8 DA240A00 call 004A3508
0040102E 5A pop edx
在执行了00401029以后,程序会将0040102E(下一条指令地址)压入堆栈,然后 JMP 到 004A3508 地址处
RETN命令:
将当前的 ESP 中指向的地址出栈;JMP 到这个地址。
堆栈平衡可以简单的理解为在一个函数的ret之前,中间入栈和出栈的次数要相等(也就是一定要保证在 RETN 这条指令之前,ESP指向的是我们压入栈中的地址)
软件加壳就是隐藏了OEP(或者用了假的OEP), 只要找到程序真正的OEP,就可以立刻脱壳,当程序运行到OEP这个位置,程序控制权会交还给原程序, 一般脱壳的步骤需要寻找这个OEP点
可以看下面这篇文章
手动脱壳教程-CSDN博客和逆向基础:软件手动脱壳技术入门_ollydbg脱壳教程-CSDN博客
1.这个是加了 ASPACK 壳程序的入口时各个寄存器的值:(入壳,解压缩)
EAX 00000000
ECX 0012FFB0
EDX 7FFE0304 //堆栈值
EBX 7FFDF000 //堆栈值
ESP 0012FFC4
EBP 0012FFF0
ESI 77F57D70 ntdll.77F57D70
EDI 77F944A8 ntdll.77F944A8
EIP 0040D000 ASPACK.2.这个是 ASPACK 壳 JMP 到 OEP(Original Enter Point)后的寄存器的值:(出壳,回主程序 OEP)
EAX 004010CC ASPACK.004010CC //保存了当前OEP的值
ECX 0012FFB0
EDX 7FFE0304 //堆栈值
EBX 7FFDF000 //堆栈值
ESP 0012FFC4
EBP 0012FFF0
ESI 77F57D70 ntdll.77F57D70
EDI 77F944A8 ntdll.77F944A8
EIP 004010CC ASPACK.004010CC
除了EIP不同以外,eax 保存当前 OEP 值,其他都一模一样啊!ESP定律的适用范围是几乎全部的压缩壳,部分加密壳。只要是在JMP到OEP后,ESP=0012FFC4的壳,理论上我们都可以使用
是不是只能下断12FFA4的访问断点?
当然不是,那只是ESP定律的一个体现,我们运用的是ESP定律的原理,而不应该是他的具体数值,不能说12FFA4,或者12FFC0就是ESP定律,他们只是ESP定律的一个应用罢了!内存断点:当下读写断点时,调试器会修改断点处读写属性,如果程序对此数据读写的话,会产生读写异常,调试器捕捉此异常
内存断点分为:内存访问断点,内存写入断点。
我们知道,在程序运行的时候会有3种基本的状态产生:
读取–>写入–>执行。
004AE242 A1 00104000 mov eax,dword ptr ds:[004AE24C] //004AE24C处的内存读取
004AE247 A3 00104000 mov dword ptr ds:[004AE24C],eax //004AE24C处的内存写入
004AE24C 83C0 01 add eax,1 //004AE24C处的内存执行
- 当对004AE24C下内存访问断点的时候,可以中断在004AE242也可以中断在004AE247和004AE24C。(因为访问包含执行、写入、读取)
- 当对004AE24C下内存写入断点的时候,只能中断在004AE247。
- 当执行004AE24C的时候,只能中断在004AE24C。
**其实将这么多我做一个方法小总结:**就是对第一次push时的esp地址做硬件断点,因为堆栈平衡,最后esp还会还原到这个地址,我们接下来的jmp就是ope了
光讲有点难懂,直接实操
od直接打开
直接看到亮眼的push,F8一下,发现ESP变化
右键ESP,数据窗口跟随(为了下硬件断点)
46这个地方一下个断点,F9
popfd,看esp又是0019ff70了,再F8
jmp跳出,jmp
跳出壳后就是解压缩的代码了,右键分析当前代码把.text.
段中数据重新反汇编成汇编代码,同IDA
的热键C
。
然后OllyDump出来
扔进IDA
写解密代码,很简单了这里
key = "this_is_not_flag"
enc = [18, 4, 8, 20, 36, 92, 74, 61, 86, 10, 16, 103, 0, 65, 0, 1, 70, 90, 68, 66, 110, 12, 68, 114, 12, 13, 64, 62, 75, 95, 2, 1, 76, 94, 91, 23, 110, 12, 22, 104, 91, 18]for i in range(len(enc)):print(chr(enc[i] ^ ord(key[i % 16])),end='')
flag{59b8ed8f-af22-11e7-bb4a-3cf862d1ee75}
这里解释一下下断点为什么是word?《IDA权威指南中的解释》
2d1ee75}
这里解释一下下断点为什么是word?《IDA权威指南中的解释》
我们之前下断点是46,是两字节的所以是word