我有几个关于堆栈保护和SSP保护的问题。第一个问题是关于堆栈守卫及其三种类型的金丝雀,如果我没猜错的话 - 终结者、随机和随机 XOR。
-
我想知道,如何在x86 Linux系统上禁用Stack Guard?我读到的某处,可以使用此命令,同时使用 gcc
-disable-stackguard-randomization
进行编译,这与启用-enable-stackguard-randomization
的此命令相同,两者都不起作用。如果需要,我的 gcc 版本是 4.8.2。 -
关于堆栈保护的下一个问题,当我能够启用/禁用它时,如何设置,我想使用哪种类型的金丝雀?我读到的,默认情况下使用终结者金丝雀,对于随机我必须用
-enable-stackguard-randomization
编译,但是随机异或呢?(或空0x00000000) -
现在关于SSP(ProPolice),我知道,对于随机金丝雀,我必须用
fstack-protector-all
编译,但是终止符呢,默认情况下它和堆栈守卫一样吗? -
最后一个,我在哪里可以找到内存中的随机金丝雀?例如,我有这样的场景 - 编译 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地址。
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;
}