内存越界访问和缓冲区溢出

内存越界访问: c对于数组指针引用不进行任何边界检查,且局部变量和状态信息都存放在栈中。此两种情况结合在一起可能导致严重的程序错误,对越界的数组元素的写操作会破坏存储在栈中的状态信息。当程序使用这个被破坏的状态,试图重新加载寄存器或执行ret指令,就会出现严重的错误。

缓冲区溢出: 一种常见的破坏状态。例如:在栈中分配某个字符数组来保存一个字符串,但是字符串的长度超过了为数组分配的空间。
程序举例:

//库函数gets()的实现
char *gets(char *s)
{
	int c;
	char *dest=s;
	//从标准输入读入一行,在遇到一个回车换行字符或某个错误情况时停止
	while((c=getchar())!='\n' && c!=EOF)
	{
		*dest++=c;
	}
	//将字符串复制到参数s指明的位置后,在字符串的末尾加上NULL字符
	if(c==EOF && dest==s)
	{
		retuen NULL;
	}
	*dest++='\0';
	return s;
}
//从标准行输入中读入一行,再将其送回到标准输出
void echo()
{
	char buf[8];//设置8字节的缓冲区,任何长度超过7个字符的字符串都会导致写越界
	gets(buf);
	puts(buf);
}

gets()函数的问题是无法确定是否为保存整个字符串分配了足够的空间。

echo的汇编代码:

void echo()
echo:
	subq	$24,%rsp
	movq	%rsp,%rdi
	call	gets
	movq	%rsp,%rdi
	call	puts
	addq	$24,%rsp
	ret

该程序在栈上分配了24个字节,字符数组buf位于栈顶,%rep被复制到%rdi作为调用gets和puts的参数。调用的参数和存储的返回指针之间的16个字节未被使用,根据用户输入字符大小,可得到一下表格:
内存越界访问和缓冲区溢出_第1张图片
如果存储的返回地址的值被破坏了,那么ret指令会导致程序跳转到一个意想不到的位置,会出现缓冲区漏洞。有时会使程序执行它本来不愿意执行的函数,从而对计算机网络系统进行攻击。

参考资料:《深入理解计算机系统》

你可能感兴趣的:(C语言)