difference between single and double quotes in printf() in C
我对在C的printf()中使用双引号和单引号有疑问。我有以下代码:
1 2 3 4 5 6 7 |
所以当我编译并运行它时,会发生以下结果:
1 2 3 4 5 6 7 | ./a.out 'AAAA%8$p' AAAA0x70243825**41414141** ./o"AAAA%8$p" AAAA |
注意,在第一种情况下,我输入了单引号,在第二种情况下输入了双引号。
这里发生了什么。
Q2。我在这里关注此链接。所以我的问题是,运行时输入argv [1]中的AAAA如何影响printf()的输出。首先,我认为这仅仅是一个巧合,但是我输入并得到以下内容:
1 2 3 | ./o 'BBBB%8$p' BBBB0x70243825**42424242** |
Edit:所以我认为看到答案有些误解。我知道直接\\ printf(buffer)\\的滥用。因此,我将引用前面提到的链接:
由于printf具有可变数量的参数,因此它必须使用格式字符串来确定参数数量。在上述情况下,攻击者可以传递字符串"%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p%p "并将printf欺骗到认为它有15个论点。它会天真地在堆栈上打印接下来的15个地址,并认为它们是它的参数:
1 2 | $ ./a.out"%p %p %p %p %p %p %p %p %p %p %p %p %p %p %p" 0xffffdddd 0x64 0xf7ec1289 0xffffdbdf 0xffffdbde (nil) 0xffffdcc4 0xffffdc64 (nil) 0x25207025 0x70252070 0x20702520 0x25207025 0x70252070 0x20702520 |
在堆栈上大约10个参数处,我们可以看到重复模式0x252070-这些是我们的%ps堆栈!我们以AAAA开头的字符串可以更清楚地看到这一点:
1 2 | $ ./a.out"AAAA%p %p %p %p %p %p %p %p %p %p" AAAA0xffffdde8 0x64 0xf7ec1289 0xffffdbef 0xffffdbee (nil) 0xffffdcd4 0xffffdc74 (nil) 0x41414141 |
0x41414141是AAAA的十六进制表示形式。现在,我们有一种方法可以传递一个任意值(在本例中,我们将传递0x41414141)作为printf的参数。此时,我们将利用另一种格式字符串功能:在格式说明符中,我们还可以选择一个特定的参数。例如,printf("%2 $ x ",1,2,3)将打印2。通常,我们可以执行printf("%$ x ")选择printf的任意参数。在我们的例子中,我们看到0x41414141是printf的第十个参数,因此我们可以简化我们的string1:
1 2 | $ ./a.out 'AAAA%10$p' AAAA0x41414141 |
,所以我真的不认为这是垃圾值。而是实际上是该位置的地址。
我的平台:Ubuntu 14.04,64位计算机。
所以我想知道输入中的'AAAA'或'BBBB'对输出'AAAA0x7024382541414141'或BBBB0x7024382542424242。
这与C中的引号无关。shell会从命令行参数中删除单引号和双引号。但是shell可能对美元符号也有特殊含义(如果使用双引号而不是单引号,则
所以这是
现在有关您奇怪的输出正在查看。
然后堆栈看起来像:
,但是您不这样做提供足够的论据。因此,您的堆栈看起来更像:
然后发生的事情是-
然后从那里读取8个字节并以十六进制打印(
<十六进制中的pa>
这是未定义的行为。不应依赖它(除非您正在编写漏洞利用程序)。它会在平台,编译器甚至优化模式之间发生变化。
通常,您希望停留在已定义行为的领域。
p.s。除了您可能已经意识到的错误使用
printf(缓冲区)非常非常非常危险。
printf的第一个参数是格式字符串,其中包含文本,还包括格式说明符,例如%d用于打印整数,%s用于打印字符串等等。
如果缓冲区包含格式说明符,则printf将尝试根据格式说明符处理格式字符串之后的下一个参数。但是您没有传递任何其他参数,而且您也不知道要传递什么参数。这样您就获得了不确定的行为。
在实践中,
非常有可能崩溃。