1.3.1 溢出例子――报错对话框
“这个很简单的程序是这样的。”老师在墙上做出投影。
/*很简单的程序:*/
#include<stdio.h>
#include<string.h>
char name[] = “ww0830”;pu
int main()
{
char output[8];
strcpy(output, name);
for(int i=0;i<8&&output[i];i++)
printf("\\0x%x",output[i]);
return 0;
}
“这个程序,还比较简单吧?”老师小心翼翼的问台下的同学。
台下一阵默然,同学们都在头晕中呢……
“好,我来解释一下!这是用C语言写的程序!”老师说。
台下一阵狂晕:“地球人都知道!”
“不要急,我一句一句的来。首先, #include<stdio.h> 和 #include<string.h> 是包含这两个头文件进来,因为后面使用的strcpy函数和printf函数是这两个头文件中定义的。”
“嗯,这个清楚了。”
“然后, char name[] = “ww0830”; 是把‘name’这个数组赋值,往里面放入‘ww0830’这几个字符。”
“哦,为什么要放入‘ww0830’而不放其他的呢?”大家疑惑不解。
“因为这是我的名字啦,哈哈!这个并不重要,什么都可以放,后面大家就会看到的。然后是 int main(){ …… } ,这个是重点啦,这就是我们常说的主函数!程序进来就是先找到这个地方,执行里面的语句。”
“接下来的 char output[8]; strcpy(output, name); 就是让系统给output变量分配8个char的空间,然后把‘name’里面装的字符拷贝给它。”
“ strcpy(des,source) 这个拷贝函数是把第二个参数source的值拷给第一个参数des。它不检查拷贝的长度,它会一直拷贝,直到source到结尾。这就是它的弱点了!”
“下面的 for(int i=0;i<8&&output[i];i++) printf("\0x%x",output[i]); 只是让大家方便检查output里面的值而已,我把它以16进制的形式打出来。”
台下听得聚精会神,一片安静。
“好,让我们运行一下,看看结果吧!在VC中编译、链接、执行,如图1-1。”
“看,打出来的是 \0x77\0x77\0x30\0x38\0x33\0x30 ,77就是‘w’的16进制表示,而30、38、33、30就是‘0830’的16进制表示。程序运行后一切正常,把‘ww0830’的16进制打出后,安全退出了。”
“嗯,呼……”台下长出了一口气,连几个女生也说道,“对,明白了,明白了。”
“呵呵,大家明白了就好。刚才大家不是问为什么要输入‘ww0830’吗,好!那我稍微改一下,改成其他的。”
“这次我把‘name[]’的值赋成‘abcdefgh’,大家再看看运行的结果有什么问题没有!如图1-2。”
台下的同学使劲的看啊看,什么都没看出来,最后玉波小心翼翼的问:“只是把‘abcdefgh’的十六进制61、62、63等打出来嘛,有什么问题吗?”
老师瞟了一眼,然后说道:“对!其实就是没有问题!”
台下狂倒……
“不是啊,不是啊”老师忙解释,“目的是让大家清楚的看下面真正的玄机。”
“这次我把‘name’再改长点,改成‘abcdefghijklmnopqrstuvwxyz’再运行,如图1-3。”
“哦哦哦……不得了了,出错了!”台下一阵恐慌。
“哈哈!不要急。”老师摆出一副天塌下来自己顶的模样。“大家来仔细看看这个出错的警告是什么。”
“是0x706f6e6d引用的0x706f6e6d内存,该内存不能为read。”玉波喃喃的念道。
“你们不觉得‘6d6e6f70’这些很熟悉吗?我们的第二个程序中打出的……”老师提示道。
“哦!‘abcd’是‘61626364’,那么‘6d6e6f70’就应该是mnop了。”那位瘦瘦的同学一阵埋头苦算后说道!
“Good,这位同学能不能给大家介绍一下自己呢?”
那位瘦瘦的同学说道,“我叫古风。”
从古风灰灰的衣服、黑黑的脸上能看出他是从农村来的。他的眼神里带着中华民族勤奋刻苦的优良传统。
“大家都要向古风同学习啊!”老师说道,“我给一个对应转换表吧,以后大家直接查就可以了。”老师打出表1所示的表格:
(黑手教程中的这个表格有问题,所以我自己做了一个贴了出来,并不是原先的那个表格)