我对C中的堆栈溢出有疑问。 我写了一个小测试程序,所以当我用8开始它时,我得到我所期望的,我写第二个buf的边界,因此buf1是空的,因为尾随零现在是buf1中的第一个元素。 到目前为止一切都那么好,如果我尝试16,因为它也有效,17事件的事件。但我希望在这里遇到一个段错误...在24 As之后会出现段错误。这是为什么?我测试了x86-32 ubuntu,debian和suse。 24字节后总是段错误... 在具有相同代码的AMD64系统上,我在32 As之后得到段错误,就像我预期的那样...... 但为什么在x86-32之后的24 ????
#include <string.h>
/*
* $ gcc -O0 -Wall -fno-stack-protector buffer.c -o buffer
*
* $ ./buffer AAAAAAAA
* buf1: test
* buf2: test
* buf1:
* buf2: AAAAAAAA
*
* $ ./buffer AAAAAAAAAAAAAAAAAAAAAAAA
* buf1: test
* buf2: test
* buf1: AAAAAAAAAAAAAAAA
* buf2: AAAAAAAAAAAAAAAAAAAAAAAA
* Segmentation fault (core dumped)
*/
static void exploit(const char *InputString)
{
char buf1[8];
char buf2[8];
strcpy(buf1, "test");
strcpy(buf2, "test");
printf("buf1: %s\n", buf1);
printf("buf2: %s\n", buf2);
strcpy(buf2, InputString);
printf("buf1: %s\n", buf1);
printf("buf2: %s\n", buf2);
}
int main(int argc, const char *argv[])
{
if (argc > 1)
exploit(argv[1]);
return 0;
}
答案 0 :(得分:0)
您正在尝试猜测编译器生成的内存布局。编译器可以以任何合适的方式自由地布局代码。但是,堆栈帧必须包含:
在您测试的x86机器上的局部变量和返回地址之间有八个字节,在x64机器上有十六个字节。如果被调用者保存了寄存器,它们将被存储在这个空间中:
func:
PUSH BP
MOV BP, SP
SUB SP, privateSpace
...
MOV SP, BP
POP BP
RET argSize
http://en.wikipedia.org/wiki/Calling_convention#x86
因此,返回地址后面的空格包含存储的帧指针BP。如果调用者再也不使用基指针,则不会注意到这种覆盖。一个函数使用它的基指针返回,但是如果函数通过系统调用退出(我记得主要方法在这个意义上是“特殊的”,但我不能提出我的声明),从来没有使用损坏的基指针和腐败将被忽视)。
测试它是否是基指针:
其他可能的原因:
this
指针。普通功能不应该出现。其他尝试:
在损坏之前和之后在被调用者中进行内存转储以查看布局。存储的基指针应指向堆栈空间(调用者的堆栈帧)。返回地址应指向代码空间(靠近当前IP)。 char *参数是一个指针。用另外两个参数(“&gt;&gt;&gt;”和“&lt;&lt;&lt;”作为char[4]
)展开它将有助于识别。