由于栈是向地地址增长的,数组缓冲区是向高地址增长的。故,长一些的字符串会导致gets覆盖栈上存储的某些信息。
随着字符串变长,下面的信息会被破坏:
输入的字符数量 被破坏的状态
0---7 无
8---11 保存的%ebx的值
12---15 保存的%ebp的值
16---19 返回地址
20+ caller中保存的状态
如果破坏了存储%ebp的值,那么基址寄存器就不能正确地恢复,因此调用者就不能正确地引用它的局部变量或参数。
如果破坏了存储的返回地址,那么ret指令会使程序跳转到完全意想不到的地方。
缓冲区溢出的一个更加致命的使用就是让程序执行它本来不愿意执行的函数。这是一种最常见的通过计算机网络攻击系统安全的方法。通常,输入给程序一个字符串,这个字符串包含一些可执行代码的字节编码,称为攻击代码,另外还有一些字节会用一个指向攻击代码的指针覆盖返回地址。那么,执行ret指令的效果就是跳转到攻击代码。
通常,使用gets或其他任何能导致存储溢出的函数,都不是好的编程习惯。不幸的是,很多常用库函数,包括strcpy、strcat、sprintf,都有一个属性——不需要告诉它们目标缓冲区的大小,就产生一个字节序列。
对抗缓冲区溢出攻击
1、栈随机化
为了在系统中插入攻击代码,攻击者不但要插入代码,还要插入指向这段代码的指针,这个指针也是攻击字符串的一部分。产生这个指针需要知道这个字符串放置的栈地址。在过去,程序的栈地址非常容易预测,在不同的机器之间,栈的位置是相当固定的。
栈随机化的思想使得栈的位置在程序每次运行时都有变化。因此,即使许多机器都运行相同的代码。它们的栈地址都是不同的。
实现的方式是:程序开始时,在栈上分配一段0--n字节之间的随机大小空间。程序不使用这段空间,但是它会导致程序每次执行时后续的栈位置发生了变化。缓冲区溢出攻击
在Linux系统中,栈随机化已经变成了标准行为。(在linux上每次运行相同的程序,其同一局部变量的地址都不相同)
2、栈破坏检测
在C语言中,没有可靠的方法来防止对数组的越界写,但是,我们能够在发生了越界写的时候,在没有造成任何有害结果之前,尝试检测到它。
最近的GCC版本在产生的代码中加入了一种栈保护者机制,用来检测缓冲区越界,其思想是在栈中任何局部缓冲区与栈状态之间存储一个特殊的金丝雀值。这个金丝雀值是在程序每次运行时随机产生的,因此,攻击者没有简单的办法知道它是什么。
在恢复寄存器状态和从函数返回之前,程序检查这个金丝雀值是否被该函数的某个操作或者函数调用的某个操作改变了。如果是,那么程序异常终止。
3、限制可执行代码区域
限制那些能够存放可执行代码的存储器区域。在典型的程序中,只有保存编译器产生的代码的那部分存储器才需要是可执行的,其他部分可以被限制为只允许读和写。
现在的64位处理器的内存保护引入了”NX”(不执行)位。缓冲区溢出攻击有了这个特性,栈可以被标记为可读和可写,但是不可执行,检查页是否可执行由硬件来完成,效率上没有损失。
转载自:
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-28104-1.html
醉了永远半张脸
恰恰证明该产品值得购买
大陆迟早要乱的
看的回复一下我