x86-32 上的 C 中的分段错误和分段错误



我有一个关于 C 语言中的堆栈溢出的问题。 我写了一个小测试程序,所以当我用 8 A 启动它时,我得到了我所期望的,我写在第二个 buf 的边界上,因此 buf1 是空的,因为尾随零现在是 buf1 中的第一个元素。 到目前为止一切顺利,如果我尝试使用 16 因为它也可以工作,事件与 17 A 一样。但是我希望这里有一个段错误...段错误出现在 24 A 之后。为什么?我在x86-32 ubuntu,debian和suse上进行了测试。总是在 24 字节后出现段错误... 在具有相同代码的 AMD64 系统上,我在 32 A 之后出现段错误,正如我预期的那样...... 但是为什么在 86-32 之后的 x24????

包括

#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: %sn", buf1);
printf("buf2: %sn", buf2);
strcpy(buf2, InputString);
printf("buf1: %sn", buf1);
printf("buf2: %sn", buf2);
}

int main(int argc, const char *argv[])
{
if (argc > 1)
exploit(argv[1]);
return 0;
} 

您正在尝试猜测编译器生成的内存布局。编译器可以自由地以任何合适的方式布局代码。但是,堆栈帧必须包含:

  • 参数(由调用方推送)
  • 返回地址(由 CPU 推送)
  • 需要保留的寄存器。这取决于目标体系结构。
  • 局部变量(由被调用方分配)

在测试的 x86 计算机上,局部变量和返回地址之间有 8 个字节,在 x64 计算机上有 16 个字节。如果被叫方保存了寄存器,它们将存储在以下空间中:

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。如果调用方不再使用基指针,则不会注意到此覆盖。函数使用其基指针返回,但如果函数通过系统调用退出(我记得 main 方法在这个意义上是"特殊的",但我无法找到我的主张),损坏的基指针永远不会被使用,并且损坏不会被注意到)。

要测试它是否是基指针,请执行以下操作:

  • 创建第三级呼叫(主呼叫、呼叫者、被叫方)。
  • 记录
  • 被调用方的返回,访问局部变量,再次记录,然后返回。
  • 如果在访问局部变量时发生段错误,则很可能是基指针。

其他可能的原因:

  • 发生错误时使用的一些调试信息。
  • 从未测试过但无论如何都会分配的金丝雀(堆栈保护器)。没有任何症状。
  • 参数数(系统调用) 破坏它会损坏调用方的堆栈指针,如果调用方不进行另一次调用,则不会被注意到。症状:如果调用方进行第二次调用,则调用方中出现段错误。
  • this指针。不应出席普通活动。

其他要尝试的操作:

在损坏之前和之后在被调用方中进行内存转储以查看布局。存储的基指针应指向堆栈空间(调用方的堆栈帧)。返回地址应指向代码空间(靠近当前 IP)。char* 参数是一个指针。用另外两个参数(">>>"和"<<<"作为char[4])的侧翼将有助于识别。

相关内容

  • 没有找到相关文章

最新更新