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. 将多个文本文件内的数据导入到Datagridview

    private BindingList listXSxxInfoList = new BindingList(); openFileDialog1.Multiselect = true;//允许选择多 ...

  2. awk积累

    1. 计算一个文本中每一列的和 [root@centos ~]# cat aaa.txt [root@centos ~]# awk 'BEGIN{a=0;b=0;c=0}{a+=$1;b+=$2;c+ ...

  3. Advanced Installer 中测试数据库连接提示“未发现数据源名称并且未指定默认驱动程序”的解决办法

    原文:Advanced Installer 中测试数据库连接提示"未发现数据源名称并且未指定默认驱动程序"的解决办法 最近需要制作一个安装包,安装包的要求如下: 1.用户手工填写M ...

  4. Upgrade a Non-CDB To a PDB on CDB

    .Stop the cluster database and start database on one node with read noly [oracle@raca1 admin]$ srvct ...

  5. How to Move SSL certificate from Apache to Tomcat

    https://www.sslsupportdesk.com/how-to-move-ssl-certificate-from-apache-to-tomcat/ Apache uses x509 p ...

  6. InfoPath分别定义New/Edit 表单

    InforPath自定义表单时,默认是New/Edit是相同的,有时不能满足特殊情况,例如,某些字段在新建时不需填,编辑才改.或者编辑时不能编辑特定字段.这时最方便的方法是分别定义表单,按不同情况使用 ...

  7. 【转】简单的jQuery插件开发方法

    在实际开发工作中,总会碰到像滚动,分页,日历等展示效果的业务需求,对于接触过jQuery以及熟悉jQuery使用的人来说,首先想到的肯定是寻找现有的jQuery插件来满足相应的展示需求.目前页面中常用 ...

  8. 通过内核对象在服务程序和桌面程序之间通信的小问题 good

    关于在通过 事件对象 在服务程序和普通桌面应用程序相互之间通信的问题,分类情况进行讨论:1.普通桌面应用程序中创建事件,服务程序中打开事件 XP的情况普通桌面应用程序中创建: m_hEvent = : ...

  9. vue.js异步上传文件前后端代码

    上传文件前端代码如下: <!DOCTYPE html> <html> <head> <meta http-equiv="Content-Type&q ...

  10. ios开发系列之内存泄漏分析(下)

    接上篇,本篇主要讲解通知和 KVO 不移除观察者.block 循环引用 .NSThread 和 RunLoop一起使用造成的内存泄漏. 1.通知造成的内存泄漏 1.1.ios9 以后,一般的通知,都不 ...