笔试宝典上关于字符串复制的问题

#include <iostream>
#include <stdio.h>
int main(void)
{
<span style="white-space:pre">	</span>char s[]="123456789";
<span style="white-space:pre">	</span>char d[]="123";
<span style="white-space:pre">	</span>strcpy(d,s);
<span style="white-space:pre">	</span>printf("%s,\n%s",d,s);
<span style="white-space:pre">	</span>return 0;
}

输出结果是多少,书上说是123456789,56789

运行结果是,求解释




你用的VC,如果用gcc则书中的结果是正确的,因为VC编译器在编译的时候对内存布局作出的后台处理以实现优化目的,比如节省内存或者加速访问,GCC对于C++标准的实现优于VC。
仍以在gcc下编译为例:
s和d是长度分别为11和4的char型数组,都是局部变量,在栈内存区域存放(不明,可以自行学习程序中变量在内存中的存储方式),向低地址增长,加入s的起始地址是20,则d的起始地址为16,
则从地址16开始依次为‘1’ ‘2’ ‘3’ ‘\0’ '1' '2' '3' ... ' 9' '\0',前4个为d的内容,后11个为s的内容,在执行完strcpy后,从地址16开始依次为'1' '2' ... '9' '\0' '5' '6' '7' '8' '9' '\0'。
VC的结果不同是因为其内存布局有调整,并未完全按照上述,你可以在VC中输出s和d的首地址二者之差一定不是4,在我这VC上是12,故而可以理解为什么VC结果与gcc不同。

因为你将d和s申请为数组,故都在堆栈区,但在字符串常量区也有'123456789'和“123”内容.
如果如下声明
char *s = "123456789";
char *d = "123";则d和s的确都指向字符串常量区域。因为字符串常量区是只读区域不能修改,执行strcpy一定会出错。
 
 

总结:在使用strcpy时一定要注意,尽量用strncpy代替。再看下面在网上找来的例子。可以帮助加深理解。

问:下面是一个简单的密码保护功能,你能在不知道密码的情况下将其破解吗?

[cpp]  view plain copy
  1. #include<stdio.h>   
  2.    
  3. int main(int argc, char *argv[])   
  4. {   
  5.     int flag = 0;   
  6.     char passwd[10];   
  7.    
  8.     memset(passwd,0,sizeof(passwd));   
  9.    
  10.     strcpy(passwd, argv[1]);   
  11.    
  12.     if(0 == strcmp("LinuxGeek", passwd))   
  13.     {   
  14.         flag = 1;   
  15.     }   
  16.    
  17.     if(flag)   
  18.     {   
  19.         printf("\n Password cracked \n");   
  20.     }   
  21.     else   
  22.     {   
  23.         printf("\n Incorrect passwd \n");   
  24.    
  25.     }   
  26.     return 0;   
  27. }   

答:破解上述加密的关键在于利用攻破strcpy()函数的漏洞。所以用户在向“passwd”缓存输入随机密码的时候并没有提前检查“passwd”的容量是否足够。所以,如果用户输入一个足够造成缓存溢出并且重写“flag”变量默认值所存在位置的内存的长“密码”,即使这个密码无法通过验证,flag验证位也变成了非零,也就可以获得被保护的数据了。例如:

[cpp]  view plain copy
  1. $ ./psswd aaaaaaaaaaaaa   
  2.    
  3. Password cracked   
虽然上面的密码并不正确,但我们仍然可以通过缓存溢出绕开密码安全保护。


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值