代码之家  ›  专栏  ›  技术社区  ›  John Pence

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

  •  0
  • John Pence  · 技术社区  · 6 年前

    %64d 在里面 printf %64 ? (将参数传递给

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

    如果我们的程序很简单 打印F

    而且,如果我们覆盖堆栈中开头的内容,会不会给我们的程序带来问题?我以为那些是程序需要的重要东西,比如env变量之类的?

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

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

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

    1 回复  |  直到 6 年前
        1
  •  1
  •   Stephen Kitt    6 年前

    当你打电话的时候 printf 具有以下参数 "%64d" ,并且无论要打印什么整数,填充到64个空格,堆栈上占用的空间只是参数本身所需的空间:一个指向字符串的指针(忽略优化)和一个整数。参数本身并没有扩展以考虑填充 这是我的工作。

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

    在视频中,用于写入超过100M空间的格式字符串是一个以整数0x08049724开头,后跟 "AAAABBBBCCCC%4$134513000x %4$n" 是指向此字符串的指针;因为它读入堆栈上的缓冲区,所以它也存在于堆栈上,但这不是与 打印F . GOT没有被缓冲区溢出覆盖,而是由 %n 打印F 它的地址是明确给它的。作者明确地说,只有512个字符可以玩;他从不说(或显示)进程内存中的任何地方都写有数百万个字符。