使用gcc的缓冲区溢出示例

使用gcc的缓冲区溢出示例,c,gcc,memory,C,Gcc,Memory,我试图在C中演示strcmp函数中的缓冲区溢出。 我有strcpyV.c文件: #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { char a[8]; char b[8]; // function causes buffer overflow strcpy(b, "01234567"); // buffer overflow a

我试图在C中演示strcmp函数中的缓冲区溢出。 我有
strcpyV.c
文件:

#include <stdio.h>
#include <string.h>

int main(int argc, char *argv[])
{

    char a[8];
    char b[8];

    // function causes buffer overflow
    strcpy(b, "01234567");

    // buffer overflow again
    strcpy(a, "89abcdef");

    printf("\nb = %s\n", b);

    return 0;
}
当我在树莓py B+(树莓喘息)中这样做并运行:

我得到了预期的结果:

b = 0123456789abcdef
但当我在Ubuntu 16.04中完成整个过程时,结果是:

b = 01234567

有没有办法在没有这种内存保护的情况下编译代码?

可以将数组打包到结构中。然后将应用结构打包的规则。标准中没有定义结构打包规则,但是如果我们使用
gcc
,在这种情况下字符数组将是连续的(注意
b
现在放在
a
之前):

#包括
#包括
int main(int argc,char*argv[])
{
结构ab{
charb[8];
chara[8];
}s;
//函数导致缓冲区溢出
strcpy(s.b,“01234567”);
//我通过调整字符串来消除缓冲区溢出。
//第二次溢出并没有增加任何东西——恰恰相反。
//第一个溢出足以获取
//你想要的行为。
strcpy(s.a,“89abcde”);
printf(“\nb=%s\n”,s.b.);
返回0;
}

您可以禁用安全检查:

从手册中:

-fstack-protector
      Emit extra code to check for buffer overflows, such as stack smashing attacks.  >This is done by adding a guard variable to functions with
      vulnerable objects.  This includes functions that call alloca, and functions with >buffers larger than 8 bytes.  The guards are initialized when
      a function is entered and then checked when the function exits.  If a guard check >fails, an error message is printed and the program exits.

-fstack-protector-all
      Like -fstack-protector except that all functions are protected.
如果您想禁用此功能,只需在选项名称中添加no-no-即可

-fno-stack-protector -fno-stack-protector-all
缓冲区溢出示例:

int main(){
    int valid = 0;
    char str1 = ["START"];
    char str2 = [8];

    gets(str2);
    if(strncmp(str1, str2, 8) == 0){
        valid = 1;
        cout << "buffer: " << str1 << ", " << str2 << ", " << valid << endl;
    }

}
intmain(){
int valid=0;
字符str1=[“开始”];
字符str2=[8];
获取(str2);
if(strncmp(str1,str2,8)=0){
有效=1;

变量的布局取决于编译器。不管怎样,这是未定义的行为。但当我在Raspberry上这样做时……这就像我写的一样。未定义的行为包括预期的行为。对不起,未定义的行为没有预期的结果。@MichaelWalz:excludes!:)这有什么变化?它仍然是未定义的行为->一个任何事情都有可能发生。而且标准并不保证在成员之间不添加填充。@Olaf您是对的,第二个溢出会降低示例的值,因此我在回答中删除了它。我确实指出我依赖gcc使用的填充规则,但我已经进一步澄清了这一点。填充规则不是由编译器定义的呃,但实际上,ABI.gcc与平台的任何其他编译器一样,必须遵守它。例如,具有16字节缓存线的平台可能会对成员使用16字节对齐,因为这将使成员以最佳方式存储在缓存中。无论如何,访问其边界以外的数组是UB。编译器可以假设您不这样做,并生成适当的代码。例如64位arch可以在一个寄存器中通过整个数组;如果您访问该数组之外的内容,现在该怎么办?猜测会发生什么或它是否有效根本没有用。@Olaf了解并识别UB的常见结果对于诊断和修复bug非常有价值。如果行为发生变化,OP将需要将其代码重写为demonstrate(我想对他的学生来说)是缓冲区溢出的常见结果。抱歉,但这是错误的。如果遇到UB,可以看看发生了什么。但是尝试为未定义的行为生成显示已定义行为的代码是没有用的。-除非你不想编写SO不支持的恶意软件。
-fstack-protector
      Emit extra code to check for buffer overflows, such as stack smashing attacks.  >This is done by adding a guard variable to functions with
      vulnerable objects.  This includes functions that call alloca, and functions with >buffers larger than 8 bytes.  The guards are initialized when
      a function is entered and then checked when the function exits.  If a guard check >fails, an error message is printed and the program exits.

-fstack-protector-all
      Like -fstack-protector except that all functions are protected.
-fno-stack-protector -fno-stack-protector-all
int main(){
    int valid = 0;
    char str1 = ["START"];
    char str2 = [8];

    gets(str2);
    if(strncmp(str1, str2, 8) == 0){
        valid = 1;
        cout << "buffer: " << str1 << ", " << str2 << ", " << valid << endl;
    }

}