【发布时间】:2015-02-26 15:11:59
【问题描述】:
我在 unix 版本 6 的 if.c 中找到了这一行。
ncom = "/usr/bin/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
为什么有这么多x? 为什么要设置这个?
【问题讨论】:
我在 unix 版本 6 的 if.c 中找到了这一行。
ncom = "/usr/bin/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
为什么有这么多x? 为什么要设置这个?
【问题讨论】:
您所说的代码如下所示:
ncom = "/usr/bin/xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
while(c=nargv[0][i]) {
ncom[9+i++] = c;
}
ncom[9+i] = '\0';
所有这些 x 都充当缓冲区,它们被以下循环覆盖。
因此代码有效地将“/usr/bin/”添加到nargv[0] 中的命令中。
有了更多的上下文,代码就是这样做的:
execv(nargv[0], nargv, np);
execv(ncom+4, nargv, np);
execv(ncom, nargv, np);
如果nargv[0] 中的给定命令是"foo",它将首先尝试运行"foo",然后是"/bin/foo",最后是"/usr/bin/foo"。
请注意,上面是一个很好的例子,如何不做这样的事情:
如果nargv[0] 中的字符串恰好比x 的个数长,代码将愉快地继续复制数据。这将覆盖堆栈的其他部分。结果是缓冲区溢出的一个很好的例子。 (您分配了一些大小的缓冲区并写入了比分配更多的数据。)
这个例子将演示这个问题:
#include <stdio.h>
int main(){
char s[]="abcde";
int i;
for(i=0;i<100;i++){
printf("position %2d contains value %3d\n",i,s[i]);
s[i]=0;
}
puts(s);
return 0;
}
如果你运行它,它(很可能)会输出这个:
position 0 contains value 97
position 1 contains value 98
position 2 contains value 99
position 3 contains value 100
position 4 contains value 101
position 5 contains value 0
position 6 contains value 0
position 7 contains value 0
position 8 contains value 0
position 9 contains value 0
position 10 contains value 0
position 11 contains value 0
position 12 contains value 12
position 1 contains value 0
position 2 contains value 0
position 3 contains value 0
position 4 contains value 0
position 5 contains value 0
position 6 contains value 0
position 7 contains value 0
[...]
它将用零填充字符串(包含 ASCII 值 97 到 101)并继续写入内存,它将找到变量 i 的位置,它还将它设置为零。现在i 为零,因此循环再次开始,一次又一次地覆盖已经覆盖的字符串。
不仅局部变量可以被覆盖,函数的返回地址也可能被覆盖,导致“分段错误”或执行任意代码,这通常被恶意软件使用。
【讨论】:
ncom 指向一个 字符串文字,然后对其进行修改 - 现代 C 中的一个大禁忌,其中字符串文字通常被存储在只读存储器中。
ncom 代码不是一个好的防御性编程示例,但实际上该字符串足够长,用户可以正确使用该程序,因为在 V6 中,您永远不需要运行长度超过 14 个字符的无路径名命令(命令名称中某处没有“/”字符的命令),因为这是目录中最长的条目。使用不当,估计会覆盖libc使用的数据。