用于C代码的x86反汇编生成:orq $ 0x0,%rsp

问题描述

我编写了以下C代码:

enter image description here

它只是分配一个包含1000000个整数和另一个整数的数组,并将该数组的第一个整数设置为0

我使用gcc -g test.c -o test -fno-stack-protector

对此进行了编译

它给出了一个非常奇怪的反汇编:

enter image description here

显然,它一直在循环中在堆栈上分配4096个字节,并且在第4096个字节中用0或“或”,然后达到3997696字节后,再分配2184字节。然后,它将第4000000个字节(从未分配过)设置为5。

为什么不分配请求的全部4000004字节?为什么它用0来“或”第4096个字节,这是无用的指令?

我在这里理解不对吗?

注意:这是用cc版本9.3编译的。 gcc版本7.4不会执行循环并“或”每个第4096个字节为0,但仅分配3997696 + 2184 = 3999880字节,但仍将第4000000个字节设置为5

解决方法

这是对 Stack Clash 类漏洞的缓解,该漏洞自90年代或更早就已知,但仅在2017年得到广泛宣传。(请参阅stack-clash.txtthis blog entry。)

如果攻击者可以安排执行具有攻击者控制大小的VLA的功能,或者可以在攻击者控制其他某些地方已使用的堆栈量时安排执行具有固定大小大数组的功能来执行这样,它们可以使堆栈指针被调整为指向其他内存的中间,从而导致函数破坏该内存,通常导致任意代码执行。

此处发出的机器代码GCC是堆栈冲突保护功能的一部分。通过(大约)每次将堆栈指针调整到大于最小页面大小,一次将其递增移动一个最小页面大小的单位,并在每次调整后访问内存,可以降低风险。这样可以确保,如果存在至少一个保护页面(页面映射的PROT_NONE),则在进行不相关存储器的调整之前,访问将出错并生成信号。主线程总是有保护页,默认情况下,新创建的保护页也有(可以在pthread线程创建属性中配置大小)。

,

这里有两件事:

  • 将“无操作” ORs read write 写入堆栈的每个页面。这些是必需的,因为通常会映射堆栈,以便在堆栈下方有一个保护页 /页面。触摸保护页面后,堆栈将向下扩展。但是,如果您触摸保护页面下方的内存,则会发生SIGSEGV。

  • x86-64 System-V ABI在堆栈指针下面指定了128-byte red zone 。编译器也可以自由使用该区域来存储局部变量。如果将128加到3997696,将得到4000008。请注意,堆栈将始终必须至少对齐8,而不是4,以便任何int64_t或double都将对齐(如Peter Cordes所述,较大的数组需要是16字节对齐的,因此也要求整个堆栈也必须是16字节对齐的),所以40000004肯定是错误的!

,

我遇到了同样的问题,唯一可以禁用这个“奇怪”汇编代码的标志是 -fno-stack-clash-protection

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...