windows堆栈溢出简易测试代码 逆向分析

本文是对前面发的“windows堆栈溢出简易测试代码”里的代码进行逆向分析,还是逆向一下比较完善。工具:OD

1.main函数的反汇编代码

ContractedBlock.gif ExpandedBlockStart.gif Code
 1 00401120  |   55            push    ebp
 2 00401121  |.  8BEC          mov     ebp, esp
 3 00401123  |.  83EC 40       sub     esp, 40
 4 00401126  |.  53            push    ebx
 5 00401127  |.  56            push    esi
 6 00401128  |.  57            push    edi
 7 00401129  |.  8D7D C0       lea     edi, dword ptr [ebp-40]
 8 0040112C  |.  B9 10000000   mov     ecx, 10
 9 00401131  |.  B8 CCCCCCCC   mov     eax, CCCCCCCC
10 00401136  |.  F3:AB         rep     stos dword ptr es:[edi]
11 00401138  |.  E8 C8FEFFFF   call    00401005
12 0040113D  |.  33C0          xor     eax, eax
13 0040113F  |.  5F            pop     edi
14 00401140  |.  5E            pop     esi
15 00401141  |.  5B            pop     ebx
16 00401142  |.  83C4 40       add     esp, 40
17 00401145  |.  3BEC          cmp     ebp, esp
18 00401147  |.  E8 C4030000   call    _chkesp
19 0040114C  |.  8BE5          mov     esp, ebp
20 0040114E  |.  5D            pop     ebp
21 0040114F  \.  C3            retn

main函数的源代码里面就只有一个函数调用和return 0语句。在反汇编代码里面貌似有很多代码,我们需要一一来分析一下:

     1. main函数里面的函数调用是对应与第11行代码,call 00401005,因为这里面只有两个call,而后一个是call _chkesp。

     2. 在call 00401005之前,就是堆栈操作和初始化操作了,第1,2行代码是为了保持堆栈平衡的。

     3. 第3行代码在堆栈上保留了一段0x40长度的空闲空间。

     4. 第4,5,6行是保存寄存器。第7~10行主要是执行stos操作,向edi指向的地址(指向堆栈保留的空闲空间),赋值eax的值0xCCCCCCCC,长度为 ecx(0x10)* sizeof(dword),长度刚好为0x40。

     5. 至于这0x40字节的空间到底有什么用,网上的大虾说是为函数内所有局部变量的开辟的。所有的准备工作做好了之后。

     6. 第12行代码是对eax寄存器清0操作。

     7. 第13,14,15是恢复前面保存的寄存器。

     8. 第16行是调整esp,因为前面开辟了一个段0x40的空间,所以执行的是add esp, 40操作。

     9. 第17,18是对堆栈进行检查。

     10. 第19,20,21行平衡堆栈并返回。

以上是对整个main函数的分析,当然我们的主要目的是分析堆栈如何溢出的,重点是看在执行call 00401005前后堆栈的变化,在这之前,我们先分析一下00401005出的反汇编代码,也就是fun1()的代码。

2. 函数fun1()的反汇编代码

 1  004010D0   |    55              push     ebp
 2  004010D1   |.  8BEC           mov      ebp, esp
 3  004010D3   |.  83EC  48         sub      esp,  48
 4  004010D6   |.   53              push     ebx
 5  004010D7   |.   56              push     esi
 6  004010D8   |.   57              push     edi
 7  004010D9   |.  8D7D B8        lea      edi, dword ptr [ebp- 48 ]
 8  004010DC   |.  B9  12000000     mov      ecx,  12
 9  004010E1   |.  B8 CCCCCCCC    mov      eax, CCCCCCCC
10  004010E6   |.   F3: AB          rep      stos dword ptr  es: [edi]
11  004010E8   |.  C745 FC  00000 > mov      dword ptr [ebp- 4 ],  0
12  004010EF   |.  8D45 FC        lea      eax, dword ptr [ebp- 4 ]
13  004010F2   |.   8945  F8        mov      dword ptr [ebp- 8 ], eax
14  004010F5   |.  8B4D F8        mov      ecx, dword ptr [ebp- 8 ]
15  004010F8   |.  83C1  08         add      ecx,  8
16  004010FB   |.  894D F8        mov      dword ptr [ebp- 8 ], ecx
17  004010FE   |.  8B55 F8        mov      edx, dword ptr [ebp- 8 ]
18  00401101   |.  C702  0F104000   mov      dword ptr [edx],  0040100F
19  00401107   |.  33C0           xor      eax, eax
20  00401109   |.  5F             pop      edi
21  0040110A   |.  5E             pop      esi
22  0040110B   |.  5B             pop      ebx
23  0040110C   |.  8BE5           mov      esp, ebp
24  0040110E   |.  5D             pop      ebp
25  0040110F   \.  C3             retn

第1~10行的代码和main函数第1~10行的代码都一样,唯一的区别在于保留的空间长度是0x48。第19~25行的代码也差不多,主要是恢复寄存器和堆栈,并返回。下面主要分析第11行到18行的代码:

     1. 第11行向ebp-4所指向的变量赋予0,长度为一个dword,4个字节,ebp-4指向的是第一个变量,即我们的iRet。这一行等价于int iRet = 0;

     2. 第12,13行是向ebp-8所指向的变量赋予ebp-4。lea eax, dword ptr[ebp-4] 等价于eax = ebp - 4。ebp-8指向的是第二个变量,即我们的pRet。(如果不知道为什么,可以查阅变量是如何在堆栈中分布的)这2行等价于int *pRet = &iRet;

     3. 第14行是把ebp-8对应的变量的值赋予ecx,为此ecx = ebp - 4。第15行执行的是ecx += 8操作,这样ecx = ebp + 4了。这2行等价于pRet = pRet + 2;

     4. 第16,17行进过两次mov操作,把ecx的值传给了edx,现在edx = ecx = ebp+4。第18行把0040100F赋予edx指向的地址,而0040100F对应的指令是jmp fun2。这3行等价于*pRet = (int )&fun2;

ebp+4指向的存储单元存储的是函数调用后的返回地址,而由上面的4可以看出来,返回地址被修改成了0040100F,这样,当函数返回的时候,就会去执行0040100F处的指令,即jmp fun2。从而执行函数fun2()。

3. 静态分析完成后,我们看看动态的情况是怎么样的。在执行call 00401005后,运行到fun1()函数的第2行时,堆栈如下

0012FF30存储的是fun1()函数的返回地址0040113D,0012FF2C所存储的是ebp:0012FF2C。当程序继续执行到fun2()的第19行后,堆栈如下

再看看0012FF30存储的值已经变成了0040100F了,即返回地址被改掉了。

整个分析过程到此就结束了。

转载于:https://www.cnblogs.com/anzhihun/archive/2008/12/14/1354699.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值