c语言strcpy函数的漏洞

来源:互联网 发布:java观察者模式的意义 编辑:程序博客网 时间:2024/06/10 04:42

    函数里的局部变量一般都是按序排放的,并且因为是分配在堆栈之中,它们的地址是向下“增长”,即向低地址方向增长。比如下面的程序:

   int flag=0x12345678;   printf("%x\n",flag);   char s[6];   printf("address of  flag:   %x\n",&flag);   printf("address of array s: %x\n",s);   strcpy(s,"my aaaa");   printf("%s\n",s);   printf("%x\n",flag);   printf("%c\n",*(char *)(&flag));//输出变量flag的第一个字节的内容

上面的程序申明了一个变量flag并初始化为十六进制的12345678,以及一个字符型数组s。程序的运行结果如下图:





从图中可以看出,程序执行时把变量flag分配的地址是0x28ff1c,而字符数组s的地址为0x28ff16,可以看到地址的增长方向是向下的,同时,s相对于flag的偏移量正好是字符数组s的大小,即6。在执行函数strcpy之前,可以把它们在内存中的布局表示如下(以字节为单位):


因为我的机器中,数据的字节序是小端模式(小端模式即是:数据的高位保存在内存的高地址,而地位保存在内存的低地址,大端模式倒过来的),所以对于变量flag,其高位为0x12保存在最高地址处,而其低位的0x78保存在其变量的起始处。这样的话,当执行函数strcpy(s,"my aaaa")时,它会将从0x28ff16的地址处向上的连续的8个字节分别赋值为字符串“my aaaa”的每个字符(第8个字节是函数strcpy加上的一个字符串终止符0x00)。那么此时的内存情况如下:


可以看到,执行strcpy函数时,它会将变量flag的前两个字节也改写了!(图中红色的表示被改写的,即flag的第一个字节被重新赋值为了字符‘a’,第二个字节被赋值为终止符0x00)。为什么会这样?因为strcpy函数并不检查目的缓冲区的大小边界,而是将源字符串逐一的全部赋值给目的字符串地址起始的一块连续的内存空间,同时加上字符串终止符

所以最后输出变量flag时,其值变为0x12340061,即其高两字节未变,而最低位变为0x61即97,即字符a的ascii码,第二低字节变为0x00,即字符串终止符。

所以,使用strcpy时容易出错,不幸的是,这种bug是不易被发现的。所以需要格外的小心。为了避免出错,可以使用另一个具有相同功能的函数: strncpy,该函数可以指定要复制的字符串的长度。

0 0