转载

从零开始学Win32平台缓冲区溢出(Part1)

缓冲区溢出是一个常见的且大家经常耳闻的软件安全漏洞,缓冲区溢出即是数据被过多的写入内存或者缓冲区,当一个缓冲区内的数据写满后,如果继续写入数据,数据就会溢出到其他缓冲区中,这将会覆盖或者说是破坏已存储的数据。

为了利用缓冲区溢出,你需要了解堆栈,CPU寄存器,内存分配等基础知识。由于缓冲区溢出本身就是一个非常庞大的话题,在这篇文章中我们会试着去理解基于堆栈的缓冲区溢出的基础知识,希望你能够喜欢。

创建C程序

首先,我们会创建一个简单的C程序并介绍一些基本知识,比如程序在内存中是如何运行的,函数调用是如何发生的,什么是返回地址等等。这就让我们从最基本的知识开始吧。

在程序中,堆栈就是用来存储临时数据的一块连续的内存。堆栈的原理即是后进先出,其有两个函数 ,PUSH是将数据放入堆栈中,POP是将数据从堆栈中取出来。在基于英特尔的系统中,从下往上他的内存地址逐渐增加,在英特尔32位架构下最大为4个字节的数据。

基本上程序的堆栈包含以下几类数据:

函数参数 调用函数的地址 返回地址 局部变量

在了解开始之前,我们需要安装会用到的工具。

虚拟机中配置完成的Windows XP Service Pack 2 Immunity Debugger Dev C ++

首先,我们会看看函数是如何被调用,返回地址等等东西。从这一阶段开始,我们已经编写好一个简单的C程序,在这段代码中我们定义了一个函数。EXE文件以及源码会在文章最后打包分享给大家。让我们看一看程序的源代码,这样我们能理解一些基本概念。

从零开始学Win32平台缓冲区溢出(Part1)

从上面的截图我们可以看到,我们在这个简单的C程序中定义了一些局部变量。接着我们使用变量调用函数,然后定义一个函数打印出“Function is called”,最后返回值为1,返回主程序。

在程序编译完成之后,我们使用Immunity Debugger工具打开程序。

点击文件菜单或者拖动这个EXE文件到Immunity Debugger工具,之后我们将在屏幕上看到以下信息。

从零开始学Win32平台缓冲区溢出(Part1)

我们在屏幕上看到四个部分,每一个部分都代表着不同类型的CPU信息。

1.信息中含有各种寄存器以及它们的值。 2.我们可以看到程序的内存转储,我们可以看到什么类型的数据被写到内存中。 3.我们也可以根据需求编辑这些值。 4.最重要的是:它显示了程序堆栈的状态

如果我们仔细观察屏幕,可以在窗口的右下角看到一个暂停按钮。这意味着用Debugger打开程序,Debugger可以对程序运行进行暂停,所以我们可以手动先启动程序。

从零开始学Win32平台缓冲区溢出(Part1)

0×01

现在,我们就开始对程序进行分析吧

第一步就是确定主函数,以及我们在程序中定义的其他函数。 如果我们的鼠标在第一个区域进行滚动,可以看到以文件名命名的主函数的ASCII以及其他函数的汇编代码,在本例中EXE文件名为First.exe。

截图中,我们有标识一些数字,这些数字是为了方便我们在接下来的内容中更好的表述而设立的。

从零开始学Win32平台缓冲区溢出(Part1)

这是主函数的汇编代码,我们可以在截图中看到“First.xxxxx”“Main Function”。 在本例中, First.xxx是我们加载到Debugger中的EXE文件名。在左边我们看到的是每一个汇编指令的内存地址,00401290这个内存地址本例中表示程序启动,004012DA则表示程序结束。图中蓝色的一行是调用我们在C程序中定义的函数。

从零开始学Win32平台缓冲区溢出(Part1)

在我们仔细观察主函数的调用时发现,主函数内存地址的后面8位中调用了一个“First.004012D3”

最后,我们可以看到函数加载到内存中,并通过printf函数打印出“Function is called”。 这个函数是将数据放入EBP寄存器中,即为入栈。在本例中,函数开始的内存地址为“004012DE”, 函数结束的内存地址为“004012FE”,这两个地址都可以在上面截图中看到。

0×02

这是最重要的一部分,我们将了解如何定义程序的断点。 断点可以帮助我们在某一个位置冻结程序,让我们可以分析寄存器状态,栈,指针等信息。 当然也允许我们对某些变化的值进行修改。所以就让我们在调用函数之前创建一个断点吧,设置断点我们可以选中某行并点击一下或者按下F2。

从零开始学Win32平台缓冲区溢出(Part1)

如上图所示,创建一个断点之后,这一行会被高亮显示。接着我们启动程序,我们可以使用F9快捷键。我们可以在屏幕上看到有些数字变化了。

从零开始学Win32平台缓冲区溢出(Part1)

在上图中,我们发现堆栈以及寄存器的值变化了,另一个有趣的事是存储断点的EIP寄存器的值。

目前,我们有两个选择

逐条指令跟踪:当我们在创建一个断点之后想执行下一条指令,我们可以使用逐条指令跟踪,键盘快捷键进入F7。  多条指令跟踪:有时候我们不需要获取详细的函数调用细节,在这种情况下我们可以使用多条指令跟踪,键盘快捷键进入F8。

0×03

好了,我接下来需要执行下一条指令,我们按下键盘快捷键F7,对堆栈进行分析。

从零开始学Win32平台缓冲区溢出(Part1)

如上图所示,在4号窗口中没有什么亮点。在1号窗口中我们可以看到断点下一条指令被执行,在2号窗口中我们看到下一条指令在EIP寄存器中分配的内存地址。

继续按下F7快捷键,我们可以看到如下这张图

从零开始学Win32平台缓冲区溢出(Part1)

我们可以看到下一个指令被执行,以及屏幕上许多数据的变化。

在1号窗口中可以看到,控制器已在前面给出的地址调用函数。仔细观察4号窗口,在堆栈的顶部,我们看到内存地址004012D4,这个内存地址是主程序的返回地址,这意味着函数执行完成后,通过这个地址计数器会跳转到主程序,也就是说程序执行完毕。

在本文我们学到的知识

分析堆栈 创建断点 分析函数调用以及寄存器状态

注:原作者未有提及第一节会将什么内容,所以就让他保持点神秘感吧。

文章中涉及源码链接: http://pan.baidu.com/s/1c0dafPQ 密码:mr5l

参考文献

http://debugger.immunityinc.com/ID_register.py

https://www.owasp.org/index.php/Buffer_Overflows

http://en.wikipedia.org/wiki/Buffer_overflow

http://en.wikipedia.org/wiki/Stack_buffer_overflow

http://www.bloodshed.net/dev/devcpp.html

译者注:此乃基础教程,求轻喷。 Ps.我就知道你们会说AV画质的

* 参考来源 infosec ,翻译/鸢尾,转载请注明来自FreeBuf黑客与极客(FreeBuf.COM)

正文到此结束
Loading...