参考答案:
【问题1】
输入的字符串样式满足其前12个字符和后续12个字符一样;中间的字符串长度刚好可以填充userPassword和origPassword之间堆栈缓冲区的位置即可,当然整个字串不会引起代码运行的崩溃。
【问题2】
gets()函数必须保证输入长度不会超过缓冲区,一旦输入大于12个字符的口令就会造成缓冲区溢出。
解决思路:使用安全函数来代替gets()函数,或者对用户输入进行检查和校对,可通过if条件语句判断用户输入是否越界。
详细解析:
1、函数strncmp(str1,str2,n)【参数】str1,str2 为需要比较的两个字符串,n为要比较的字符的数目。字符串大小的比较是以ASCII 码表上的顺序来决定,此顺序亦为字符的值。Strncmp()首先将s1 第一个字符值减去s2 第一个字符值,若差值为0 则再继续比较下个字符,直到字符结束标志'\0',若差值不为0,则将差值返回。
【返回值】若str1与str2的前n个字符相同,则返回0;若s1大于s2,则返回大于0的值;若s1 若小于s2,则返回小于0的值。
程序中在定义两个数组时,会分配两个12位的地址空间,origPassword在前,userPassword在后,gets()函数中,当userPassword输入位数大于12位时,就会溢出,多出来的字符将被写入到堆栈中,这就覆盖了堆栈原先的内容,根据函数的作用,只要userPassword的值和origPassword的值一致则可绕过该口令验证函数的机制;当输入的字符串样式满足其12个字符和后续12个字符一样,而中间的字串长度刚好可以填充userPassword和origPassword之间堆栈缓冲区的位置时,根据堆栈的后进先出原理,当读取userPassword的值时,溢出的后续12位会读取到userPassword中,而在读取origPassword的值时会读取到原先userPassword中的值,如此两个数组的值就会一致,从而绕过该口令验证函数的限制。
2、gets()函数可以无上限的读取,而且不会判断上限,因此,gets()函数必须保证输入长度不会超过缓冲区,一旦大于该缓冲区就会造成溢出。可以使用安全函数来代替gets()函数,比如fgets()函数,或者对用户输入进行检查和校对,可通过if条件语句判断用户输入是否越界。