请解释下面的例子。问题很简单,但结果很突然。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char *argv[])
{
int flag = 0;
char passwd[10];
strcpy(passwd, argv[1]);
if(0 == strcmp("LinuxGeek", passwd))
{
flag = 1;
}
if(flag)
{
printf("\n Password cracked \n");
}
else
{
printf("\n Incorrect passwd \n");
}
return 0;
}
标志的值在行
之后变为垃圾值strcpy(passwd, argv[1]);
但是,如果我将变量标志定义为
int flag = 0
行后
strcpy(passwd, argv[1]);
我得到了理想的结果。请简要解释一下。
答案 0 :(得分:6)
简短的回答是,当argv[1]
的长度大于9时,程序的行为是未定义的,因为那样会溢出缓冲区passwd
。
很长的答案显然,你的编译器按照列出的顺序对堆栈中的变量进行排序,因此在flag
之后移动passwd
会在缓冲区和strcmp
之后放置四个额外的零字节在passwd
上将其中一个识别为NUL终止符。
问题的解决方法是跳过无用的复制:
char *passwd = argv[1];
或者完全删除passwd
变量并进行以下比较:
strcmp("LinuxGeek", argv[1])
答案 1 :(得分:2)
当我打印flag
和passwd
的地址时,我分别得到了0x7fff3315c91c
和0x7fff3315c910
。
所以我得出结论,如果argv [1]的大小大于12(passwd
和flag
的地址之间的差异,passwd
的值将覆盖flag的值。 12)。
passwd
地址模型(0x7fff3315c910):
| 10 | 11 | 12 | ........... | 1A | 1B |
flag
地址模型(0x7fff3315c91c):
| 1C | ........
从上面我们可以看到flag
的地址被passwd
答案 2 :(得分:1)
您不对要操作的字符串执行任何检查(长度,空字节),尤其是argv
。例如,输入密码可能不适合您的passwd
变量。