【问题标题】:Non Null-terminated value causing StrCmp to return 0?导致 StrCmp 返回 0 的非 Null 终止值?
【发布时间】:2018-11-23 12:43:32
【问题描述】:

我有以下代码:

_Bool grantAccess(char *password){
    char goodPassWord[]= "goodpass";
    return (0 == strcmp(password, goodPassWord));

}

_Bool grantAccessExercise(void){
    char password[9];
    int allow = 0;

    printf("Please enter password: ");

    gets(password); 

    if (grantAccess(password)) {
         allow = 1;
    }

    return (allow != 0);
    }

当我输入 10 个字符的任意组合作为密码时,它会溢出并覆盖空终止符。谁能解释为什么非空终止值导致 StrCmp 返回 0?

【问题讨论】:

  • 这是未定义的行为,因此无法保证0 的结果。它还不如完全做其他事情。
  • 请注意,dangerous 函数 gets 不会“覆盖空终止符”,而是写入数组的空终止符越界 .
  • 仅仅因为某些东西似乎有效并不意味着行为实际上是定义的,只是你碰巧是“幸运的”(有些人会认为它un幸运)。你不知道它什么时候会坏掉,也不知道一旦它发生你做了什么让它坏掉。
  • @Hughes_J 请注意,您需要区分 '实现定义的行为',这意味着该行为不是由标准定义的,而是留给编译器供应商(然后需要记录它们各自的实现如何表现)和 'undefined behavior' 这意味着不存在任何正确的行为,无论你做什么,结果都不正确(例如计算实数平方根从负实数值)。

标签: c buffer-overflow strcmp


【解决方案1】:

谁能解释为什么非空终止值导致 StrCmp 返回 0?

这不是发生的事情。

会发生什么:

  • password 上的缓冲区溢出覆盖了作为堆栈定位变量allow 一部分的字节
  • 因此,allow 不再包含值零,而是包含其他值。
  • 对grantAccess() 的调用返回false,并且allow 未被修改。
  • 最后,allow 包含由于溢出导致的非零值。

为了验证,我做了如下测试:

  • 我输入了密码“0123456789”
  • 我观察到allow == 57,这是字符“9”的 ASCII 码。

【讨论】:

  • 换句话说,TL;DR,strcmp 返回 0。
  • 请注意,这仍然是 UB。无法保证堆栈上的值(变量)的顺序。但是 +1 用于发现此示例中 strcmp 看似奇怪的行为的原因。
【解决方案2】:

进一步说明:您在此处观察到的是stack corruption。如果您输入足够长的字符串作为密码,您甚至会得到stack smashing。您可以尝试为您的 password 数组赋予不同的大小,这可能会导致堆栈中的事物重新排序。 stack smashing or stack buffer overflow is here的一个很好的解释。

您还可以更改代码以使用malloc 在堆上分配password 数组。您可能会得到看似有效的代码,因为大多数内存位置在增加时,有时很可能包含一个 0,它被解释为 NULL 终止符。这将是一种更加阴险的行为,因为您的 grantAccess 函数可能似乎可以正常工作。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-08-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-08
    • 2012-06-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多