堆栈保护和堆栈粉碎保护 - 金丝雀,内存



我有几个关于堆栈保护和SSP保护的问题。第一个问题是关于堆栈守卫及其三种类型的金丝雀,如果我没猜错的话 - 终结者、随机和随机 XOR。

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

  2. 关于堆栈保护的下一个问题,当我能够启用/禁用它时,如何设置,我想使用哪种类型的金丝雀?我读到的,默认情况下使用终结者金丝雀,对于随机我必须用-enable-stackguard-randomization编译,但是随机异或呢?(或空0x00000000)

  3. 现在关于SSP(ProPolice),我知道,对于随机金丝雀,我必须用fstack-protector-all编译,但是终止符呢,默认情况下它和堆栈守卫一样吗?

  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地址。

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 的函数中生成的。以下是其代码的某些部分:

  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由内核初始化,因此至少复制 7 个有效字节的AT_RANDOM。金丝雀的最后一个字节设置为零。

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

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

现在关于SSP(ProPolice),我知道,对于随机金丝雀,我必须编译 使用"fstack-protector-all",但是终结者呢,它和 默认情况下,在堆栈保护中?

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

最后一个,如果你们中有人,可以告诉我,我在哪里可以找到随机 记忆中的金丝雀。

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

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;
}

最新更新