我试图通过Smashing the Stack for Fun和Profit在C中做一个例子,但我有点卡在一点,以下是代码(我有一个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用于保存的栈指针上的指针.
其次,我的理解是char buffer[1]
占用8个字节(由于64位拱)并且如果我增加这个缓冲区来说buffer[2]
,仍然相同的代码应该工作正常,但这不会发生并且它开始给出seg错误.
此致,努曼
我使用的每个架构上的'char'是8位宽,无论它是8位微,16位微,32位PC还是64位新PC.另一方面,Int往往是单词大小.
本地人放在堆栈上的顺序可以是特定于实现的.我的猜测是你的编译器在"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
逐步完成gdb中的反汇编(反汇编,stepi,nexti),并查看每一步的寄存器(信息寄存器).
在这里您可以如何逐步完成反汇编:
gdb ./myprogram break main run display/4i $eip stepi stepi ... info registers ...
你也应该知道(你可能已经做过,因为你有一部分工作了)在许多发行版中,默认情况下在gcc中启用堆栈保护程序.您可以手动禁用它-fno-stack-protector
.