繁体   English   中英

x86 反汇编为 C 代码生成:orq $0x0, %(rsp)

[英]The x86 disassembly for C code generates: orq $0x0, %(rsp)

我编写了以下 C 代码: 在此处输入图像描述

它简单地分配一个包含 1000000 个整数的数组和另一个 integer,并将数组的第一个 integer 设置为 0

我使用gcc -g test.c -o test -fno-stack-protector编译了这个

它给出了一个非常奇怪的反汇编: 在此处输入图像描述

显然,它一直在循环中在堆栈上分配 4096 个字节,并且每隔 4096 个字节用 0 进行“或”运算,然后一旦达到 3997696 个字节,它就会进一步分配 2184 个字节。 然后它继续将第 4000000 个字节(从未分配过)设置为 5。

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

我在这里理解有什么问题吗?

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

这是针对Stack Clash class 漏洞的缓解措施,该漏洞自 90 年代或更早以来就为人所知,但仅在 2017 年才被广泛宣传。(请参阅stack-clash.txt此博客条目。)

如果攻击者可以安排一个具有攻击者控制大小的 VLA 的 function 来执行,或者可以安排一个具有大型固定大小数组的 function 来执行,当攻击者以其他方式控制已经使用的堆栈数量时,他们可以导致堆栈指针被调整到指向其他memory的中间,从而导致function破坏memory,通常导致任意代码执行

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

这里有两件事:

  • “无操作” OR读取写入堆栈上的每个页面。 这些是必需的,因为通常映射堆栈,以便在堆栈下方有一个保护页面/pages。 当保护页被触摸时,堆栈向下展开。 但是,如果您触摸保护页面下方的 memory,则会发生 SIGSEGV。

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM