堆砸不火.为什么

  • 本文关键字: c++ c glibc stack-smash
  • 更新时间 :
  • 英文 :


我正在尝试让 glibc 检测堆栈粉碎,我使用以下代码:

 #include <stdio.h>
 #include <string.h>
 static const int n = 5;
 int main(int argc, char *argv[])
 {
  if (argc != 2)
  {
     printf("usage: %s stringn", argv[0]);
     return -1;
  }
  printf("%s, len = %dn", argv[1], strlen(argv[1]));
  unsigned char a[n][n];
  unsigned char * b = a[n - 1];
  memcpy(b, argv[1], (strlen(argv[1]) + 1) * sizeof(unsigned char));
  return 0;
 }

如果 argv[1] 长度大于 5,我希望检测到堆栈粉碎错误,但是,我没有,并且 valgrind 没有检测到错误。我应该更改什么才能得到此错误?(数组 A 必须是二维的)

默认情况下,GCC 仅在您执行特别危险的事情(如 alloca(或 gets,如您在注释中提到)或声明大型自动数组时添加代码来检测堆栈粉碎。

如果要为所有功能启用保护,请使用-fstack-protector-all选项。您还可以使用 -Wstack-protector 请求有关未受保护函数的警告。

似乎 gcc 中决定何时启用堆栈保护的逻辑有点棘手。文档中的第一个注释:

-堆叠保护器

发出额外的代码以检查缓冲区溢出,例如堆栈粉碎攻击。这是通过向具有易受攻击对象的函数添加保护变量来完成的。这包括调用 alloca 的函数,以及缓冲区大于 8 个字节的函数。在进入函数时初始化防护,然后在函数退出时检查。如果防护检查失败,则打印错误消息并退出程序

因此,我们应该期望本地缓冲区小于 8 字节的函数不受保护。例如,这个:

int unprotected() {
    char a[5];
    strcpy(a, "this is much too long");
    return a[0];
}

gcc -fstack-protector -Wstack-protector编译,给出一个警告,如

警告:堆栈保护器

不保护功能:所有本地阵列的长度都小于 8 字节 [-堆栈保护器]

因此,您可能会认为您的char[5][5]将受到保护,因为它的长度超过 8 个字节。但是,当我将其编译为汇编程序时,我没有得到任何警告堆栈保护(您可以在这篇Dr. Dobbs文章中找到要查找的汇编程序)。似乎 gcc 将其视为 5 个缓冲区,每个缓冲区 5 个字节,而不是一个 25 字节的缓冲区。

您可以说服 gcc 启用堆栈保护,方法是向它显示一个大于 8 字节的缓冲区:

void protected(char *arg) {
    union {
        char dummy[5 * 5];
        char a[5][5];
    } u;
    memcpy(u.a[4], arg, (strlen(arg) + 1));
}

或者简单地使用 -fstack-protector-all .

相关内容

  • 没有找到相关文章

最新更新