缓冲区溢出笔记(2.0)

来源:互联网 发布:新网域名别名解析 编辑:程序博客网 时间:2024/05/08 15:41

首先得会内存、寄存器还有程序运行的规则。

存储知识:

     文件地址(File Offset):数据在PE文件中的地址,文件在磁盘上存放时相对于文件开头的偏移;

     虚拟内存地址:用户程序看到的存储空间,每个进程都有4G虚拟空间,以下说的内存、所有的存储空间都是虚拟内存;

     物理内存地址:操作系统才能看到,用户程序不能接触;

这三个地址要层层映射


内存:

    代码区:存放二进制代码

    数据区:存储全局变量

    堆区:动态内存空间(由程序员分配)

    栈区:存放函数调用关系(缓冲区溢出就在这里发生)(由编译器分配)


重点研究栈的结构:

     栈帧:每个函数有自己的栈帧,只有被调用的函数才会在系统栈开辟栈帧,调用完毕将弹出栈帧

     两个寄存器(用于标示当前正在执行的函数的栈帧):

         ebp:指向栈顶的底部

         esp:指向栈顶的顶部

    发生函数调用时栈帧的创建过程:

          参数入栈

         返回地址入栈

         保存当前栈帧状态,也就是主调函数栈帧的ebp和esp,一般情况下只要ebp就行

         把esp寄存器内容装入ebp寄存器,即创建被调用函数的栈帧作为当前栈帧

         根据被调用函数需要的变量情况开辟一定大小的空间,用esp减去空间就得到当前栈帧的栈顶(从栈底到栈顶内存地址从高到底)


  


注意:返回地址是被调函数被调用指令的下一条指令地址,是代码区的地址。

被调函数执行结束之后弹出栈的过程是这样的:

   1.esp加上局部变量占用的空间

   2.弹出ebp,ebp指向调用者函数

   3.返回地址存入指令寄存器eip

   4.esp加上两个内存单元的大小也就是之前ebp和返回地址占用的空间

   5.esp加上参数占用的空间。这样就完成了被调函数和调用者函数栈帧的转换。

明白了这些就可以开始缓冲区溢出小实验了:

#include<stdio.h>void hack(){printf("hello");//_exit(0);return;}int main(){int a[0];    a[3]=0x004016b6;return 0;}


主函数并没有调用hack()函数但是输出为



看了下图就明白了


我们知道数组是从a[0]的位置开始向后移动的,那么a[3]的位置(如图的话应该是a[2]才对,但这里a[3]才行,这是视具体的机器而定的因为还有编译优化的问题)正好是返回地址,但是给a[3]赋值为hack()函数的起始地址那么main函数就会跳转到hack()的地址执行hack函数。注意main函数也有返回地址。另外这里为什么输出两个“hello world”我还不清楚原因,如果把hack()函数的“return”改为"_exit(0)"就只输出一个"hello world",这是为什么呢,如果有大神知道原因还请赐教。

hack()函数的地址先通过正常调用一次然后用IDA工具很容易就找到了。反汇编软件爆破就要用到上面的三个存储地址的映射关系。

没想到写得这么累。

大概先这样。

0 0
原创粉丝点击