2

我正在用 C++ 测试一个简单的缓冲区溢出。该示例是一个测试,如果没有进行检查,恶意用户可以使用缓冲区溢出覆盖变量。

该示例定义了一个缓冲区,然后是一个变量,这意味着应该为缓冲区分配空间,然后为变量分配空间。该示例读取cin长度为 5 的缓冲区,然后检查 admin 变量是否设置为 0 以外的值,如果是,则用户在概念上获得了管理员访问权限。

#include <iostream>
using namespace std;

int main()
{
    char buffer[5];
    int admin = 0;

    cin>>buffer;
    if(strcmp(buffer,"in") == 0)
    {
        admin = 1;
        cout<<"Correct"<<endl;
    }
    if(admin != 0)
        cout << "Access" << endl;
    return 0;
}

我有 3 台机器,1 台 Windows 和 2 台 Linux 系统。

当我在 Windows(CodeBlocks)上测试它时(逻辑上)输入超过 5 个字符溢出并重写admin变量的字节

现在我的第一个 linux 系统也可以工作,但只有当我输入 13 个字符时,这是否与不同的编译器以及它们如何为程序分配内存有关?

我的第二台 linux 机器根本无法溢出。只有在第 13 个字符之后才会出现转储错误。

为什么他们差别这么大?

4

2 回答 2

1

你应该检查拆卸。从那里你会看到究竟发生了什么。

一般来说,有两点需要考虑:

  1. 编译器完成的填充以对齐堆栈变量。

  2. 编译器对堆栈变量的相对位置。

第一点:您的数组char buffer[5];将被填充,因此int admin;将在堆栈上正确对齐。我希望它通常在x86x64上填充到 8 个字节,因此要覆盖 9 个符号。但是编译器可能会根据它认为合适的方式做不同的事情。尽管如此, Windows 和 Linux 机器似乎x86(32 位)。

第二点:编译器不需要按照声明的顺序将堆栈变量放入堆栈。在 Windows 和第一个 Linux 机器上,编译器确实放在char buffer[5]; 下面int admin;,所以你可以溢出到它里面。在第二台 Linux 机器上,编译器选择以相反的顺序放置它,所以不是溢出到,而是在写入超出分配的空间后int admin;破坏调用者的堆栈帧main()char buffer[5];

这是我自己对类似问题的回答的无耻链接 -检查此类溢出的示例

于 2013-09-16T21:47:13.313 回答
1

正如您所发现的,未定义的行为是未定义的。试图解释它通常不是很有效。

在这种情况下,几乎可以肯定是由于您的堆栈的排列和插入的/在编译器/系统之间变化的局部变量之间的填充字节。

于 2013-09-16T21:19:38.790 回答