C 为什么会出现这种溢出?

C 为什么会出现这种溢出?,c,C,在以下代码中: #include <stdio.h> #include <stdlib.h> #include <string.h> int check_authentication(char *password) { char password_buffer[16]; int auth_flag = 0; strcpy(password_buffer, password); if(strcmp(password

在以下代码中:

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

int check_authentication(char *password) {  
    char password_buffer[16];   
    int auth_flag = 0;

    strcpy(password_buffer, password);

    if(strcmp(password_buffer, "brillig") == 0)
        auth_flag = 1;
    if(strcmp(password_buffer, "outgrabe") == 0)
    auth_flag = 1;

    return auth_flag;
}

int  main (int argc, char *argv[]){
    if(argc < 2){
         printf("Usage: %s <password>\n", argv[0]);
        exit(0);    
    }

        if(check_authentication(argv[1])){
        printf("\n-=-=-=-=-=-=-==-=-=-\n");
        printf("  Access Granted\n");
        printf("-=-=-=-=-=-=-==-=-=-\n");
    }
    else {
        printf("Access Denied\n");
    }       
}
#包括
#包括
#包括
int check_身份验证(字符*密码){
字符密码_缓冲区[16];
int auth_标志=0;
strcpy(密码\缓冲区,密码);
if(strcmp(密码缓冲区,“brillig”)==0)
认证标志=1;
if(strcmp(密码缓冲区,“抢占”)==0)
认证标志=1;
返回auth_标志;
}
int main(int argc,char*argv[]){
如果(argc<2){
printf(“用法:%s\n”,argv[0]);
出口(0);
}
if(检查_身份验证(argv[1])){
printf(“\n-=-=-=-=-=-=-=-=-=-=-\n”);
printf(“授予的访问权”);
printf(“-=-=-=-=-=-=-=-=-=-=-\n”);
}
否则{
printf(“访问被拒绝\n”);
}       
}
如果我运行诸如“aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa。我很困惑,因为当我运行gdb调试器时,auth_标志在内存中的password_缓冲区之前,并且从未溢出

编辑:我知道文本不适合缓冲区,但我正在试验缓冲区溢出,以及如何以可控的方式利用它们。是的,我们可以使阵列更大,但这不是重点


我想知道是否有人能告诉我为什么会发生这种情况/是什么导致了这种情况。

aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa。然后使用strcpy将其复制到大小为16的字符数组中。尝试增加密码缓冲区大小

为避免溢出,目标指向的数组大小 应足够长,以包含与源相同的C字符串(包括 终止的空字符),并且在内存中不应与 来源


因为您正在将输入复制到一个太小的缓冲区中(而且没有任何原因)。您的方法可以实现(没有溢出)如下

我知道它溢出了自助餐,但为什么它会导致允许访问?(认证标志>0)


因为
auth_flag
char password_buffer[16]之后内存中的下一个
int
。对于某些编译器(和操作系统),如果溢出
password\u buffer
,则很可能修改
auth\u flag

内存以连续方式存储在堆栈中, 因此,有一个char[16]和一个int表示身份验证是否成功通过

当您传入一个指向缓冲区的指针并在不检查本地缓冲区边界的情况下复制它时,您可能会溢出缓冲区并重写堆栈变量

输入'A'*20时,前16个'A'进入缓冲区,其余4个'A'进入int(通常sizeof(int)为4字节)

现在,你的int不是0,它是: auth=0x4141 因为“A”的ASCII码是0x41

有一篇非常好的文章与此相关-


它列出了堆栈溢出的基础知识,稍后会更高级一些。

当您调整缓冲区大小时,它需要长度+1,因为它需要终止空字符。如前所述,您正在调用未定义的行为。因此,不可能有标准答案。任何答案都取决于系统、编译器和使用的编译选项。所以,如果你真的想要一个像样的答案,你需要提供这些信息。但我仍然感到困惑的是,授予访问权的原因是auth_标志不是零。如果我们使用这个字符串,我知道它会溢出自助餐,但为什么它会导致授予访问权限?(auth_flag>0)@yasgur99溢出缓冲区会导致未定义的行为。在这种情况下,任何事情都有可能发生。我没有试图让代码正常工作,我知道它是溢出的,这就是为什么会出现问题,但我似乎无法找出是什么导致了这种情况的发生specifically@yasgur99编辑。在您的代码中,
auth\u标志
int
几乎肯定会立即存储在
password\u buffer
之后(内存中)。我在调试器中进行了检查,但没有。我不知道这是否与Linux/Little Endian有关,但我1000%确定密码缓冲区在auth之后_flag@yasgur99您是否检查了gcc-S的输出?还有,我只是想帮你。。。如果您在运行时使用
gdb
(或其他调试器)检查了它,那么您应该在问题中添加完整的运行时跟踪。改善你的缩进。
int check_authentication(const char *password) {
    size_t len = strlen(password);

    return strncmp(password, "brillig", len) == 0 ||
           strncmp(password, "outgrabe", len) == 0;
}