10分钟学习缓冲区溢出(1)

到现在才做这样的尝试,真是不好意思.不过还是写出吧. 先讲讲如何通过改写返回地址来改变程序流程

代码: w32下编译vc6

缓冲区溢出就是:

1函数调用要把返回地址保留放在栈中,当程序返回时,ret指令会把栈中的地址弹出到ip计数器,然后继续执行

2栈中的内容可能被改写,当内容覆盖了返回地址后,程序就会跳转到别的地方执行.

下面举个例子,看不懂没关系

低------------------------buffer2-buffer1-ebp-retAddr-para---------高

当输出的内容超过缓冲区长度后,就会覆盖ebp和返回地址.当然,一般的输入只会造成段错误,精心构建的缓冲区溢出代码才会影响软件

#include  < stdio.h >
void  function( int  a,  int  b,  int  c) 
   
char buffer1[5]; 
   
char buffer2[10]; 
   
int *ret; 
 //栈示意图
    //低------------------------buffer1-ebp-returnAddress-参数1-参数2-参数3-----------高
   ret 
=(int *) (buffer1 + 12); //加12是因为buffer1占8个字节(由于内存对齐),然后原来的ebp占4个
       //ret就是指向返回值
   
   (
*ret) += 10; //为什加10后面会说
}
 
 
void  main() 
  
int x; 
 
  x 
= 0
  function(
1,2,3); //我们的目标是跳过x=1的赋值,直接执行printf

  x 
= 1
  printf(
"%d ",x); 
}
 

 

先看看main的反汇编代码.用vc6的debug功能,运行中设置断点,然后在main上面右键选 反汇编

12 :    void  main()  {//下面是c和汇编混合写的,汇编语句表示的是*上面一句*c语言的功能是如何实现!!
00401060   push        ebp
00401061   mov         ebp,esp//上面两句是过场,每个函数都要保存ebp,这样建立了一个所谓的帧
00401063   sub         esp,44h//sp向下,给局部变量提供空间,装buffer1和buffer2
00401066   push        ebx
00401067   push        esi
00401068   push        edi
00401069   lea         edi,[ebp-44h]
0040106C   mov         ecx,11h
00401071   mov         eax,0CCCCCCCCh//把中间的内容全部填成ccccc,防止信息泄露用
00401076   rep stos    dword ptr [edi]
13:     int x;
14:
15:     x = 0;
00401078   mov         dword ptr [ebp-4],0
16:     function(1,2,3);
0040107F   push        
3
00401081   push        2
00401083   push        1
00401085   call        @ILT+0(function) (00401005)//在这个call了,我们要跳过下面x=1的语句
0040108A   add         esp,0Ch//在这里我注意到call后面的语句地址是08a,这个值会被压栈,我们要改这个值
17:     x = 1;
0040108D   mov         dword ptr [ebp
-4],1//我们要跳过
18:     printf("%d ",x);
00401094   mov         eax,dword ptr [ebp-4]//这是我们希望执行的语句,94-8a=10,我们返回地址要加10
00401097   push        eax
00401098   push        offset string "ret %x" (00420f74)
0040109D   call        printf (004010d0)
004010A2   add         esp,
8
19:   }

004010A5   pop         edi
004010A6   pop         esi
004010A7   pop         ebx
004010A8   add         esp,44h
004010AB   cmp         ebp,esp
004010AD   call        __chkesp (
00401150 )
004010B2   mov         esp,ebp
004010B4   pop         ebp
004010B5   ret

 

右建在vc里面添加寄存器,和内存查看的窗口,你会用的着的.

这是function里面的两句做的事

7:       ret =(int *) (buffer1 + 12);
0040B7D8   lea         eax,[ebp+4] //ebp+4是返回地址,放入eax 

0040B7DB   mov         dword ptr [ebp-18h],eax//把这个地址放入ret
8:
9:       (*ret) += 10;//修改这个地址
0040B7DE   mov         ecx,dword ptr [ebp-18h]
0040B7E1   mov         edx,dword ptr [ecx]
0040B7E3   add         edx,0Ah
0040B7E6   mov         eax,dword ptr [ebp-18h]
0040B7E9   mov         dword ptr [eax],edx
10:   }

 

执行完这些以后,返回地址就从8a改成了94.

0012FF20  0040108A 改前 
0012FF24  00000001 
0012FF28  00000002 
0012FF2C  00000003

改后

0012FF20  00401094 
0012FF24  00000001 
0012FF28  00000002 
0012FF2C  00000003

最后ret会把94这个地址弹到ip,然后下面就跳过了x=1这句了

不过程序最后会在_chkesp函数里面出错,原因是我们虽然跳过了x=1

的赋值语句,也跳过了汇编中0040108A   add         esp,0Ch这句,这句的目的是让esp回到调用前的位置.

由于调用事压了1,2,3这三个数,所以要加0c=12个字节.

没有这句esp就和开始调用不一致拉.不过没有关系.缓冲区溢出时我们的代码会用exit()退出,所以根本运行不到后面的内容.

eof


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值