
这一课,给大家讲一下,非常好用的ESP定律(至少能脱30种壳)。
首先,我们来复习几个东西
1,ESP寄存器,一般是用来存放栈顶指针的。
2,push *** 是压栈指令,把后面的东西,压入堆栈,与其对应的是pop指令。
3,pushad指令, 把寄存器EAX、ECX、EDX、EBX、ESP、EBP、ESI和EDI等压栈,相对应的为popad指令。
4,pushfd指令,在堆栈上压入32位的EFLAGS寄存器的值,相对应的位popfd指令。
接下来,讲一下ESP定律的原理
1,在加壳程序载入时,假设堆栈状态为:
| 000 | - ESP指向这里
| bbb |
| aaa |
2,例如UPX,它的第一条指令为pushad,那么F8单步一下后,堆栈为:
| 寄存器 | - ESP指向这里
| 的内容 |
| 000 |
| bbb |
| aaa |
3,此时,我们对ESP的值,下硬件访问断点。
4,壳之所以将寄存器,全部压栈,就是为了保护寄存器的值,所以,在壳解压的过程中,ESP会始终指向堆栈中寄存器数据所处位置之上。
5,等到代码和数据解密结束了,那么,又会用popad将寄存器的值拿出来了,此时,触发了我们所下的硬件访问断点,程序断了下来
6,寄存器的值拿出来后,自然就要跳往OEP了
再次针对UPX壳来看,程序加载后为:
/*1014240*/ pushad
/*1014241*/ mov esi, 01010000
/*1014246*/ lea edi, dword ptr [esi+FFFF1000]
/*101424C*/ push edi
/*101424D*/ or ebp, FFFFFFFF
/*1014250*/ jmp short 01014262
我们单步一下,此时寄存器窗口显示 ESP 0006FF6C
我们在命令栏输入: hr 0006ff6c 回车
F9 运行程序,程序断在:
/*10143BD*/ popad
/*10143BE*/ lea eax, dword ptr [esp-80]
/*10143C2*/ push 0
/*10143C4*/ cmp esp, eax
/*10143C6*/ jnz short 010143C2
/*10143C8*/ sub esp, -80
/*10143CB*/ jmp 0100739D
前往OEP自然就知道了。
好,我们再来看另外一种壳:nSPack 3.7(北斗)
载入,代码为:
/*101A116*/ pushfd
/*101A117*/ pushad
/*101A118*/ call 0101A11D
/*101A11D*/ pop ebp
/*101A11E*/ sub ebp, 7
/*101A121*/ lea ecx, dword ptr [ebp-2B6]
在这里,我再跟大家讲一下要知道的东西
在很多教程中,告诉别人ESP定律脱壳,就是找pushad,然后在运行到下一行时,下ESP断点
其实,可以根据我们刚才对原理的分析来看,不用先单步一下,也是可以的(注意ESP的变化范围)
在这里,脱北斗时,开始不用单步,直接下ESP断点。
然后,会发现,F9两次,再F8一次,就到达OEP了。
具体的脱壳操作,以及其它对ESP值下硬件访问断点的方法,请看xiaomajia52的视频
下一课,将讲一下内存镜像法,及脱壳的一些小技巧。

谢谢!
用户系统信息:Mozilla/4.0 (compatible; MSIE 7.0; Windows NT 6.0; SLCC1; .NET CLR 2.0.50727; .NET CLR 3.0.04506; .NET CLR 3.5.21022; MAXTHON 2.0)