我遇到了我无法解释的事情。这是问题所在

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void ask()
{
    char name[64];
    printf("What is your name ? ");
    scanf("%s",name);
    printf("Hi %s\n", name);
}

int main(int argc, char* argv[])
{
    ask();
    return 0;
}


这里是反汇编的版本:

gdb$ disas ask
Dump of assembler code for function ask:
   0x0804846c <+0>: push   ebp
   0x0804846d <+1>: mov    ebp,esp
   0x0804846f <+3>: sub    esp,0x58
   0x08048472 <+6>: mov    DWORD PTR [esp],0x8048550
   0x08048479 <+13>:    call   0x8048340 <printf@plt>
   0x0804847e <+18>:    lea    eax,[ebp-0x48]
   0x08048481 <+21>:    mov    DWORD PTR [esp+0x4],eax
   0x08048485 <+25>:    mov    DWORD PTR [esp],0x8048565
   0x0804848c <+32>:    call   0x8048370 <__isoc99_scanf@plt>
   0x08048491 <+37>:    lea    eax,[ebp-0x48]
   0x08048494 <+40>:    mov    DWORD PTR [esp+0x4],eax
   0x08048498 <+44>:    mov    DWORD PTR [esp],0x8048568
   0x0804849f <+51>:    call   0x8048340 <printf@plt>
   0x080484a4 <+56>:    leave  
   0x080484a5 <+57>:    ret    
End of assembler dump.


当我将其运行到gdb中时,我中断scanf指令以获取缓冲区地址(堆栈中的第二个地址),然后执行scanf指令,并检查缓冲区地址:0x0b的无踪迹

(gdb) r < <(perl -e 'print "\x0bABCDE"')
--------------------------------------------------------------------------[regs]
  EAX: 0x00000001  EBX: 0xB7FCDFF4  ECX: 0x00000001  EDX: 0xB7FCF354  o d I t s Z a P c 
  ESI: 0x00000000  EDI: 0x00000000  EBP: 0xBFFFF378  ESP: 0xBFFFF320  EIP: 0x08048491
  CS: 0023  DS: 002B  ES: 002B  FS: 0000  GS: 0063  SS: 002B
--------------------------------------------------------------------------[code]
=> 0x8048491 <ask+37>:  lea    eax,[ebp-0x48]
   0x8048494 <ask+40>:  mov    DWORD PTR [esp+0x4],eax
   0x8048498 <ask+44>:  mov    DWORD PTR [esp],0x8048568
   0x804849f <ask+51>:  call   0x8048340 <printf@plt>
   0x80484a4 <ask+56>:  leave  
   0x80484a5 <ask+57>:  ret    
   0x80484a6 <main>: push   ebp
   0x80484a7 <main+1>:  mov    ebp,esp
--------------------------------------------------------------------------------

Breakpoint 1, 0x08048491 in ask ()
gdb$ x/4xw 0xbffff330
0xbffff330: 0x44434241  0xb7e90045  0x0000002f  0xb7fcdff4


如您所见,存在我的ABCDE,后跟空字节0x00,但不会出现\x0b。我不明白为什么scanf不考虑它。 0x090x0c也是如此。但是0x010x080x0e及更高版本正在运行。我有点迷茫。

有什么主意吗?

非常感谢。

PS:之所以在这里发布是因为我当时在二进制文件前面,当我向他发送0x0b之类的字节时,其行为不是我所期望的。我撤消了部分讨论,发现scanf在这里是坏人……但是,如果您认为这不适用于本论坛,请告诉我,我会将其移至更合适的位置。谢谢!

#1 楼

scanf函数会跳过前导空格,而空格是isspace宏/函数为其返回true的字符集。

在标准语言环境中,该字符集由\t(0x09),\n (0x0a),\v(0x0b),\f(0x0c)和\r(0x0d)。当然还有空白字符(0x20)。

评论


谁,为此感谢!我不会猜到的。太好了!

– Hackndo
15年8月10日在9:55

#2 楼

处理scanf时,在\x09~\x0bxd库调用中还有一个有趣的地方。

您只需将\x0b放在输入字符串的开头。如果只是将\x0b放在字符串的中间,并且从头到第一个AAAAAA\x0bBBBBB都有有效的ascii(不在\ x09〜\ x0d中),例如

B

如果再次执行程序,则会发现以下\x0b将被放弃,或者输入字符串将被第二个有效的q4312079q截断。