我试图从C中的Smashing the Stack for Fun and Profit做一个例子,但是有点卡在某一点上, 以下是代码(我有一个64位的Ubuntu 64位机器):
int main()
{
int x;
x = 0;
func(1,2,3);
x = 1;
printf("x is : %d\n", x);
}
void func(int a, int b, int c)
{
char buffer[1];
int *ret;
ret = buffer + 17;
(*ret) += 7;
}
上面的代码工作正常,返回时x=1
行没有执行,但是我无法理解ret = buffer + 17;
背后的逻辑,不应该是ret = buffer + 16;
,即8字节缓冲区为8,堆栈上保存的基指针为8。
其次,我的理解是char buffer[1]
占用8个字节(由于64位拱)
如果我将此缓冲区增加到buffer[2]
,仍然相同的代码应该正常工作,但这不会发生并且它开始给出seg错误。
此致 努曼
答案 0 :(得分:13)
本地人放在堆栈上的顺序可以是特定于实现的。我的猜测是你的编译器在“char buffer 1”之前将“int * ret”放在堆栈上。因此,要获得返回地址,我们必须通过“char buffer 1”(1字节),“int * ret”(8字节)和保存的基本指针(8字节)总计17字节。
这是x86 64位上堆栈帧的描述: http://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-035-computer-language-engineering-spring-2010/projects/x86-64
答案 1 :(得分:9)
逐步完成gdb中的反汇编(反汇编,stepi,nexti),并查看每一步的寄存器(信息寄存器)。
您可以在此处逐步进行反汇编:
gdb ./myprogram
break main
run
display/4i $eip
stepi
stepi
...
info registers
...
你应该也知道(你可能已经知道你已经完成了部分工作)在许多发行版中,默认情况下在gcc中启用堆栈保护程序。您可以使用-fno-stack-protector
手动禁用它。
答案 2 :(得分:3)
有很多这个堆栈粉碎的东西,你最好的朋友是gdb。既然你已经分段了,那么你已经在写记忆了,你不应该这样做(一个好兆头)。一种更有效的方法是将返回地址更改为有效地址的其他地方(例如,更改为func
的地址或您已获得的某些shellcode)。我推荐的一个很好的资源是Shellcoder's Handbook,但是由于你使用的是64位架构,很多例子都需要一些工作才能开始。
答案 3 :(得分:0)
除了运行调试器(或者更好)之外,您还可以使用printf“%p”结构来打印变量的地址,例如:
printf("buf: %p\n", buffer); //&buffer[0] works too; &buffer works for an array
printf("ret: %p\n", &ret):
printf("a: %p\n", &a);
打印各种地址可以深入了解编译器/实现如何在后台安排事情。你也可以直接从C代码中完成它!
答案 4 :(得分:0)
如果您对x64缓冲区溢出漏洞感兴趣,请考虑查看stealth's borrowed code chunk technique。