You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

GCC栈金丝雀(stack canary)位置存在差异的原因是什么?

栈金丝雀位置差异的原因说明

你观察到的金丝雀位置不同是正常现象,主要由三类编译相关因素决定:

  • 目标架构差异:你给出的第一个反汇编片段是32位x86程序,默认使用ebp作为栈帧基址,32位模式下GCC默认会把金丝雀放在ebp和栈上缓冲区之间,也就是地址低于ebp的位置(对应示例中的ebp-0xc),这种布局下要覆盖ebp必须先覆盖金丝雀,可以同时保护帧指针和返回地址。你看到的第二种金丝雀在rbp+8之后的场景属于64位x86_64程序的栈布局,部分编译配置下金丝雀会放在更靠近返回地址的高地址侧,仅覆盖返回地址的保护范围,帧指针不在其保护范围内,因此攻击者可以在不触碰金丝雀的前提下覆盖rbp。
  • 栈保护级别参数差异:GCC提供了多档栈保护参数,不同参数下金丝雀的插入逻辑不同:
    • -fstack-protector:发行版默认级别,仅对存在字符数组的函数开启保护,保护目标仅为返回地址
    • -fstack-protector-all:对所有函数的栈结构开启保护
    • -fstack-protector-strong:保护范围介于前两者之间,覆盖更多存在栈溢出风险的场景
      当仅开启默认的-fstack-protector时,GCC不需要保护帧指针,会直接把金丝雀放在返回地址和缓冲区之间,不会放在缓冲区和rbp之间,就会出现你观察到的现象。
  • 帧指针优化的影响:64位模式下编译时如果开启了-fomit-frame-pointer优化(多数发行版O2及以上优化级别默认开启),rbp不再作为栈帧基址,而是被当作通用寄存器使用,栈布局会完全调整,金丝雀的位置也不再围绕rbp排布。

补充

第二种场景下虽然攻击者可以不触发栈检查就覆盖帧指针,但要完成控制流劫持依然需要覆盖返回地址,还是会触发金丝雀校验,不会直接导致栈保护失效。

你给出的32位反汇编示例对应代码如下:

0x080484e0 <+52>: mov eax,DWORD PTR [ebp-0xc]
0x080484e3 <+55>: xor eax,DWORD PTR gs:0x14
0x080484ea <+62>: je 0x80484f1 <func+69>
0x080484ec <+64>: call 0x8048360 <__stack_chk_fail@plt>

内容的提问来源于stack exchange,提问作者Aaa Bbb

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.24 17:06:04