简单的缓冲区溢出实验

时间:2023-02-10 15:33:38

在VS2008中进行的缓冲区溢出实验

其中代码如下所示:

   1:  #include <stdio.h>
   2:  #include <stdlib.h>
   3:   
   4:  void why_here(void) //这个函数没有任何地方调用过 
   5:  {
   6:  printf("why u here !n\n");
   7:  printf("you are traped here\n");
   8:  system("pause");
   9:  _exit(0);
  10:  }
  11:   
  12:   
  13:  int main(int argc,char * argv[])
  14:  {
  15:   
  16:   
  17:  int buff[1];
  18:  buff[3] = 0x004113c0; //buff[3]=0x0041111d; buff[3]=why_here;
  19:   
  20:   
  21:  system("pause");
  22:  return 0;
  23:  }

在代码中,没有任何地方调用了why_here函数,但是该程序的执行结果如下图所示:

简单的缓冲区溢出实验

可以看到,why_here函数被执行了,我们来看看调试过程中反汇编的结果:

 

   1:  int main(int argc,char * argv[])
   2:  {
   3:  00411450 55               push        ebp  
   4:  00411451 8B EC            mov         ebp,esp 
   5:  00411453 81 EC CC 00 00 00 sub         esp,0CCh 
   6:  00411459 53               push        ebx  
   7:  0041145A 56               push        esi  
   8:  0041145B 57               push        edi  
   9:  0041145C 8D BD 34 FF FF FF lea         edi,[ebp-0CCh] 
  10:  00411462 B9 33 00 00 00   mov         ecx,33h 
  11:  00411467 B8 CC CC CC CC   mov         eax,0CCCCCCCCh 
  12:  0041146C F3 AB            rep stos    dword ptr es:[edi] 
  13:   
  14:   
  15:  int buff[1];
  16:  buff[3] = 0x004113c0;
  17:  0041146E C7 45 04 C0 13 41 00 mov         dword ptr [ebp+4],offset why_here (4113C0h) 
  18:   
  19:   
  20:  system("pause");
  21:  00411475 8B F4            mov         esi,esp 
  22:  00411477 68 D8 57 41 00   push        offset string "pause" (4157D8h) 
  23:  0041147C FF 15 B8 82 41 00 call        dword ptr [__imp__system (4182B8h)] 
  24:  00411482 83 C4 04         add         esp,4 
  25:  00411485 3B F4            cmp         esi,esp 
  26:  00411487 E8 B9 FC FF FF   call        @ILT+320(__RTC_CheckEsp) (411145h) 
  27:  return 0;
  28:  0041148C 33 C0            xor         eax,eax 
  29:  }
  30:  0041148E 52               push        edx  
  31:  0041148F 8B CD            mov         ecx,ebp 
  32:  00411491 50               push        eax  
  33:  00411492 8D 15 B4 14 41 00 lea         edx,[ (4114B4h)] 
  34:  00411498 E8 EA FB FF FF   call        @ILT+130(@_RTC_CheckStackVars@8) (411087h) 
  35:  0041149D 58               pop         eax  
  36:  0041149E 5A               pop         edx  
  37:  0041149F 5F               pop         edi  
  38:  004114A0 5E               pop         esi  
  39:  004114A1 5B               pop         ebx  
  40:  004114A2 81 C4 CC 00 00 00 add         esp,0CCh 
  41:  004114A8 3B EC            cmp         ebp,esp 
  42:  004114AA E8 96 FC FF FF   call        @ILT+320(__RTC_CheckEsp) (411145h) 
  43:  004114AF 8B E5            mov         esp,ebp 

 

 

在程序的执行过程中,我们在监视窗口中,查看如下变量的值:

简单的缓冲区溢出实验

通过汇编代码我们可以看到,进入main函数后,堆栈操作过程如下:

1.将ebp压栈:push ebp

2.将ebp指向esp的位置:mov ebp, esp

3.将esp减去0xCCh字节:sub esp, 0CCh

4.将ebx, esi, edi 压栈:push ebx; push esi; push edi;

5.将ebp和esp+8的位置初始化为:0xCCCCCCCCh: 汇编代码9~12行

进入main函数过后的堆栈变化如下图所示:

简单的缓冲区溢出实验

通过上图可以发现,&buff[3]的地址就是main函数的返回地址eip存放的地方,我们在C代码的18行将buff[3]赋值为why_here的地址,所以eip就被修改成了why_here的地址,

这样在main函数返回的时候,就会跳转到why_here执行。如果这段代码的是恶意代码,那么将会对系统造成严重的损害。

 

总结:

一直都很懒,不想记录技术心得,今天又把缓冲区溢出拿出来学习了一下,虽然很简单,感觉还是受益匪浅。一定要理清楚x86堆栈的结构,要学会使用vs进行调试,在看C语言不行的时候就要进行反汇编。

这个程序,以前直接将buff[0]~buff[0x3d]的位置都赋值为why_here的地址,这样的话vs2008在运行的时候就会报错,说检查到堆栈溢出,这应该是ebp也被破坏了的原因。还有个问题就是:

我直接对buff[3]=(int)why_here;赋值或者对buff[3]=0x41111d;赋值都可以跳转到why_here的函数体。C语言代码的18行。

刚开始,我一直不明白,把why_here赋值给buff[3]其实得到的值也是0x41111d,这样就出现了将0x41111d和0x004113c0赋值给buff[3]都可以跳转到why_here的情况,即一个函数对应了两个地址。这让我非常的疑惑。

让我们来看看汇编代码的0x41111d和0x004113c0分别存放了什么,如下图所示:

0x41111d存放的是一条跳转指令,这条指令的目标地址是why_here的实际地址,即0x4113c0.

简单的缓冲区溢出实验

0x4113c0存放的是why_here的实际地址:

简单的缓冲区溢出实验

我们注意到0x41111d位置处,其实是一个函数的跳转表,

当我们去某个函数的名字,如why_here的时候,我们得到的是这个跳转表中某一项的地址,而不是函数的实际地址。

至于为什么这样做,我觉得应该和编译器有关,个人猜想:

1.把函数都放到一个跳转表中,只要跳转表的地址不变,那么函数实际存放的位置即使变了也无所谓,只需要修改jmp指令的目标地址就行了。

2.用户把函数名赋值给一个整形变量,得到的是跳转表中的地址,而不是实际存放函数的地址,如果怀有恶意的程序员修改了这个地址的话比直接修改实际地址带来的危害应该更小。