C/C++ 格式字符串中的填充如何存储在 Linux 的虚拟内存中?

How do paddings in format string of C/C++ get stored in virtual memory of Linux?

例如,当我们在printf中使用%64d时,这是否意味着space的ASCII码内容的64字节数据被存储在堆栈中,因为%64? (传递参数给printf)?

我问这个是因为我看了一个视频,那个家伙填充了超过 1 亿 spaces 来进行格式字符串利用(然后使用 %n 并编写特定的地址到那个位置),但我不明白有人如何在堆栈上使用超过 100-150MB 的数据(spaces)而不到达堆栈外部?我认为在 Linux 中这样做会导致段错误?

如果我们的程序是一个简单的 printf 那么通常我们可以上升多长时间(在 Linux 中)直到我们到达堆栈的末尾并因此导致段错误?

还有,如果我们覆盖堆栈中开头的内容,我们的程序会不会出现问题?我认为这些是程序需要的重要内容,例如环境变量等?

我正在谈论的视频(在视频末尾):

https://www.youtube.com/watch?v=t1LH9D5cuK4&t=616s

同样在其他视频中也没有传递给main函数的字符串,我们放入的格式字符串仍然在堆栈上而不是在堆上(使用gdb显示堆栈)

当您使用 "%64d" 等参数调用 printf 时,无论要打印什么整数,都会填充到 64 spaces,space stack 只是参数本身所需的 space :一个指向字符串的指针(忽略优化)和一个整数。参数本身没有扩展以考虑填充 - 这是 printf 的工作。

至于扩展本身,对于足够小的填充大小,这可能发生在堆栈上(这至少是 GNU C 库所做的;我还没有检查 C 标准是否指定了这一点),但实际上如示例中提到的大填充大小,扩展将在堆上发生(除非填充大小太大以至于 printf 失败并且 returns 错误 errno 设置为 EOVERFLOW).

在视频中,用于写入超过 100M spaces 的格式字符串是以整数 0x08049724 开头,然后是 "AAAABBBBCCCC%44513000x %4$n",然后是需要填充多少个 'X' 字符字符串输出到 512 字节。堆栈上调用 printf 所需的只是指向该字符串的指针;因为它被读入堆栈上的缓冲区,所以它也存在于堆栈中,但这不是与 printf 相关的要求。 GOT 不会被缓冲区溢出覆盖,它是由 %n 参数写入 printf 的,它采用显式指定给它的地址。作者明确表示只有 512 个字符可以玩;他从不说(或显示)数百万个字符写入进程内存中的任何位置。