《黑客攻防技术-系统实战》第二章--栈溢出1

作者:银河娱樂城   来源:http://www.materia-ic.com    栏目: 银河娱乐游戏官网    日期:2019-11-16

  栈缓冲溢出一直是最流行, 我们理解最透彻的安全问题之一,尽管栈缓冲溢出是我们最了解,最公开的漏洞之一,但是现在在我们的软件中仍然存在栈溢出的问题,在这里首先介绍栈缓冲溢出的问题

  希望通过栈溢出这一系列的文章,可以对栈有更深刻的理解,避免在编码的时候出现这种问题,另外我们可以利用栈缓冲存在的漏洞对系统进行攻击动作,这是这次学习的目标

  “缓冲区”: 一片有限,连续的内存区域, 在C语言中,最常见的缓冲区就是数组, 这节主要介绍与数组有关的内容

  在C语言中,没有专门的机制去考虑检查缓冲区的内在边界, 所以栈溢出就容易出现,一旦输入的数据超出缓冲区的范围,从而改写其他缓冲区域, 什么事情都会发生

  因为是作为演示,这里我们故意打印下标5, 编译运行结果会得到一个非常奇怪的数字:

  这个例子显示,当C没有提供内存保护机制的时候,越过缓冲区读取其他数据是非常容易的,如果我们输入的数据超出缓冲区会发生什么呢?

  为什么要设置255这么大呢? 为了达到效果, 增大踩内存的概率, 因为并不是所有超出内存的读写都会导致问题, 只有超出的内存已经有有效数据的时候出错

  为什么我们要介绍栈呢? 和上面内容有什么关系呢? 我们看一下下面的C 程序的内存布局,然后分析一下

  那么我们看一下数组应该是在栈里面分配的, 为什么我们不放在堆里面呢?下面我们对比一下堆和栈的本质区别或许就知道原因了

  栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出。

  堆:首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,

  会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块 内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的 大小,系统会自动的将多余的那部分重新放入空闲链表中。

  栈:在Windows下,栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因 此,能从栈获得的空间较小。

  堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。

  堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便.

  另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,他不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。

  栈: 在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。

  当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。

  这里我们从底层的角度来看为什么函数使用栈呢? 主要目的是为了更有效的使用函数, 函数可以改变程序执行的流程, 因此,一条指令可以单独执行, 更重要的是,

  函数执行结束之后将把控制权交给调用者, 通过使用栈, 函数的整个调用过程更有效率

  这个例子中, 系统首先会先执行main里面的指令, 碰到函数调用的时候, 系统中断正常流程, 进行函数调用的前的处理,然后执行function里面的指令,整个过程是:

  function 的参数a, b 参数圧入栈 == 系统调用函数,把函数的返回地址(RET, RET保存的是调用函数是的指令指针EIP的地址)压入栈 == 调用函数

  说下为什么这么编译: 因为我们要进行反汇编,进行gdb调试所以需要加上-ggdb选项, 另外我们还应该使用优化栈边界选项,因为它将使栈以双字节单位递增(或递减),

上一篇:堆和栈的区别doc       下一篇:堆和栈的区别 学步园