样例 1

#include <stdio.h>
#include <string.h>
 
#define MAX_SIZE 256
 
void safe_function(char *input) {
    char buffer[MAX_SIZE];
    // 使用strncpy防止溢出
    strncpy(buffer, input, sizeof(buffer));
    printf("Received: %s\n", buffer);
}
 
int main() {
    char input[] = "This is a test string that should not exceed the maximum size.";
    safe_function(input);
    return 0;
}

strncpy 不会自动在目标缓冲区末尾添加空终止符(\0)。如果输入字符串长度等于或超过 buffer 的大小(MAX_SIZE),buffer 将不是一个合法的 C 字符串,后续操作(如 printf)可能导致内存越界读取或程序崩溃。

修复的话就手动添加终止符(或者直接用 strncpy 的填充 0)

strncpy(buffer, input, sizeof(buffer) - 1);

样例 2

#include <stdio.h>
#include <string.h>
 
void vulnerable_function() {
    char buffer[64];
    printf("Input: ");
    gets(buffer);
    printf("You entered: %s\n", buffer);
}
 
int main() {
    setvbuf(stdout, NULL, _IONBF, 0);
    vulnerable_function();
    return 0;
}

gets 函数不检查输入长度,当输入超过 buffer 的容量(64 字节)时,会导致缓冲区溢出,覆盖栈上的关键数据(如返回地址),可以任意代码执行。

可以使用安全的输入函数

fgets(buffer, sizeof(buffer), stdin);

样例 3

#include <stdio.h>
#include <string.h>
 
void success(void) { puts("You Hava already controlled it."); }
 
void vulnerable(void) {
    char s[12];
 
    gets(s);
    puts(s);
 
    return;
}
 
int main(int argc, char **argv) {
    vulnerable();
    return 0;
}

gets 未限制输入长度,输入超过 12 字节会溢出 s 数组。可覆盖栈上的返回地址,劫持程序流程(如跳转至 success 函数)

修复也是修改为更加安全的函数

fgets(s, sizeof(s), stdin);

这里局部变量没有初始化,不过 fgets 函数只会读取 n-1 个字符(如果遇到换行符会更少),并在最后添加字符串结束标志,所以直接这么改就行了