【问题标题】:Stack Guard and Stack Smashing Protection - canaries, memoryStack Guard 和 Stack Smashing Protection - 金丝雀,内存
【发布时间】:2015-01-18 20:47:46
【问题描述】:

我有几个关于 Stack Guard 和 SSP 保护的问题。第一个问题是关于 Stack Guard 及其三种类型的金丝雀,如果我没记错的话——终结者、随机和随机 XOR。

  1. 我想知道,如何在 x86 Linux 系统上禁用 Stack Guard?在我读到的某处,可以使用此命令,在使用 gcc '-disable-stackguard-randomization' 进行编译时,与启用 '-enable-stackguard-randomization 的命令相同strong>',两者都不起作用。如果需要,我的 gcc 版本是 4.8.2。

  2. 下一个关于 Stack 保护的问题,什么时候可以启用/禁用它,如何设置,我想使用哪种类型的金丝雀?我读到的,默认使用终结器金丝雀,对于随机我必须使用'-enable-stackguard-randomization'进行编译,但是随机异或呢? (或使用 null 0x00000000)

  3. 现在关于 SSP(ProPolice),我知道,对于随机金丝雀,我必须使用 'fstack-protector-all' 进行编译,但是终止符怎么样,它与 Stack 中的一样吗守卫,默认?

  4. 最后一位,如果你们中的任何人,可以告诉我,我可以在内存中找到随机金丝雀的位置。例如,我有这种情况 - 编译的 C 程序,如 'gcc -g example.c -o example -fstack-protector-all',所以使用随机金丝雀。比方说,每次执行后我都能获得金丝雀的地址。所以期待,我有:Canary = 0x1ae3f900。从不同的论文中,我得到了一些信息,金丝雀位于 .bss 段中。所以我使用 readelf 获得 .bss 段的地址:'readelf -a ./example | grep bss'。它是 080456c9。在 gdb 中我设置了一些断点,以获取金丝雀的地址,但是当我检查 .bss 地址 x/20x 0x080456c9 时,我看到的只是 0x00000000 地址,但是 金丝雀无处可去。另外,我检查了 __stack_chk_fail 是否不存在,但结果相同,我在那里看不到它。我从 PLT/GOT 得到 stack_chk_fail 的地址。

提前感谢您的回答和时间。

【问题讨论】:

标签: gcc random linux-kernel x86 protection


【解决方案1】:

Stack Smashing Protection (SSP) 是对 StackGuard 的改进。 SSP 最早是在 gcc 4.1 中实现的。

我想知道,如何在 x86 Linux 系统上禁用 Stack Guard?

使用 -fno-stack-protector 禁用用户态 SSP。

--disable-stackguard-randomization--enable-stackguard-randomization 是 glibc 源代码的构建选项。

什么时候可以启用/禁用它,我该如何设置,哪种类型 我想使用金丝雀?

据我所知,这在 gcc 中是不可配置的。从 glibc 2.10 开始,堆栈金丝雀是在一个名为 _dl_setup_stack_chk_guard 的函数中生成的。这是its code的一部分:

  if (dl_random == NULL)
    {
      ret.bytes[sizeof (ret) - 1] = 255;
      ret.bytes[sizeof (ret) - 2] = '\n';
    }
  else
    {
      memcpy (ret.bytes, dl_random, sizeof (ret));
      ret.num &= ~(uintptr_t) 0xff;
    }

dl_random 保存了AT_RANDOM 的辅助向量入口地址,它是内核在创建进程时初始化的一个 16 字节随机值。如果您在未初始化 AT_RANDOM 的内核或模拟器上运行,则检查 dl_random == NULL 将为真,并且使用的金丝雀是终止符值,其中第一个和第二个最高有效字节初始化为 255 和 \n , 分别。所有其他字节为零。通常AT_RANDOM 由内核初始化,因此AT_RANDOM 的最低7 个有效字节被复制。 canary 的最后一个字节设置为零。

所以如果你想使用特定的方法来生成金丝雀,你可以更改这段代码并构建你自己的 glibc。

作为一种替代方法,@PeterCordes 在 cmets 中建议将您的金丝雀值写入内存位置 %%fs:0x28(参见下面的代码)在 main 函数的顶部并恢复运行时生成的金丝雀之前从main返回。

现在关于 SSP(ProPolice),我知道,对于随机金丝雀,我必须编译 使用“fstack-protector-all”,但是终结器怎么样,是否与 在 Stack Guard 中,默认情况下?

-fstack-protector 选项的所有变体都使用 SSP。这些不会影响金丝雀的生成方式。

最后一位,如果你们中的任何人,可以告诉我,我在哪里可以找到随机的 内存中的金丝雀。

金丝雀在进程启动早期动态生成;你不能使用readelf 来获取金丝雀。根据this的文章,i386编译时可以使用以下代码获取canary:

int read_canary()
{
  int val = 0;
  __asm__("movl %%gs:0x14, %0;"
          : "=r"(val)
          :
          :);
  return val;
}

对于 x86_64:

long read_canary()
{
  long val = 0;
  __asm__("movq %%fs:0x28, %0;"
          : "=r"(val)
          :
          :);
  return val;
}

【讨论】:

  • 您可以更改此代码并构建您自己的 glibc。 或者可能只是写到 main 顶部的 %%fs:0x28,并在返回之前恢复原始金丝雀值以防万一main 本身或任何 CRT 启动函数都使用了堆栈保护。或者调用exit 而不是让main 返回,这样你就不需要恢复旧的堆栈金丝雀。 IDK 如果异常可以通过 main 展开并导致堆栈保护器检查失败,但可能不是因为任何顶级异常捕获都可能中止而不是返回。
  • 如果你调用exit而不是从main返回,你不需要恢复旧的堆栈金丝雀。无法访问main 的堆栈cookie 检查代码(也不会使用其返回地址)。所以调用exit 简化了main
猜你喜欢
  • 1970-01-01
  • 2012-04-19
  • 2016-10-04
  • 2012-04-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多