strcpy()函数应该是我们用的比较常用的一个函数,基本功能是将一个字符串拷贝到我指定的内存空间。但是要复制的字符串长度超过这段内存空间的话,结果可能是未知的。

比如以下的程序:

#include <stdio.h> 
#include <string.h>
 
int main(int argc, char *argv[])
{
    int flag = 0;
    char password[5] = {'\0'};
 
    strcpy(password, argv[1]); 
 
    if(0 == strcmp("root", password)) 
    { 
        flag = 1; 
    } 
 
    if(flag) 
    { 
        printf("密码被破解了\n"); 
    } 
    else 
    { 
        printf("密码破解失败\n"); 
 
    } 
    return 0; 
} 

上述程序的功能是一个简单的密码破解功能,也就是判断用户输入的密码是不是”root“,如果是,则输出密码被破解了,否则提示用户密码破解失败!字符串数组argv[1]的内容已经事先设定为”123456789“。运行结果如下:


程序输出密码被破解了,说明if(0 == strcmp("root", password)) 这个语句判断通过了,将flag设为1了。但是我们的疑问是,”root“明明和”123456789“不一样啊,为什么if判断会通过呢?我们使用VC 6.0来调试下,如下:



从调试中可以看到,在执行到” if(0 == strcmp("root", password)) “时,flag的值已经变成57了,是不是很奇怪?
仔细看调试过程,p
assword[0]这个字符的地址是0x0012ff74“,password[1]这个字符的地址是”0x0012ff75“,以此类推,到了flag的地址是”0x0012ff7c“。也就是说,从password[0]开始,到flag,这是一段连续的内存区域,这段内存区域一共是0x0012ff7c - 0x0012ff75 = 9个字节大小,password数组占去了5个字节大小,也就是从地址0x0012ff74“到地址0x0012ff78“存放的都是password的字符。而argv[1]有”123456789“一共9个字符,将前5个字符给了password数组后,剩余的”6789“这4个字符,就存放在地址0x0012ff79“到0x0012ff7c“这端内存区域中。而flag的地址是0x0012ff7c“,所以flag就存放了字符”9“,而字符”9“的ASCII码值是57,所以flag最终的值就是57。这样的话,即使用户输入的密码不是”root“,但是程序密码也被破解了,这就是使用strcpy函数的一个陷阱,即strcpy函数不会去检查第一个参数的存储区域是否容得下第二个参数的存储容量。


========================2017年1月22日更新====================
有热心的网友指出,flag变量跟password数组在内存上连续存放,但是也有肯定不是连续存放的,这可能取决于编译器。我是在VC6上编译的,也许用GCC编译的话,就不会连续存放了,gcc编译可能flag还是0。但是不管怎么,strcpy不检查数组越界,这个始终是需要注意的。
posted on 2017-01-07 15:23  C语言答疑课堂  阅读(686)  评论(0编辑  收藏  举报