一、什么是缓冲区溢出?
缓冲区溢出是指当计算机向缓冲区内填充数据位数时超过了缓冲区本身的容量,使得溢出的数据覆盖在合法数据上,通过往程序的缓冲区写超出其长度的内容,造成缓冲区的溢出,从而破坏程序的堆栈,造成程序崩溃或使程序转而执行其它指令,以达到攻击的目的。
二、程序的简单说明
执行过程:
void fun()函数中buf只分配了8字节的空间,通过写超出其长度的字符串ss,并传入void fun()函数对buf赋值,使调用fun()函数时的堆栈溢出,覆盖了返回地址,令构造的ss输入部分恰巧使覆盖返回地址部分的内容正好指向haha()函数入口,这样程序就不会返回之前的步骤(也就是主函数中调用fun()函数下边的指令),而是进入了haha()函数,同时执行haha()函数中的printf("\nOK!success")指令,在屏幕上打印出OK!success
寻找待构造的ss值:
首先通过定义一个全局变量k,它代表传入的ss和buf之间内存地址(彼此相对的地址)的距离,然后在主函数中首先定义一个任意ss(经测试,传入什么ss并不影响ss和buf之间的距离),调用fun(),这样可以得到在本机上二者地址相差的距离,然后用go记录haha()的代码段地址,这里需要说明一点:当调用一个函数的时候,首先是参数入栈,然后是返回地址。并且,这些数据都是倒着表示的,因为返回地址是4个字节,所以实际上返回地址就是:buf[k-1]*256*256*256+buf[k-2]*256*256+buf[k-3]*256+buf[k-4]。将go拆分成4部分后赋给ss相应位置,得到的ss就是我们所想要的可以令fun()函数执行后直接跳到haha()函数的字符串。
三、代码部分
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <iostream>
int k;
void fun(const char* input)
{
char buf[8];
strcpy(buf,input);
k=(int)&input-(int)buf;
printf("%s\n", buf);
}
void haha()
{
printf("\nOK!success");
}
int main(int argc, char* argv[])
{
printf("Address of foo=%p\n",fun);
printf("Address of haha=%p\n",haha);
void haha();
int addr[4];
char s[]="FindK";
fun(s);
//printf("%d\n", k);
int go=(int)&haha;
//由于EIP地址是倒着表示的,所以首先把haha()函数的地址分离成字节
addr[0]=(go << 24)>>24; addr[1]=(go << 16)>>24; addr[2]=(go << 8)>>24; addr[3]=go>>24;
char ss[]="aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa";
for(int j=0;j<4;j++){
ss[k-j-1]=addr[3-j];
}
//fun(argv[1]);
fun(ss);
return 0;
四、运行结果