为什么scanf()仅在匹配指定文本后才读取输入?
为什么scanf()仅在匹配指定文本后才读取输入?
嘿,这个问题我当初刚接触scanf的时候也踩过坑,咱们结合你贴的CTF逆向代码来唠明白~
先把你那段代码整理成可读格式(看起来后面没贴完,但核心是这个scanf的用法):
int main(void) { int iVar1; char input[32]; fwrite("Password: ",1,10,stdout); __isoc99_scanf("DoYouEven%sCTF",input); iVar1 = strcmp(input,"__dso_handle"); if ((-1 < iVar1) && (iVar1 = strcmp(input,"__dso_handle"), iVar1 < 1)) { printf("Try again!"); return 0; } // 剩余代码省略 }
本质上,scanf的格式串里,除了%s、%d这类格式说明符,其他普通字符都是「强制匹配项」。它的工作逻辑不是“跳过这些字符直接读变量”,而是:
- 会从输入流里逐个字符比对这些普通文本,必须完全匹配(字符、顺序都不能错),才会继续处理后面的格式说明符。
- 只有匹配完前面的
DoYouEven之后,%s才会开始把后续的非空白字符读到input里;而且读完之后,scanf还会继续等着输入里出现CTF这三个字符,要是没匹配上,这次scanf操作就相当于失败了,input里的内容可能完全不是你预期的那样。
就拿这个CTF题来说,出题人就是故意挖了个坑:很多人看到要让input不等于__dso_handle(因为if里判断等于的话就输出Try again),可能直接输入__dso_handle,但实际上scanf根本不会把这个值读到input里——因为输入开头没有DoYouEven,scanf一直在等着匹配这个前缀,自然不会处理%s。
正确的输入得是DoYouEven__dso_handleCTF:
- 先匹配上
DoYouEven,触发%s读取中间的__dso_handle到input; - 最后匹配上末尾的
CTF,整个scanf操作才算完成。
说白了,scanf设计成这样,就是为了支持「格式化输入匹配」——比如你要读取一个日期,写"%d/%d/%d",就要求输入必须是2024/10/01这种带/的格式,中间的/就是强制匹配项,少一个都不行,这样才能保证读入的是符合格式的日期数据。
这种用法在逆向CTF里特别常见,就是利用新手对scanf格式串的不熟悉,设下匹配陷阱,一不小心就踩坑~
内容来源于stack exchange
相关产品推荐
相关产品推荐

