我从这个链接在线阅读了以下代码:05/Lectures/BufferOverflow.html
我对这行中%p的用法感到困惑:
printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");它摘自以下代码片段:
/*
StackOverrun.c
This program shows an example of how a stack-based
buffer overrun can be used to execute arbitrary code. Its
objective is to find an input string that executes the function bar.
*/
#pragma check_stack(off)
#include <string.h>
#include <stdio.h>
void foo(const char* input)
{
char buf[10];
printf("My stack looks like:\n%p\n%p\n%p\n%p\n%p\n% p\n\n");
strcpy(buf, input);
printf("%s\n", buf);
printf("Now the stack looks like:\n%p\n%p\n%p\n%p\n%p\n%p\n\n");
}
void bar(void)
{
printf("Augh! I've been hacked!\n");
}
int main(int argc, char* argv[])
{
//Blatant cheating to make life easier on myself
printf("Address of foo = %p\n", foo);
printf("Address of bar = %p\n", bar);
if (argc != 2)
{
printf("Please supply a string as an argument!\n");
return -1;
}
foo(argv[1]);
return 0;
}我知道%p是指针的格式化程序,但是为什么格式化程序后面没有值?这里实际打印的值是什么?如果它打印提供给foo函数的参数的地址,那么为什么有5 '%p‘,为什么所有的'%p’不都格式化相同的值?
非常感谢。
发布于 2014-03-20 00:30:36
这是利用未定义的行为。
通过故意不向printf提供值,va_arg将从要打印的堆栈中提取任意值。这不是正确的代码。事实上,这段代码片段似乎试图解释黑客技术,这种技术经常利用未定义行为发生时出现的故障。
发布于 2019-06-19 20:04:46
--这段代码很糟糕,对于使用调试器查看堆栈来说,这是一个非常糟糕的替代。不要浪费你的时间,直到/除非你明白它是如何滥用调用约定和它到底是打印的。(并查看编译器生成的代码,查看调用时堆栈指针指向的位置)。
,它依赖于32位x86上典型的堆栈-args调用约定。(因此,变量printf函数将把堆栈上的数据作为额外的args处理)。函数“拥有”它们的arg(并且可以修改它们),但是在实践中,大多数函数不修改它们的堆栈args,而各种函数则更少。
它还依赖于编译器不插入一堆额外的填充,使call printf的ESP由16对齐,这是现代版本的i386系统V所需要的。如果发生这种情况,在您想要用strcpy缓冲区溢出覆盖的真实内容之前会有一些额外的填充指针。
在x86-64代码中,x86-64 System在整数寄存器中传递前6个整数/指针args,因此在格式字符串之后,前5个%p转换将捕获RSI、RDX、RCX、R8和R9中的任何垃圾。(RDI中的格式字符串)。然后,您将从堆栈中获得一些qword,用于其余的%p转换。
在Windows中,调用约定包括“影子空间”:比被调用方拥有的x64高出32个字节,在这里,它们可以转储寄存器args,使args数组与堆栈args相邻。打电话的人必须预订这个空间。strcpy也会出现这种情况,因此可能会有某种程度的平衡,但是仍然要打印RDX、R8和R9中的垃圾。(RCX中的格式字符串)。
通常,大多数用于其他非x86 ISAs的调用约定都有一些寄存器args (通常为4,例如ARM或MIPS),而且大多数不使用阴影空间。
https://stackoverflow.com/questions/22521064
复制相似问题