您的位置:首页 > 其它

最简单的一个堆栈溢出攻击实例 (2) [by Progsoft]

2006-11-22 00:50 351 查看
下面我们以Release版本为例,解剖程序。

将exe反汇编得到关键代码如下:

函数ShowComputerName:


00401030: 8B 4C 24 04 mov ecx,dword ptr [esp+4]


00401034: 83 EC 0C sub esp,0Ch


00401037: 8D 44 24 00 lea eax,[esp]


0040103B: 50 push eax


0040103C: 51 push ecx


0040103D: E8 BE FF FF FF call 00401000


00401042: 83 C4 14 add esp,14h


00401045: C3 ret

主函数main:


00401080: 68 30 50 40 00 push 405030h


00401085: E8 A6 FF FF FF call 00401030



0040108A: 83 C4 04 add esp,4

我们知道函数调用是采用堆栈方式,那么CPU是怎么工作的呢?

在WindowsXP/2000操作系统下,通过大量的汇编代码我们可以看到,函数调用的参数传递是采用堆栈进行。

何故?

原因是我们使用的个人计算机一般都是采用x86系列CPU,由于可用通用寄存器非常少的缘故,只能采用堆栈进行。而作者工作使用的PowerPC系列CPU,由于有32个通用寄存器,所以函数调用的参数都采用寄存器R3、R4……来完成。据说苹果机采用PowerPC应该就属于按照寄存器传递的方式,但作者没有苹果机,有大家可以自己看看。

下面还是回归正题,这个代码怎么跑呢?

假定代码运行到00401080处,ESP指针为00130000

那么堆栈将如何发展呢?

| ………… | 低地址
+------------------------------+
| |
+------------------------------+ 高地址 ESP 00130000

完成push 405030h后,405030h被压栈,ESP指针上移。

| ………… |
+------------------------------+ ESP 0012FFFC
| 00405030h |
+------------------------------+

完成call 00401030后,也就是开始调用函数ShowComputerName。

函数调用后,返回main主函数的 EIP地址0040108A被压栈,同时ESP指针上移。这个压栈数值就是我们要利用的溢出攻击目的。

| ………… |
+------------------------------+ ESP 0012FFF8
| 0040108Ah |
+------------------------------+
| 00405030h |
+------------------------------+

下面我们就来到溢出函数部分,我们可以知道现在ESP是0012FFF8,所以mov ecx,dword ptr [esp+4]就是将压栈的数组首地址取出来放置到寄存器ecx。

接下来sub esp,0Ch,是预留局部变量pucComputerName的空间,刚好12个字节。ESP上移12个字节,就是pucComputerName首地址。

| ………… |
+------------------------------+ ESP 0012FFEC
| pucComputerName |
| 的空间 |
| |
+------------------------------+
| 0040108Ah |
+------------------------------+
| 00405030h |
+------------------------------+

再后lea eax,[esp],将esp的值赋值给eax,现在eax指向pucComputerName的首地址,exc指向全局变量g_aucName的首地址

0040103B: 50 push eax
0040103C: 51 push ecx

eax和ecx被压栈给函数GetName调用时候使用,这样栈空间图演变为:

| ………… |
+------------------------------+ ESP 0012FFE4
| 00405030h |
+------------------------------+
| 0012FFECh |
+------------------------------+
| pucComputerName |
| 的空间 |
| |
+------------------------------+
| 0040108Ah |
+------------------------------+
| 00405030h |
+------------------------------+

接下来调用函数GetName,返回函数ShowComputerName的EIP指针00401042已经被压栈,ESP再次上移,栈空间图演变为:

| ………… |
+------------------------------+ ESP 0012FFE0
| 00401042h |
+------------------------------+
| 00405030h |
+------------------------------+
| 0012FFECh |
+------------------------------+
| pucComputerName |
| 的空间 |
| |
+------------------------------+
| 0040108Ah |
+------------------------------+
| 00405030h |
+------------------------------+

接下来在函数GetName就是复制拷贝了,也就是将g_aucName的内容如实全部拷贝到局部变量pucComputerName所在地址,由于局部变量使用的是栈空间,这样我们main函数返回的EIP就被我们无情改写得面目全非了,欺骗了CPU,目的达到。

拷贝完成暂未返回函数ShowComputerName的栈空间状态。

| ………… |
+------------------------------+ ESP 0012FFE0
| 00401042h |
+------------------------------+
| 00405030h |
+------------------------------+
| 0012FFECh |
+------------------------------+
| 'H','e','l','l' |
| 'o','W','o','r' |
| 'l','d','!','/0' |
+------------------------------+
| 00401072h |
+------------------------------+
| 0x6A,0x00,0x68,0x30, |
+------------------------------+
| 0x50,0x40,0x00,0x68, |
+------------------------------+
| 0x30,0x50,0x40,0x00, |
+------------------------------+
| 0x6A,0x00,0xFF,0x15, |
+------------------------------+
| 0x90,0x40,0x40,0x00, |
+------------------------------+
| 0x6A,0x00,0xFF,0x15, |
+------------------------------+
| 0x48,0x40,0x40,0x00, |
+------------------------------+

由于GetName调用关系的保留的EIP指针和ESP现在指针都未被破坏,因此ret能正常返回,执行过后。

EIP被置为00401042h,ESP下移为0012FFE4

接下来我们要执行00401042所在指令了,也就是add esp,14h,为什么是14h呢,原因是我们不是push了2个函数参数么?此处也需要“弹出”,此处非pop弹出,是编译器优化结果,直接该esp最快、最直接。14h=0Ch+08h

这样我们的ESP指针就下移到0012FFF8,此时你看看此处返回地址是什么?已经被我们改写为jmp esp指令所在地址,这样执行ret后,EIP被置为00401072h,ESP下移为0012FFFC。

EIP即将执行的指令是jmp esp,而ESP 所在地址就是我们溢出攻击指令。下面发生了什么相信大家都明白了,那就是我们攻击自己溢出漏洞的程序部分被激活。

由于时间太晚了,就写到这里了。

编写该攻击程序心得体会,请看下篇。^_^
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: