缓冲区溢出测试程序执行后出现Segmentation Fault的原因咨询
关于缓冲区溢出后出现Segmentation Fault的原因分析
先梳理下你提供的测试代码和现象:
测试代码(buffer.c)
#include<stdio.h> #include<stdlib.h> #include<string.h> int pass(char password[]) { int auth=0; char p[16]; strcpy(p,password); if(strcmp(p,"Hello")==0) { auth=1; } return auth; } void main(int argc,char *argv[]) { if(pass(argv[1])) { printf("----ACCESS GRANTED----\n"); } else { printf("----ACCESS DENIED----\n"); } } //aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa // aaaaaaaaaaaaaaaaaaaaaaaaaaaaa
测试结果
- 正常输入的预期结果:
gcc -g buffer.c ./a.out Hello ----ACCESS GRANTED----
(此结果符合预期。)
- 输入较长字符串触发缓冲区溢出,绕过验证:
./a.out aaaaaaaaaaaaaaaaaaaaaaaaaaaaa ----ACCESS GRANTED----
(表明发生了缓冲区溢出。)
- 输入更长字符串后出现段错误:
./a.out aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa ----ACCESS GRANTED---- Segmentation fault
为什么会出现Segmentation Fault?
这要从栈内存的布局和函数调用的栈帧结构说起:
在pass函数的栈帧里,局部变量的布局大概是这样的(具体顺序可能因编译器和架构略有不同,但核心逻辑一致):
- 首先是
char p[16],占16字节的栈空间 - 接下来是
int auth,占4字节(32位架构)或8字节(64位架构)的栈空间 - 再往下是函数的返回地址(保存着
pass函数执行完后要回到main函数的哪个位置继续执行),还有栈基址指针等关键数据
当你输入的字符串长度超过16字节时:
- 前16字节填满
p数组 - 接下来的字节会覆盖
auth变量的值,把原本的0改成非0值(比如全是'a'的话,对应的ASCII值是0x61,属于非0),所以pass函数返回1,main函数输出ACCESS GRANTED - 但当输入的字符串长度继续增加,超过
p+auth的总长度后,就会继续覆盖栈上更靠后的返回地址。当pass函数执行完毕,要跳转到返回地址指向的位置时,这个地址已经被你输入的无效数据(比如0x61616161这类无意义的地址)覆盖了,而这个地址通常不属于程序的合法内存空间,CPU尝试访问这个无效地址时,就会触发操作系统的内存保护机制,抛出Segmentation Fault(段错误)。
简单来说:短的超长输入只是篡改了auth变量让验证通过,但更长的输入篡改了函数的返回地址,导致程序执行到了非法内存区域,触发段错误。
内容的提问来源于stack exchange,提问作者Aaryan BHAGAT
相关产品推荐
相关产品推荐

