其他分享
首页 > 其他分享> > memcpy函数实现缓冲区溢出漏洞

memcpy函数实现缓冲区溢出漏洞

作者:互联网

本次实验需要用到的环境和工具要是需要的可以留言评论,我就不一一介绍了,估计也没啥人看。主要是太多了,我不想打字。

学习这个漏洞我们要去学习漏洞的理论知识。

在汇编程序的执行过程中,如果需要调用某个函数一般是call函数地址,而call这条指令在执行的时候会把函数返回地址(执行完函数后要执行的下一条指令的地址)压栈,然后在栈中的伸展方向是从高地址向低地址延申的。这里可能不是很好理解,我画个图hhhh,比如我在执行call指令时压栈的返回地址的在栈中的序号是10000,然后我调用函数的变量也需要压榨,我申请的一个空间为10的数组,所以我就会申请9990到10000这10个格子用来放参数,然后在存参数的过程中其实栈指针是从低地址移向高地址,第一个参数存9990,第二个存9991,,,但是如果我们的申请的空间是10但是实际上有20个参数的话,参数还是会继续往栈中存,就会覆盖原本存函数返回地址的数据。

 

当执行完memcpy函数以后,就是那个栈平衡,就会把栈中的调用函数入栈的数都出栈,直到把存返回地址的位置出栈到EBP,EBP的地址是当前指令的地址,EIP的地址是下一条指令的地址。

那我们想想,如果我们把恶意代码作为参数传到栈中,然后想办法让函数返回以后再跳回栈中执行栈中的恶意代码,那不就能实现栈溢出了吗?

所以问题就在于,1.如果我们存的数据造成了栈溢出,那么数据是从哪里开始溢出的(覆盖返回地址的数据)?2.如何让已经返回的主程序EIP再回到栈中执行我们存进去的恶意代码?

 先展示一下实验的包含溢出漏洞代码程序:

 

 可以看出我们在主函数中调用并overflow函数,并传了参数shellcode进去,在overflow函数里面,有调用memcpy函数,这个函数是复制字符串到数组中,申请的数组长度为10,但是我们传的参数shellcode是大于数组的空间的。

实验思路:先找到程序运行时memcpy函数返回地址在栈中的位置被shellcode的哪一部分覆盖了,然后修改shellcode覆盖返回地址的部分为jmp esp(回到栈中)的字节码(汇编的字节码),在shellcode中jmp esp后改为我们要执行的恶意代码的字节码,就能实现溢出。也许这里讲的很抽象,但是通过调试跟踪就会明白,下面我们来记录一下调试的过程。

调试用vc++6.0调试,因为能看到堆栈变化过程,还能看到反汇编的代码,和字节码,以前觉得好难,现在觉得好强大hhhhh。

打个断点,让鼠标停在打断点那行代码上,点那个小手,然后出现一个红色的圆点,就是断点:

 

 然后点击框起来的地方,就能调试并停在断点出,如果没有编译的话,编译器会提醒你编译,照做就行。

 

运行停在断点处后,点我圈起来的三个图标,从左到右依次是,显示寄存器,显示内存情况(后面可以搜索看栈的内容),显示反汇编代码

 

 

 然后点下一步,圈出来的是步过和步入,我一般喜欢步过,不明白去别的可以百度一下。

 

 可以看到call memcpy和把返回地址出栈到ebp然后ret,返回执行。

 

当执行到pop ebp前一句时,栈的内容,此时是把esp的地址的内容出栈到ebp中,此时看到内容为46474849,机器读是49484746(这里涉及大端小端存储,不作解释,自行百度)。

 

 然后再往下执行的时候,就会报错,因为把46474849出栈到ebp中,机器下一条就会去找这个地址去执行下一条代码,可是这个地址是没有代码的就会报错。

 

 所以,前面思路的第一个问题我们已经解决了,shellcode的内容从46开始就会覆盖返回地址,现在我们解决第二个问题,使下一条指令的地址回到栈中。这个时候我们可以利用动态链接库中的jmp esp,我们这个时候用一个工具去找。就双击Findjmpesp.exe,显示的全都是,我们选第一个。

 

 然后把这个地址写到shellcode中46474849的位置,然后代替它入栈,细心的同学就发现刚刚出栈的时候怎么是49484746,所以我们写地址到shellcode中的时候也要倒着写,就是da24e477.

 再重新编译调试一次,是不是出栈以后执行的指令就变成了,jmp esp。

 

 再下一步看看回到栈中以后,执行啥代码。虽然后面机器解释为push,pop啥的,但是它那个字节码其实是我们存到栈里面的,49以后的数字50,51.....

 

 

 

 所以第三步就是我们把我们要执行的恶意代码的字节码写进来,就会继续执行我们要的操作。如何搞出字节码呢,就是编译器的工作了,我们先把恶意代码的C语言程序写出来,这里我用的是老师给的。

展示一下我的程序,这个程序是汇编代码,它内容是调用一个弹窗函数,然后再调用一个退出程序的函数,这个程序并不是我写的,我们查找并填入两个函数的绝对内存地址:

 

 如何找到函数的绝对内存地址:

MessageBox A在user32.dll中的相对地址为3D8DE,user32.dll的基址为77e10000,程序运行的时候,函数的地址就是base+相对地址。所以我们把这两个数加起来77e4d8de。

00

 

 另一个函数,自己算哈:

 

 然后我们编译运行一下createshellcode.程序看看是什么样的。

 

 然后我们把这个函数asm的部分(弹窗并退出程序)的字节码写到overflow.c函数的shellcode的jmp esp的后面。反汇编可以查看字节码。要把asm部分所有的字节码都抄过去,我知道这个工作量很大,或许网上有脚本hhhh,但是我是手抄

 

 然后回到overflow.c,然后我们编译执行一下。

 

执行的结果是这样子的,也许细心的同学会发现我的两个弹窗的字不是一样的,因为前面的弹窗的字被我改过的,这个弹窗的字符我用的是原本的字节码。成功实现了栈溢出~~~

 

 

 本次实验学习介绍就到这里啦!

标签:字节,我们,地址,缓冲区,执行,shellcode,memcpy,溢出,函数
来源: https://www.cnblogs.com/hhhhhxian/p/16211923.html