0

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

我之所以问这个问题是因为我观看了一个视频,其中那个家伙填充了超过 1 亿个空格来执行格式字符串漏洞利用(然后使用%nand 将特定地址写入该位置),但我不明白有人怎么能在堆栈上使用超过 100-150MB 的数据(空间)而不到达堆栈外部?我认为在 Linux 中这样做会导致段错误?

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

而且,如果我们覆盖堆栈中开头的内容,它不会导致我们的程序出现问题吗?我认为这些是程序需要的重要东西,比如环境变量等等?

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

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

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

4

1 回答 1

1

当您printf使用参数调用时"%64d",以及要打印的任何整数,填充到 64 个空格,堆栈上占用的空间只是参数本身所需的空间:指向字符串的指针(忽略优化)和整数. 参数本身并没有扩展以考虑填充 - 这是printf的工作。

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

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

于 2018-10-12T12:37:59.503 回答