1.栈随机化
①为了在系统中插入攻击代码,攻击者还要插入指向这段代码的指针。产生这个指针需要知道字符串的栈地址。
②栈随机化使得程序每次运行栈的位置都有变化。不同机器运行同样的代码,栈的位置不一样。
实现:
程序开始时在栈上分配一个0~n字节的随机大小空间。
使用分配函数 alloca 在栈上分配指定字节数量 的空间。 程序不使用这段空间 ,但是它会导致程序 每次执行时后续的栈位置发生了变化 。分 配的范围 必须足够大,才能获得足够多样的栈地址变化,但是又要足够小,不至千浪费程 序太多的空间。
③Linux系统中,栈随机化是
地址空间布局随机化技术
ASLR中的一种。
每次运行时程序的不同部分,包括
程序代码、库代码、栈、全局变量和堆数据
,都会被加载到存储器的不同区域。
执著的攻击者如何克服随机化?
蛮力法。反复用不同地址进行攻击。常见把戏:攻击代码前面一段很长的nop指令序列(空操作雪橇nop sled),只要猜中了这段序列中某个地址,就能够通过这段序列到达攻击代码。例如:一个256字节的nop序列,破解的随机化, 枚举
地址。
因此:ASLR技术增加了成功攻击系统的难度,但是不能提供完全的安全保障。
2.栈破环检测
①局部缓冲区超越边界的破坏。
②栈保护机制(stack protector):
在栈中局部缓冲区与栈状态之间插入栈保护者——canary(金丝雀、哨兵值)
随机产生,在恢复寄存器状态和从 函数返回之前,程序检查这个金丝雀值是否被该函数的某个操作或者该函数调用的某个函数的某 个操作改变了。如果是,那么程序异常中止。
gcc中用命令行选项 "-fno-stack-protector" 来阻止产生这种代码。


指令参数
%gs:20
指明金丝雀值用段寻址
(segmented
addressing)
从存储器中读入。
将金 丝雀值存放在一个特殊的段中,标志为“只读”,这样
攻击者就不能覆盖存储的金丝雀值
。在恢复寄存器状态和返回前,函数将存储在栈位置处的值与金丝雀值做比较。
3.限制可执行的代码区域
在典型的程序中,只有保存
编译器产生的代码的那部分存储器才需要可执行的
。其他部分可以被限制为只允许读和写。
虚拟存储器空间在逻辑上被分成了页 (page), 典型的每页是 2048 或者 4096 个字节。硬件支持多种形式的存储器保护,能够指明用户程序和操作系统内核所允许的访问形式。以前, x86 体系结构将读和执行访问控制合并成一个 位的标志,这样任何被标记为 可读的页也都是可执行的。栈必须是既可读又可写的,因而栈上的字节也都是可执行的。最近,AMD为它的64位处理器的内存保护引入了“NX" (No-execute, 不执行)位,将读和执行访问模式分开,并且Intel也跟进了。有了这个特性,栈可以被标记为可读和可写,但是 不可执行,检查页是否可执行由硬件来完成,效率上没有损失。
参考:《深入理解计算机系统》——RandaLH BEyant David ROallaron