您的位置:首页 > 其它

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

2007-10-12 00:08 323 查看
到现在才做这样的尝试,真是不好意思.不过还是写出吧. 先讲讲如何通过改写返回地址来改变程序流程

代码: 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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: