正文

使用 Visual C++ 2005 的现代语言功能编写更快的代码(4)2005-12-07 10:32:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/ainterly/7918.html

分享到:

安全性

在 2002 年,Bill Gates 发出了可信任计算 (Trustworthy Computing) 倡议,这对 Microsoft 开发的所有产品都有着不可小视的冲击力。Windows 操作系统的开发人员在安全性培训和代码评审上花费了几个月的时间,这使得 Windows Server 2003 成为该公司曾经发布过的安全性最高的一个操作系统。Microsoft Office 2003 还包含了许多安全功能,例如 Information Rights Management (IRM)、更好的宏安全性和在 Outlook 中阻止 HTML 下载等等。而编译器小组也在大踏步地使他们开发的编译器及其生成的代码变得更安全。

Visual Studio .NET 2002 引入了缓冲区安全检查 /GS 编译器选项。这一标志将导致编译器在决定为有缓冲区溢出攻击嫌疑的函数返回地址之前就预先在堆栈上分配空间。在函数进入时,一个带有已知计算值的安全 Cookie 会被放在这个缓冲区中,而在函数退出时,编译器会对其进行检查,以确保该 Cookie 没有被破坏。对 Cookie 值的更改意味着有重写返回地址的可能性,而这会产生一个错误并导致应用程序终止。

当然,这并不能防止所有的缓冲区溢出攻击。Visual Studio .NET 2003 还增强了 /GS 功能。它通过对堆栈上的局部变量进行排序来将数组分配在高于其余局部变量的内存地址上,从而防止这些局部变量造成溢出。这样会阻止基于 vtable 入侵的攻击和其他基于指针的攻击。


7 原来的 /GS

Visual C++ 2005 对这一强大的功能进行了又一次升级。当进行函数调用时,函数的激活记录按照如 7 所示的方式放置。如果一个局部缓冲区发生了溢出,黑客就有可能重写其堆栈上的所有内容,其中包括异常处理函数记录、安全 cookie、帧指针、返回地址,以及函数的参数。这些值中的大多数都是通过各种机制保护的(例如安全异常处理),然而,在一个以函数指针作为参数的函数中,利用缓冲区溢出仍有可能。如果一个函数将函数指针(或者一个包含函数指针的结构或类)作为参数,黑客就可能会重写这一指针的值,并使代码执行任何他/她想要运行的函数。为了防止这一点,Visual C++ 2005 编译器会分析所有的函数参数来防止这一漏洞,并如 8 所示放置函数激活记录。那些易受攻击的参数会在堆栈的局部变量下创建副本,然后使用这些副本而不是参数本身。缓冲区溢出可能会重写原始值,但是它们不会被利用,因为正在使用的副本仍然保持原始值。


图 8 新的 /GS

与“secure by default”可信任计算指令相一致的是,Visual C++ 2005 编译器现在默认支持缓冲区安全检查选项。这会有助于使所有用 Visual C++ 编译的产品更加安全。实际上,Microsoft 现在正在用这个已经启用的选项来构建它的所有产品,其中包括 Windows、Office 和 SQL Server。

Visual C++ 2005 在其他方面的进步就是确保代码是以考虑安全性为前提开发的。绝大多数 C++ 应用程序都依赖于 C 运行时库 (CRT) 和标准模板库 (STL)。这些库在最初设计时,代码安全性不具有高的优先级,而许多现在普遍使用的攻击也不存在。这样做的结果是,许多由这些库提供的功能常常以一种不安全的方式被使用,从而使得应用程序暴露在一些潜在的攻击之下。最近出版的书籍(如 Michael Howard 撰写的 Writing Secure Code (Microsoft Press,2002 年)中,都强调了某些编码实践的重要性,这些实践都不以这些库为例。

在 Visual C++ 2005 中,Microsoft 推出了经过重新编写的这些库的新版本,它致力于找出所有可能导致一般安全问题的函数,并提供一些更安全的替换版本。这项工作的长远目标是弃用所有“不安全”的版本,而提倡使用一些具有相同功能但更加健壮的版本。单单是 CRT 的这个新版本,就引入了超过 400 个新的“安全”函数,从而可以确保检查所有的指针参数是否为空值,并且所有进行内存复制操作的函数除了知道目的缓冲区和源缓冲区之外,还要知道需要复制多少字节的数据。

返回页首返回页首

小结

Visual C++ 2005 的新功能还有很多,难以在此一一详述:混合映像的延迟 CLR 加载、本机 AppDomains API、为在 AppDomains 和进程方面提供更好的全局变量支持而引入的新的声明规范、模块构造函数、为对象文件和 .NET 模块提供的链接器支持、隐式装箱、使用与 C# 开发人员所喜爱的语法一样的 XML 注释、全新的面向 .NET 框架的 STL 版本、参数数组、别名提示、新的浮点模型、运算符重载等等。

任何基于 .NET 框架的语言的新版本经常让人们想问“如果我们的开发小组想要编写一个面向 .NET 的应用程序,应该使用哪一种语言?”现在,如果您正在做许多本机 Interop 工作,那么很简单。C++ 是开发本机 Interop 最易于使用的语言,而且它常常具有最佳的性能。此外,如果您想要将现有的 C++ 应用程序转到 .NET 上,那就的确没有更好的选择了。实际上,当您把现有的应用程序转化为 .NET 框架时,使用 Visual C++ 是 Microsoft 极力推荐的一条途径。

至于新的应用程序,您或许会问,为什么不熟悉 .NET 的开发人员选择一种语言而不选择另一种语言。由于每种语言都有其优势,所以无法对这个问题作出简单的回答,但对于纯基于 .NET 的应用程序而言,C#、Visual Basic 和 C++ 中的体验基本相同。如果您作为一个开发人员已经习惯于使用某种特定的语言,就没有什么重要的原因要转向使用另外一种语言了。

但如果您正在开发某种 Interop,您也许会选择 C++ 语言而不是其他。使用 C++ 体验肯定要好于其他的语言,因为在 C++ 中直接内置了范围广泛的 Interop 支持。此外,它通过析构函数提供的确定性清除功能在消除资源泄漏和确保应用程序的正确性时简直就是无价之宝。C++ 还有许多强大的功能可以与 CLR 提供的功能联合使用。例如,C++ 不仅支持模板和泛型,而且还支持它们的组合。这比单独使用其中任何一个功能更富有表现力,也更为强大。尤其有用的一个库编写技术是编写实现一般接口的模板。这会为您的模板提供所有的灵活性和强大的功能(例如专用化),而它仍会让其他语言有通过一般接口直接使用从模板实例化的对象的能力。总而言之,C++ 的确找到了属于自己的位置。

阅读(3487) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册