科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件运行时和编译时的安全性检查 /RTC

运行时和编译时的安全性检查 /RTC

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

运行时和编译时的安全性检查 /RTC

作者:Microsoft Corporation 来源:Microsoft 开发人员网络 2007年10月28日

关键字: RTC Linux

  • 评论
  • 分享微博
  • 分享邮件

RTC 表示运行时检查。RTC 有若干子选项。与 /GS 不同,/RTC 设计用于调试版本,而不用于优化代码。与 /GS 相同的是,如果您不喜欢默认对话框,可以编写自己的处理程序。

使用 Microsoft® Visual Studio® 调试应用程序时,RTC 对话框可以为您提供在错误发生之处调试应用程序的选项。此外,还可以在 Visual Studio 中创建若干个配置,每个配置都包含各种选项的不同组合,例如,对发布版本使用 /GS 选项,而对调试版本使用一个或多个 /RTC 选项。

/RTCs - 堆栈帧运行时错误检查

此选项在保护堆栈不被破坏方面采取了若干措施。

  • 在每次调用函数时,将所有局部变量初始化为非零值。这样可以防止以前的调用对堆栈中的值的无意使用。

  • 验证堆栈指针能够检查到堆栈破坏,例如,在一个位置将函数定义为 __stdcall,而在另一个位置将函数定义为 __cdecl 可导致堆栈破坏。

  • 检测局部变量的溢出和不足。这与 /GS 不同,因为它仅适用于调试版本,并且检测缓冲区的两端以及所有缓冲区是否遭到破坏。

cl /Od /MLd /ZI /EHsc /RTCs GS-RTC.cpp

此命令将关闭优化 (/Od),并设置 _DEBUG 预处理器定义。

使用此命令编译样例后,请再次尝试运行 测试 1。此时它将会捕捉到覆盖操作。

测试 2 说明了不包括返回地址的堆栈溢出:

void Test2()
{
   char buffer1[100];
   char buffer2[100];
   buffer1[0] = 0;
   for (int i=0 ; i <= sizeof(buffer2); i++)
   {
      buffer2[i] = 'a';
   }
   buffer2[sizeof(buffer2)-1] = 0;
   cout << buffer2 << '-' << buffer1 << endl;
}

此循环使 buffer2 溢出一个字符,因为它使用 <= 代替了 <。它将覆盖 buffer1 的第一个字符。使用 /RTCs 编译器开关进行编译并使用 gs-rtc 2 运行时,系统将显示下面的对话框:

securitychecks03

3. 使用 gs-rtc 2 选项时生成的错误。

测试 3 对缓冲区不足进行了说明:

void Test3()
{
   char buffer1[100];
   char buffer2[100];
   memset(buffer1,'a',sizeof(buffer1)-1);
   buffer1[sizeof(buffer1)-1]=0;
   memset(buffer2,'b',sizeof(buffer2)-1);
   buffer2[sizeof(buffer2)-1]=0;
   *(buffer1-1) = 'c';
   cout << buffer1 << endl;
   cout << buffer2 << endl;
 }

(要运行测试 3,请使用命令“gs-rtc 3”。)在本例中,buffer2 的最后一个字节被覆盖,并且对话框将显示 buffer1 出现的问题。如果不进行运行时检查,此测试的输出结果为:

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbcaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

由于这一写入操作破坏了 buffer2 的终止符,因此,所有将 buffer2 用作空结束字符串的操作都将获得一个长度为期望值两倍的字符串。

测试 4 显示了 /RTCs 选项如何将未初始化变量设置为“标志”值:

void Test4()
{
   unsigned int var;
   cout << hex << var;
}

在使用 /RTCs 编译之后运行 测试 4时,将得到十六进制值 cccccccc。如果不使用 /RTCs 进行编译,将得到堆栈中剩余的随机值。

/RTCc - 检测导致数据丢失的分配

此选项将插入代码,以便在分配导致数据丢失时向您发出警报,这样可以确保在转换为较小类型时从不丢失数据。测试 5 说明以下内容。

void Test5(int value)
{
   unsigned char ch;
   ch = (unsigned char)value;
}

请执行以下命令来编译此代码:

cl /Od /MLd /ZI /EHsc /RTCc GS-RTC.cpp

请在命令提示符处使用其他数字来运行此命令。例如,此命令将触发错误:

gs-rtc 5 300

securitychecks04

4. /RTCc 开关中使用大于 255 的数值时所生成的错误。

无符号字符最多可容纳 255 个字符,因此向程序中输入 300 将导致数据丢失。使用 gs-rtc 5 200 再次运行命令,此时将不会出现错误。

如果要转换为较小类型,并要故意丢失上面的数位,则可以使用如下所示的掩码:

   ch = (unsigned char)(value & 0xFF);

/RTCu - 报告使用了未初始化的变量

当访问未初始化的变量时,此选项将会发出警告。测试 6 包含三个子测试,代码如下:

void Test6(int value)
{
   int uninitialized;
   int var;
   switch (value) {
      case 3:
         uninitialized = 4;
      case 2:
         var = 5 * uninitialized;
         break;
      case 1:
         int *var2;
         var2= &uninitialized;
         var = 5 * uninitialized;
         break;
   }
}

(请注意,执行 case 3 中的语句后,程序将直接转到 case 2 中执行。)使用以下命令编译此代码:

cl /Od /MLd /ZI /EHsc /RTCu GS-RTC.cpp

运行 gs-rtc 6 2 时,系统将显示以下对话框:

securitychecks05

5. 使用 gs-rtc 6 2 时所生成的错误

运行 gs-rtc 6 3 时,系统将不显示对话框,因为变量已被初始化。"但是,即使使用了未初始化的变量,gs-rtc 6 1 也不会出现错误,因为编译器不跟踪可以通过指针来初始化的变量。

查看本文来源
    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章