缓冲区溢出 - 覆盖字符串

时间:2013-10-14 13:45:19

标签: c buffer-overflow

我遇到了一些我发现的问题。鉴于以下内容:

int match(char *s1, char *s2) {
    while( *s1 != '\0' && *s2 != '\0' && *s1 == *s2 ){
        s1++; s2++;
    }
    return( *s1 - *s2 );
}

int main() {
    char str1[8], str2[8];
    scanf("%s", str1);
    scanf("%s", str2);
    if (match(str1, str2) == 0)
        printf("They are the same.\n");
    else
        printf("They are not the same.\n");
}

可以使用两个不同值的输入字符串来使程序打印消息“它们是相同的”? (上面的代码不能更改)

据我所知,当数组被添加到堆栈中时,它们被“推入”它并且信息以相同的方向写入。因此,如果我输入“AAAAAAAAA”(A x 9)到str2,它将溢出并且str1将打印“A”。

我的第一次尝试是为str2输入A x 16,希望程序用8 A覆盖str1中的值,程序只读取str2中的8个值。 str1的值为A x 8,但str2的值保持为A x 16。

有没有办法用它来解决这个问题?或者我是否以错误的方式思考这个问题?

编辑:此问题意味着要在具有过时且易受攻击的Linux版本的特定计算机上运行。我通过gdb运行程序,它显示两个字符串在内存中彼此相邻,并且str2溢出到str1中。那么我的问题是,我可以使用它来使str2和str1在比较它们时看起来与程序相同吗?

5 个答案:

答案 0 :(得分:3)

  

可以使用两个不同值的输入字符串来使程序打印消息“它们是相同的”? (上面的代码不能更改)

不存在这样明确定义的场景。这些要求毫无意义。

  

据我所知,当数组被添加到堆栈中时,它们被“推入”它并且信息以相同的方向写入。因此,如果我输入“AAAAAAAAA”(A x 9)到str2,它将溢出并且str1将打印“A”。

这是不正确的。缓冲区str1(可以包含 7 字母+ 1个空终止)将溢出,并且从那里可能发生任何事情,您调用未定义的行为。可能的未定义行为的一些示例是:分段故障/崩溃&刻录,或程序似乎正常工作。

无法保证str2与str1相邻分配。也没有任何保证str1在str2之前分配。甚至没有任何保证它们在堆栈上分配,尽管这很可能。

  

有没有办法用它来解决这个问题?

没有

  

或者我是否以错误的方式思考这个问题?

答案 1 :(得分:2)

我有另一个想法:如果输入“A”和“A A”会怎样?根据{{​​3}},sscanf期望'%s'的非空格字符,因此它将在“A A”中的第一个“A”之后停止读取(注意空格字符)。标签“缓冲区溢出”具有误导性。

答案 2 :(得分:1)

覆盖缓冲区会调用未定义的行为。任何事情都可能发生,所以你绝不能依赖它。

此外,str1str2在内存中不一定是彼此相邻的,你不能依赖它。

可能的解决方案

char buffer[16];
char * str1 = &buffer[8];
char * str2 = &buffer[0];

这样您就可以安全地从str2溢出到str1(但不能从str1溢出到str2)。你应该仍然有适当的长度检查。

答案 3 :(得分:1)

你有没有试过相反的方法?这取决于堆栈的布局方式。我会为str2尝试“AAAAAAAAAA”forstr1和“AAAAAAA”(7x'A')。 AFAIR堆栈从上到下增长。

请参阅here以获取解释。

编辑:我知道如果你写过数组限制会发生邪恶(未定义)的事情,但问题明确告诉不要改变程序。看起来像是了解软件开发中的安全风险。

答案 4 :(得分:0)

  

可以使用两个不同值的输入字符串来使程序打印消息“它们是相同的”?

您的字符串比较功能错误。 return( *s1 - *s2 );在这里毫无意义。将功能更改为

int match(char *s1, char *s2) {
    while( *s1 != '\0' && *s2 != '\0') {
        if(*s1 != *s2 )
             return 1;
        s1++; s2++;
    }

    return 0;
}