You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过gets向C语言输入含空字符的字符串以演示缓冲区溢出

为什么必须输入'\0'才能让strcmp判定两个字符串相等?

嘿,这个问题我太熟了——完全是C语言字符串的核心规则在跟你“搞事情”!

首先得回忆清楚:C语言里的字符串本质是字节数组,必须以'\0'(空字符)作为终止标志,而strcmp函数的工作逻辑很死:它会逐字节对比两个字符串的内容,要么遇到不相等的字节就停止,要么直到碰到双方的'\0'才会判定相等。

你的场景里,虽然通过gets溢出缓冲区覆盖了相邻的目标变量,但如果没把目标变量对应的字符串终止位置也覆盖成'\0',strcmp就会一直往后读内存里的垃圾数据,自然不会认为两者相等。

举个你大概率会用到的代码例子:

#include <stdio.h>
#include <string.h>

int main() {
    char buffer[16];
    char target[16] = "original"; // 初始化后末尾自带'\0'
    
    printf("Input something: ");
    gets(buffer); // 危险函数,会自动给buffer加'\0'
    
    if (strcmp(buffer, target) == 0) {
        puts("Match success!");
    } else {
        puts("No match...");
    }
    return 0;
}

编译命令:gcc -fno-stack-protector -z execstack -fno-pie -o overflow_demo overflow_demo.c

当你输入超过16个字符时,确实会覆盖target的内容,但如果只覆盖了target的前N个字符,没碰它原来的'\0',或者溢出后target的末尾没被设为'\0',那target的字符串会“失控”地延伸到内存里下一个随机的'\0'位置,这时候和自带'\0'的buffer比,肯定不相等。

怎么解决这个问题?

给你两个实用的思路:

  • 思路一:在溢出输入的末尾手动加'\0'
    构造输入时,填满缓冲区后,先输入你想覆盖到target的字符串内容,再额外加一个'\0'字节。比如缓冲区是16字节,target是16字节,那输入就是:16个填充字符 + 你要的目标字符串 + 1个'\0',这样target的末尾就会被强制设为'\0',strcmp就能正确匹配了。

  • 思路二:精准覆盖到target原有的'\0'位置
    其实更高效的是,找到target原字符串的'\0'所在的内存偏移,在溢出时直接把那个位置覆盖成'\0'(或者覆盖成你要的字符串的一部分,同时确保末尾是'\0')。比如原来的target是"original",它的'\0'在第9个字节,那你溢出时除了覆盖前8个字符,还要把第9个字节改成'\0',这样target就变成了你想要的字符串,并且正确终止。

额外小提示
  • gets函数会自动给输入的缓冲区加'\0',所以buffer的字符串是天然终止的,但target的终止符必须你通过溢出手动设置。
  • 如果调试时发现地址乱飘,记得加-fno-pie编译参数关闭地址随机化,这样栈地址固定,更容易精准溢出。

内容的提问来源于stack exchange,提问作者firedrillsergeant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.20 11:07:27