1 内存分配
一个C/C++编译的程序所占用的系统内存一般分为以下5个部分的内容:
2 内存泄露
内存泄露一般是指未释放已经不再使用的先前申请的堆内存。
也就是在使用malloc或new申请了堆内存后,在适当的时机需要使用相应的free或delete来释放不再需要的堆内存,否则会形成内存泄露。
3 缓冲区溢出
缓冲区是程序运行的时候机器内存中的一个连续块。
缓冲区溢出是指当向缓冲区内填充数据位数超过了缓冲区自身的容量限制时,发生的溢出的数据覆盖在合法数据(如数据、下一条指令的指针、函数返回地址等)上的情况。
缓冲输入,将若干内容先存储到称为缓冲区(buffer)的临时存储区域,等待适当时机将缓冲区内的内容变得对程序可用,非缓冲输入是不使用缓冲区,直接让输入对程序可用。缓冲输入对于频繁读写有更高的效率,而非缓冲输入是即时交互程序所需要的。
最好的情况是程序不允许输入超过缓冲区长度的字符并检查数据长度,由于大多数程序都会假设数据长度总是与所分配的储存空间相当,进而存在缓冲区溢出安全隐患。
例如下面的小程序:
#include void test(){char buff[4];printf("some input:");gets(buff);puts(buff);}int main(){test();return 0;}
该程序的test()函数中使用了标准的C语言输入函数gets(),由于它没有执行边界检查,最终会导致Test函数存在缓冲区溢出安全漏洞。
test()函数的缓冲区最多只能容纳3个字符和一个空字符,所以超过4个字符就会造成缓冲区溢出。
该程序的堆栈说明如下图所示:
如果输出3个字符“abc",buff[4]正好被3个字符和NULL填充:
如果输入5个字符“abcde“,%edp的一些区域的内容将被覆盖,造成缓冲区溢出:
人为的缓冲区溢出一般是由于攻击者写一个超过缓冲区长度的字符串植入到缓冲区,然后再向一个有限空间的缓冲区中植入超长的字符串,这时可能会出现两个结果:一是过长的字符串覆盖了相邻的存储单元,引起程序运行失败,严重的可导致系统崩溃;另一个结果就是利用这种漏洞执行任意指令,甚至取得系统的root特级权限,进而危害系统安全。
补充:数据在栈中的存储方式
先看下面的代码:
#include int main(){int i=0;int a[]={1,2,3,4,5};for(i=0;i<=5;i++){a[i]=0;printf("%d