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

标签 linux c virtual-memory c++ buffer

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

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

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

而且,如果我们覆盖堆栈开头的内容,是否会导致我们的程序出现问题?我认为这些是程序所需的重要内容,例如环境变量等?

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

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

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

最佳答案

当您使用诸如 "%64d" 之类的参数调用 printf 时,无论要打印什么整数,填充到 64 个空格,栈上占用的空间是只有参数本身所需的空间:一个指向字符串的指针(忽略优化)和一个整数。参数本身不会扩展以考虑填充 — 这是 printf 的工作。

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

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

关于linux - C/C++格式字符串中的填充如何存储在Linux的虚拟内存中?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52788504/

相关文章:

c - fork 进程与套接字通信

c - 如何使我的递归 C 程序更有效率?

c - 用于存储带孔凸多边形的库/数据结构

linux - 控制另一个进程的内存映射

Linux:页面错误和网络文件系统

linux - Enctype ="multipart/form-data"在 linux 环境下不工作?

linux - 更改 while 循环内的变量

linux - 如何找到有关我的 CPU 并行架构的信息?

python - pathlib.Path.chmod(mode) 中模式的解释

operating-system - MMU 是在操作系统和物理内存之间进行调解还是只是一个地址转换器?