AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > VC编程

VC++中利用/GS开关防止缓冲区溢出

51自学网 2015-08-30 http://www.wanshiok.com

  防范缓冲区溢出

  防范缓冲区溢出最简单的方式是限制复制的数据大小,使其不能大于目标缓冲区容量。虽然此方法看上去微不足道,但实际上,经验证明,要在那些大型的C/C++代码中,完全消除了缓冲区溢出的隐患,是件非常艰巨的任务。另外,使用如 .NET或Java这样的受托管技术,也能极大地降低缓冲区溢出的危险,但把大型项目移植到此技术上,实施起来不太可能也不适当。

  基于堆栈的缓冲区溢出可如此简单地被利用的原因在于,编译器生成的指令,会把函数的返回地址存储在堆栈中,但要认识到,编译器在这个问题中,只扮演了一个小小的角色。从Visual C++.NET(7.0)开始,Visual C++开发小组采取了一种方法,可从编译器方面减少此类问题发生的机率,他们在堆栈中保存函数返回地址的数据之下,插入了一个带有已知数值的cookie,由此,如果缓冲区溢出改变了函数的返回地址值,同样也会覆盖这个cookie,而在函数返回时,一般会对这个cookie进行检测,如果检测到cookie已被修改,就会抛出一个安全异常,而如果这个异常未被处理,此进程就会终止。以下的代码演示了一个带有安全异常处理方法的简单程序:

void _cdecl sec_handler( int code, void *)
{
 if ( code == _SECERR_BUFFER_OVERRUN )
 {
  printf("检测到一个缓冲区溢出。/n");
  exit(1);
 }
}

int main()
{
 _set_security_error_handler( sec_handler );
 //主程序代码在此省略。
}

  Visual C++.NET 2003(7.1)通过移动易受攻击的数据结构--(如异常处理方法的地址)--到堆栈中位于缓冲区之下的某个位置,增强了缓冲区溢出的保护力度。在编译器的7.0版本中,可通过破坏缓冲区与cookie之间的敏感数据,绕过安全cookie所提供的保护;然而,在新版本的编译器中,已把这些数据移到位于缓冲区下的一个区域,现在,想要通过修改这些数据而达到溢出,似乎是不太可能了。

  图1演示了在C++编译器6、7.0、7.1中,堆栈概念上的布局,并演示了堆栈由高地址向低地址空间方向增长,这也是当程序执行时,堆栈增长的方向。堆栈向下增长,正是导致缓冲区溢出的主要原因,因为溢出会覆写在比缓冲区更高的内存地址空间上,而此正是易受攻击数据结构的栖身之地。


图1:堆栈逻辑布局

  除了把异常处理方法等信息移到堆栈中数据缓冲区之下,Visual C++.NET 2003的链接器也把结构化异常处理方法的地址放到可执行文件的头部中。当异常发生时,操作系统可以检查堆栈中的异常信息地址,是否符合记录在文件头信息中的异常处理方法,如果情况不符,异常处理方法将不会执行。比如说,Windows Server 2003就可检查结构化异常信息,而此项技术也在Service Pack 2中移植到了Windows XP上。

  而Visual C++ 2005(8.0)在此基础上又更进了一步,通常当有函数调用发生时,如果其中的一个本地缓冲区超出限度了,攻击者可能改写堆栈中在此之上的任何东西,包括异常处理、安全cookie、帧指针、返回地址和函数参数。而这些值的大多数被不同的机制所保护(如安全异常处理),但对一个有函数指针作参数的函数来说,仍有机会被溢出。如果一个函数接受一个函数指针(或结构、类中包含有函数指针)作为参数,攻击者就有可能改写指针中的值,使代码执行任何他想要的函数。鉴于此,Visual C++ 2005编译器将分析所有可能存在此漏洞的函数参数,并复制一份函数参数--并不使用原有的函数参数,把它放在堆栈中本地变量之下。如果原有函数参数被溢出改写了,只要副本中的值仍保持不变,整个函数就不会被攻破。

 
 
说明
:本教程来源互联网或网友上传或出版商,仅为学习研究或媒体推广,wanshiok.com不保证资料的完整性。

上一篇:在应用程序中播放声音资源文件  下一篇:用Visual C++实现PDF文件的显示