扫描溢出(“%8s”,字符串)?

时间:2009-11-24 04:58:48

标签: c scanf buffer-overflow

我知道溢出普通代码是可能的:

char string [9];

scanf(“%s”,string)。

但是有可能溢出scanf(“%8s”,字符串)吗? 8只是一个例子。

我知道“%8s”就像分隔符一样,但我也注意到当我输入长度超过8个字符的字符串时,程序将因以下原因终止:

*检测到堆栈粉碎* :./a.out已终止

======= Backtrace:=========

...

显然,有一个标志可以检测到GCC默认打开的堆栈粉碎。由于这是一个堆栈粉碎,我的猜测是它仍然可以溢出并执行任意代码。

与正常溢出相反,会破坏scanf(“%s”)的调用者,如果scanf(“%8s”)可能溢出,它将在scanf函数内溢出,这样当scanf尝试返回时,将获得控制权。 / p>

但是scanf是一个系统调用,它需要模式切换(从用户模式切换到内核模式),并且在内部它会调用诸如read之类的东西到stdin等。所以不确定我们是否可以在内核模式或其他东西溢出。

欢迎评论!!

更新>>

在上面的例子中假设了字符串[9]。以下真实代码中的字符串[8]。

问题在于安全扫描(“%8s”)与GCC堕胎之间看似矛盾的故事,因为堆栈粉碎。

简化代码:

void foo(pass some pointer) {
char input[8];
int input_number = 0;

while (1) { // looping console
   printf some info;
   scanf("%8s", input);

   input_number = atoi(input);

   if ((strlen(input) == 1) && (strncmp(input, "q", 1) == 0)) {
       input_number = -1;
   }
   switch (input_number) {
       case -1: to quit the console if input = 'q';
       default: to print info that pointer refers to;
       ...
   } 

}

}

注意:

  1. foo被其他人召唤。
  2. 虽然字符串是实际的8个字节 代码用“%8s”,我不这么认为 导致粉碎。

4 个答案:

答案 0 :(得分:8)

请参阅http://www.opengroup.org/onlinepubs/009695399/functions/scanf.html

  

每个指令由以下之一组成...一个可选的非零十进制整数,指定最大字段宽度。

     

取值
     匹配不是空格字符的字节序列。应用程序应确保相应的参数是指向char,signed char或unsigned char数组的初始字节的指针,其大小足以接受序列和终止空字符代码,这些代码应自动添加。

因此它不会溢出9字节的字符串缓冲区。

答案 1 :(得分:3)

如果您希望输入功能强大,请永远使用scanf(或fscanf)。

您应该使用fgets(或类似的“受缓冲区溢出保护”变体),然后使用sscanf

scanffscanf的主要问题是,如果行不符合预期格式(例如,scanf失败,则文件指针可能会以不确定的位置结束) )。使用fgets/sscanf方法,可以更加轻松地保证您处于行边界,而无需使用ftellfseek来移动文件。

关于缓冲区是否会溢出的具体查询,C标准可以这样说:

  

...相应的参数应该是一个指向大小足以接受序列的字符数组的初始元素的指针,以及一个自动添加的终止空字符。

因此,对于"%8s"格式,您需要一个9个字符的数组。

我怀疑你的代码中还有其他一些问题。有了测试程序:

#include <stdio.h>
int main(int argc, char* argv[]) {
    char x1;
    char a[9];
    char x2;
    x1 = x2 = ' ';
    scanf ("%s",a);
    printf ("[%c] [%s] [%c]\n",x1,a,x2);
    return 0;
}

我明白了:

pax> ./qq.exe
dfjdhadgha...lghjdfgjhd
[s] [dfjdhadgha...lghjdfgjhd] [ ]
  6 [main] qq 4744 _cygtls::handle_exceptions: Error while dumping state
  (probably corrupted stack)
  Segmentation fault (core dumped)

当我更改同一个程序以使用"%8s"时,我得到(对于完全相同的输入):

pax> ./qq.exe
dfjdhadgha...lghjdfgjhd
[ ] [dfjdhadg] [ ]

答案 2 :(得分:1)

如果为少于8个章程分配字符串,它肯定会覆盖缓冲区,scanf也不会附加空终止符。但是只要你的字符串中有足够的空间来代表你的价值,你就不应该过分重视。

答案 3 :(得分:1)

正如ysth指出的,数组应该能够包含字符串终止空字符,所以使用8字节数组(特别是如果它在栈上分配,因为它是在你的代码中)很可能搞砸了。