金丝雀字是位于缓冲区(例如堆栈)和程序中控制数据之间边界的位序列,作为检测缓冲区溢出并对其作出反应的一种方式。
这些金丝雀在 Linux 上通常有多少位?
金丝雀字是位于缓冲区(例如堆栈)和程序中控制数据之间边界的位序列,作为检测缓冲区溢出并对其作出反应的一种方式。
这些金丝雀在 Linux 上通常有多少位?
让我们试试吧!这是一个非常简单的示例程序。
int test(int a)
{
return a;
}
用GCC编译,在汇编阶段拦截编译。(-S
标志会这样做。)重命名程序集文件(这样它就不会被覆盖)并再次编译,这次还要添加-fstack-protector-all
和-mstack-protector-guard=global
标志。第一个标志为所有函数启用堆栈金丝雀,第二个标志选择全局金丝雀而不是线程本地的。(线程本地默认值在实践中可能更有用,但全局版本的程序集更容易理解。)
比较两个生成的程序集文件,我们发现了以下添加(评论是我的)。
movl %edi, -20(%rbp) ; save function parameter onto stack (unrelated to canary)
movq __stack_chk_guard(%rip), %rax ; load magic value into RAX register
movq %rax, -8(%rbp) ; save RAX register onto stack (place the canary)
movl -20(%rbp), %eax ; load function parameter into EAX register for return (unrelated to canary)
movq -8(%rbp), %rcx ; load canary value into RCX register
movq __stack_chk_guard(%rip), %rdx ; load magic value into RDX register
cmpq %rdx, %rcx ; compare canary value to expected value
je .L3 ; if they are the same, jump to label .L3 (continue)
call __stack_chk_fail ; otherwise (stack corruption detected), call the handler
.L3:
leave
我们可以看到金丝雀是在 RAX、RCX 和 RDX 寄存器中处理的,它们都是 64 位宽的。(它们的 32 位对应物将被命名为 EAX、EBX 和 EDX。16 位版本被命名为 AX、BX 和 CX。8 位变体 AL、BL 和 CL。)另一个线索是存储、加载和比较canary(MOVQ 和 CMPQ)有一个“Q”后缀,用于标识 64 位指令。(32 位指令具有“L”后缀,16 位指令具有“W”后缀,8 位指令具有“B”后缀。)
因此,我们得出结论,金丝雀是一个 64 位的值,这在 64 位架构(在我的例子中是 x86_64 GNU/Linux)上是有意义的。我希望他们将始终使用本机字号,因为这对我来说最有意义。你可以在你的机器上尝试同样的实验,看看你会得到什么。
正如我在本页中看到的那样:堆栈粉碎保护器
堆栈金丝雀是原生字大小的,如果随机选择,攻击者将不得不在 2^32 或 2^64 组合中猜测正确的值
使用的位数必须等于处理器的字大小。所以如果你有一个 32 位处理器,它的字大小是 32,因此金丝雀字是 32 位长。