Chinaunix首页 | 论坛 | 博客
  • 博客访问: 525006
  • 博文数量: 257
  • 博客积分: 1666
  • 博客等级: 上尉
  • 技术积分: 1535
  • 用 户 组: 普通用户
  • 注册时间: 2012-04-02 23:02
文章分类

全部博文(257)

文章存档

2013年(2)

2012年(255)

分类:

2012-09-13 12:53:01

    C对于数组引用不进行任何边界检查,并且局部变量和一些状态信息都存放在栈中,这就可能引起严重的程序错误,因为这将会引起对不属于自己范围之内的一些数据的读写。一种特别常见的状态破坏称为缓冲区溢出,下面举个常见的例子,用一个数组存储字符串,但是字符串的长度超出了数组大小。

点击(此处)折叠或打开

  1. char *gets(char *s)
  2. {
  3.        int c;
  4.        char*dest = s;
  5.        int gotchar=0;
  6.        while((c=getchar())!='\n' && c!=EOF)
  7.        {
  8.            *dest++ = c;
  9.            gotchar++;
  10.        }
  11.       *dest = '\0';
  12.       if(c==EOF && !gotchar)
  13.           return NULL
  14.       return s;
  15.   }
  16. int hello()
  17. {
  18.      a[8];
  19.      gets(a);
  20.      return 0;
  21. }
在这里我们故意定义了一个只有8个元素的数组,在调用gets()函数时没有超出数组大小的提醒。这样超出数组大小的部分就会存放到临近数组空间的存储区。要是在这些临近空间存放了其它的数据的话就会被覆盖,我们可以将上面的C程序反汇编一下,看看在这些操作在栈中是如何实现的。
下面这段代码就是反汇编过后从中挑选出来的比较重要的几句代码:

  1. hello:
  2.   pushl %ebp
  3.   movl %esp,%ebp
  4.   pushl %ebx
  5.   subl $20,%esp
  6.   leal -12(%ebp), %ebx
  7.   movl %ebx,(%esp)
  8.   call gets
  9.   addl $20, %esp
  10.   popl %ebx
  11.   popl %ebp
  12.   ret
程序在将ebp于ebx存储到栈中后就开辟了一个20个字节的空间(第5行代码),然后第6行代码的意思是开辟数组的存储空间(开辟了8个字节,包括字符串结尾的null),首地址存放在ebx寄存器中。下面开始调用gets()函数。
可能看代码还不是很清楚,下面的是hello函数的帧栈示意图:

当我们输入的字符数不超过7个时,能够存放在a开辟的空间里,当超过时就会覆盖ebx中的甚至是ebp和返回地址的信息,破坏是积累的,随着输入字符数量的增加,破坏的状态越来越多。
如果破坏了返回地址的数据,则ret指令会使程序跳转到完全意想不到的地方。

缓冲区溢出攻击:
       通常,输入给程序一个字符串,这个字符串包含一些可执行的代码的字节编码(攻击代码),还有一些就是会用一个指向攻击代码的指针覆盖返回地址,这样,当执行ret指令时程序就会跳转到攻击代码。

阅读(473) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~