序
- gcc/g++ 编译器中提供了对缓冲区溢出的栈保护选项 -fstack-protector
- 栈溢出的时候,core dump 反馈的行数是不准确的,首先通过反汇编,确认是否去执行__stack_chk_fail了,确定栈溢出了,然后使用log 去跟踪到底是哪里发生了问题
- gcc/g++ 默认会开启-fstack-protector 启动栈保护,但要注意的是,它不会对所有的函数都启用栈保护, 只为局部变量中含有 char 数组的函数插入保护代码,这会导致在很底层的时候栈已经发生了溢出,但是这些栈没有栈保护,直到有保护栈的函数才被检测出来报错,就很难排查问题,如果要让所有函数都启动栈保护,可使用-fstack-protector-all
正文
今天在写程序的时候,发现了一个栈溢出的问题,程序大概如下:
void fn2(string str){
}
void fn1(){
const char* str = NULL;
2 => fn2(str);
}
void fn(){
1 => string temp("aaa");
fn1();
}
无论是vsvocde的报错还是gdb的core dump,错误没有报错在 2=>处,而是报在了1=>处, 而1肯定是没有问题的,后来一路打log下去才发现哪里出错了
通过gdb去查看反汇编的报错堆栈的时候,其报错堆栈的最后指向的将要运行代码是__stack_chk_fail, 说明栈溢出了,此时core dump的报错的行是不准的,一定要看汇编
因为该程序编译的时候,没启用-fstack-protector-all, 使用的是g++默认的-fstack-protector,导致在fn2()中其实已经发生了栈溢出却没有被检测到,到fn1()才被检测到
0x00007f5bc51528ea <+1722>: je 0x7f5bc5152910 <rtm_recv_channel_msg(void*, void*)+1760> //判断预存的随机数是否相等,不等,栈被破坏了
0x00007f5bc51528ec <+1724>: jmp 0x7f5bc515290b <rtm_recv_channel_msg(void*, void*)+1755>
0x00007f5bc51528ee <+1726>: mov %rax,%rbx
=> 0x00007f5bc515290b <+1755>: callq 0x7f5bc514c750 <__stack_chk_fail@plt> //abort
0x00007f5bc5152910 <+1760>: mov -0x8(%rbp),%rbx
栈保护
关于栈保护这一块,可以参考一下ref.1,如下图:
栈保护是处于缓冲区溢出攻击而设定的,缓冲区溢出导致保存的上个栈的ebp被修改而设,从而做ret的时候,可以满足攻击者的想法跳转到其想要的指令位置去执行,但因为缓冲区使用上永远都是从下往上使用的,所以在保存的ebp前保存一个数,可以通过检测该数是否发生了改变从而判定ebp是否受到了缓冲区溢出攻击被修改了
开启栈保护的方法如下
-fstack-protector:
启用堆栈保护,不过只为局部变量中含有 char 数组的函数插入保护代码。
-fstack-protector-all:
启用堆栈保护,为所有函数插入保护代码。
-fno-stack-protector:
禁用堆栈保护。