内存越界引用和缓冲区溢出
c语言对数组不进行边界检查,可能会导致,数组越界访问,导致存储越界,将数组的数据写入其他缓冲区。导致数据丢失、错误。
出现问题的原因:
图片来源https://blog.csdn.net/snowq/article/details/1749087
栈的存储,按照地址从大到小进行存储,先进后出的规则,也就是说后进入的数据存储的地址,要比先进入的数据存储的地址要小。
当给数组分配一个内存时,先将地址做减法,然后每存储一个数据,指针做加法。
如果我们声明一个数组,然后进行存储数据,当数组越界访问时,由于c语言并不会做边界检查所以,当指针存储到最后一个数据时,指针做加法,指向的并不是数组存储的范围,就会导致将其他数据覆盖、更改。
缓冲区溢出导致的问题:
- 可能会将返回时执行语句的地址重写,导致执行原本不会执行的函数。
- 会启动一个shell程序,给攻击者提供操作系统的函数。
对抗缓冲区溢出攻击
栈的随机化
如果攻击者攻击系统,既要插入代码,还要插入指向这段代码的指针,如果攻击者可以知道这段代码的指针,直接插入指针,则可以执行这段代码。
在程序开始时,在栈上分配一段0~n字节随机大小的空间,程序不使用这段空间但是它会导致后续程序执行时,栈的位置发生变化。
栈破坏检测
使用栈保护者机制,在栈帧中任何局部缓冲区与栈状态之间存储一个特殊的金丝雀值,并在恢复寄存器状态和从函数返回之前,程序检查这个金丝雀值,判断是否被更改,如果是,则程序异常终止。
限制可执行代码区域
只有编译器产生的代码的那部分内存才需要是可执行的,其他部分可以被限制为只允许读写。
支持边长栈帧
当一个固定长度的数组分配内存时,可以给定固定的内存,但是如果一个变量作为数组的长度,就会导致分配的内存不固定。引入栈指针和帧指针。
图片来源https://blog.csdn.net/shijunwang/article/details/80217237
大概步骤:
- 先将%rbp寄存器数据压入栈中。
- 计算地址,由于是指针,所以一个元素占用8个字节,所以,按照8的倍数计算,并且,还要将数据对齐,向下取整到最近的16的倍数。
- 计算变长数组的首地址,将除以8(8字节),向上取整。再将地址乘8,得到首地址。