实践堆栈缓冲区溢出(1)

文章可能比较繁琐吧……
有点像个人日记,其中也遇到了问题……
……
正文开始:

缓冲区溢出(Buffer Overflow),呃,对于程序员来说,总是不愉快的,而且它往往成为许多漏洞的根源。不过对于Hacker们,可能是个很高兴的发现。

十分常见的一种缓冲区溢出情况就是……通过适当的溢出,覆盖其他区域的数据,从而打乱程序的正常流程

 

堆栈溢出,是一种比较容易实现的。

此篇文章就以C++为工具,来实践几个堆栈溢出的例子。

 

先简单回想下,堆栈内部一般存放什么数据——

临时变量,函数调用的参数,一些寄存器信息。

呵呵,寄存器信息?!对的,这个是个很好的注入点。

函数调用的时候,先是参数按照一定顺序压入堆栈,然后保存指令寄存器地址(EIP)。

 

函数调用……其实是打乱了程序的顺序执行,因为它使程序从这个位置跳到另一个位置。

那么,当函数返回的时候,它需要恢复原有的流程顺序,那么,EIP就是保存了调用前的下条指令地址。

这么说……我们可以把这个堆栈中原先的EIP值改掉,那么程序不就按照我们的意图执行了?

指针运算,为这一切提供了可能。

 

当然,我们也不是随意乱改堆栈中EIP的值。如果改后的地址,不是存放指令,或者不是这个段内的数据,那么就会出现类似以下错误(SPF:段保护错误):

 

我们看如下的代码……


//测试环境:Windows XP + SP2  Intel T2050 Centrino Duo

//编译环境:Visual C++ 8.0 (CLR)

#include "stdafx.h"

void  func(){

     printf("Never called implicitly./n");

}

 

void inject(){

     //用来测试溢出的函数

}

 

int _tmain(int argc, _TCHAR* argv[])

{

     inject();

     printf("Normal END./n");

}

 

当然上面的代码,只是先给个框架,还没给出最最关键的代码。

先简单解释下,有些可能令人感到生疏的字眼……

 

头文件stdafx.h 不太熟悉?

没关系……你可以认为就是包含了stdio.h的所有内容(外加一个tchar.h头文件)。

_tmain,和main一样都是程序入口函数,不过它跟字符编码(Unicode还是MBCS)有关。

 

现在,相信聪明的你已经明白此次代码的目的了……

就是不通过显式,去调用func函数

 

我们目前要做手脚的就是inject函数

我们为了修改堆栈内EIP的值,我们需要有一个指向堆栈数据的指针。

呵呵,这里是C++,不是汇编,不能随便读取某些寄存器(ESPEBP)的值。不过我们可以建立一个临时变量,然后获得它的地址……

 

呃,在此之前,我们需要大致想下堆栈内存布局:

|―――――――――――――-|

|―― main中的临时变量  ――|

|―― 参数(如果有的话) ――|

|――      保存的EIP       ――|

|――      保存的EBP         ――|

|―― inject的临时变量       ――|

|―――――――――――――-|

 

那么,我们只要在inject中定义一个临时变量,然后取出它的地址,地址向上加就可以得到EIP所在的地址。

因为偶的电脑(大多数都是)属于IA32Intel Architecture 32-bit)系列,每个寄存器都是32位。

那么,在C++下使用int32位,其实更准确是unsigned long)是再适合不过了,这样来,指针运算就可以方便多了。

int sth=10;  //变量可以随便取名,取值

int* p=&sth;

 

嘿嘿,接下来,就是让指针p成为“溢出的凶器”。

……按照刚才所算的……

p[0]就是sthp[1]就是保存的EBPp[2]……就是它了,EIP

要把p[2]改为函数func的入口地址。

那么……

最后一句,就是p[2]=(int)func

说明:如果不进行强制转型,会出现编译错误,提示:

error C2440: =: 无法从“void (__cdecl *)(void)”转换为“int

 

运行下,试试吧……

期待,输出Never called implicitly,而不是Normal END

……

结果……

输出了Normal END

有点失望,还出现了运行错误:

Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call.  This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.

 

它明显是在进行堆栈修正的时候,找不到曾经放在栈里的正确EBP指针……它需要这个指针来恢复栈顶(ESP寄存器值)。

也就是说,我们修改的p[2],其实是保存的EBP

这么说……改为p[3]试试,即如下的代码:

void inject()

{

     int sth=10;

     int* p=&sth;

     p[3]=(int)func;

}

 

这下……顺利点了……!

输出了Never called implicitly,但是……出现了一个非法操作:

果然……

事情变的不顺利啦……

不过没关系,坚信这些问题都能解决……

 

问题,目前可以归结为两个:

1,  为什么p[3]才是保存的EIP?!

2,  即使修改了EIP值,但是为什么程序会出现非法操作?


暂时把问题先提出到这里吧,下一篇文章再随便写写自己的解决途径。

To be continued

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值