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了,是不是很奇怪?

仔细看调试过程,password[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不检查数组越界,这个始终是需要注意的。

小心使用strcpy函数时越界的更多相关文章

  1. strcpy函数

    不调用C/C++库函数,编写strcpy()函数. char * my_strcpy(char *strDest,const char *strSrc) { char *p=strDest; whil ...

  2. strcpy函数用法

    字符串是数组类型,不能通过赋值运算进行,要通过strcpy进行拷贝,其中目的字符串必须是字符串变量,源字符串可以是常量,复制后源字符串保持不变. strcpy()是C中的一个复制字符串的库函数,在C+ ...

  3. strcpy 函数的实现

    原型声明:extern char *strcpy(char *dest,const char *src); 头文件:string.h   功能:把从src地址开始且含有‘\0’结束符的字符串赋值到以d ...

  4. strcpy函数的实现

    strcpy函数的实现 大家一般认为名不见经传strcpy函数实现不是很难,流行的strcpy函数写法是: char *my_strcpy(char *dst,const char *src) { a ...

  5. strcpy函数和strncpy函数的区别

    strcpy函数和strncpy函数的原型介绍在我的另一篇文章中介绍了,见strcpy,strncpy,strlen等函数原型 strcpy:字串复制 原型:char *strcpy(char *de ...

  6. memcpy、memmove、memset及strcpy函数实现和理解

    memcpy.memmove.memset及strcpy函数实现和理解 关于memcpy memcpy是C和C++ 中的内存拷贝函数,在C中所需的头文件是#include<string.h> ...

  7. strcpy函数的C/C++实现

    2013-07-05 14:07:49 本函数给出了几种strcpy与strncpy的实现,有ugly implementation,也有good implementation.并参考标准库中的imp ...

  8. strcpy函数导致release版程序崩溃

    最近在写一个读取模型文件的小程序.很随意的使用了strcpy函数进行char字符数组的拷贝,这个数组是需要传递给PostMessage作为WPARAM的参数.代码部分如下: char pStrCurr ...

  9. 第九十六题(编写strcpy 函数)

    96.08 年中兴校园招聘笔试题 1.编写strcpy 函数 已知strcpy 函数的原型是 char *strcpy(char *strDest, const char *strSrc); 当中st ...

随机推荐

  1. 使用BGP的虚拟下一跳实现IGP的路由负载

    网络拓扑: XRV1 ============================================================== !hostname XRV1! interface ...

  2. WPF 鼠标在图片Image上悬停时切换更改设置图片源Source

    // 无效的写法,图片不会被切换 <Image Margin="0,0,0,0" Width="50" Height="50" Sou ...

  3. Android 联系人导入导出(VCard格式)

    之前在Android Contact 导入导出 vcf格式(不依赖第三方库)记录了一下依赖Android sdk中的功能导入导出联系人(第一次做java项目内容,有些地方的记录是否正确,暂时我也不知道 ...

  4. C#图片灰度处理(位深度24→位深度8)

    #region 灰度处理 /// <summary> /// 将源图像灰度化,并转化为8位灰度图像. /// </summary> /// <param name=&qu ...

  5. Git基本用法(二)

    比较内容 git diff [--cached] 参见上节 git diff <分支1> <分支2> 比较两个分支的不同 git diff <分支名> <文件 ...

  6. 窗体图片背景(两种方法:设置Brush.Bitmap指向图片,别的控件也可以这样)

    var   Bitmap: TBitmap; procedure TForm1.FormCreate(Sender: TObject); begin   Bitmap := TBitmap.Creat ...

  7. QT5.7静态编译(使用VS2013与VS2015编译,XP可用,有详细configure脚本。VS下Qt插件的配置。编译选项加上-mp可以开启多线程编译,编译速度提高2倍以上)

    http://blog.csdn.net/u011964923/article/details/52886908 configure -confirm-license -opensource -pla ...

  8. Js判断当前浏览者的操作系统

    function validataOS(){ var userAgent = navigator.userAgent; if(userAgent.indexOf('Window')>0){ re ...

  9. win2003浏览器提示是否需要将当前访问的网站添加到自己信任的站点中去

    Win2003的操作系统,的确比其它操作系统在安全上增加了不少,这是为用户所考虑的.当然,既然提供了安全性,尤其是在上网的时候,可以禁止某些活动脚本的显示,这样,就可以多方面的避免在使用Win2003 ...

  10. Unity AssetBundle,Asset,GameObject之间的联系

    一.问题 首先,这里说明一下,我这边的GameObject有点笼统,就是表达的是游戏中的具体实例. 二.概念 1)Asset是什么? 游戏中具体的资源,像texture,mesh,material,s ...