缓存溢出.docx

上传人:b****2 文档编号:2622578 上传时间:2023-05-04 格式:DOCX 页数:10 大小:17.88KB
下载 相关 举报
缓存溢出.docx_第1页
第1页 / 共10页
缓存溢出.docx_第2页
第2页 / 共10页
缓存溢出.docx_第3页
第3页 / 共10页
缓存溢出.docx_第4页
第4页 / 共10页
缓存溢出.docx_第5页
第5页 / 共10页
缓存溢出.docx_第6页
第6页 / 共10页
缓存溢出.docx_第7页
第7页 / 共10页
缓存溢出.docx_第8页
第8页 / 共10页
缓存溢出.docx_第9页
第9页 / 共10页
缓存溢出.docx_第10页
第10页 / 共10页
亲,该文档总共10页,全部预览完了,如果喜欢就下载吧!
下载资源
资源描述

缓存溢出.docx

《缓存溢出.docx》由会员分享,可在线阅读,更多相关《缓存溢出.docx(10页珍藏版)》请在冰点文库上搜索。

缓存溢出.docx

缓存溢出

缓存溢出

缓存溢出(Bufferoverflow),是指在存在缓存溢出安全漏洞的计算机中,攻击者可以用超出常规长度的字符来填满一个域,通常是内存区地址。

这篇文章就是讲解简单的缓存溢出问题。

文章以x86_32和linux系统平台为蓝本。

为了介绍缓存溢出,数据的存储地址、主要的汇编指令、重要的寄存器等内容都要讲解。

1.变量存储

在C语言中,变量属性有很多中,但是对于缓存溢出问题,我们主要关心的数据的存储位置,或存储空间。

因此,这里我们主要关心全局变量,局部变量和静态变量。

在C语言中,通常全局变量和静态变量被分配于数据段(datasection)中,但是局部变量分配在栈(stack)中。

另外,大家清楚,栈空间中还存储CS,IP等一些列与指令地址相关的重要数据,因此,在对局部变量进行数据拷贝的时候,如果拷贝数据块过大,就可能将IP,CS等寄存器存放的数据空间覆盖掉,写入一些非法的数据,当从设IP值时,计算机就跳转到新的非法数据代码空间了。

这里有一个简单的C文件,overflow1.c

intdata=0x66666666;

intfunc1(void)

{

staticintsdata=0x55555555;

intret=0;

returnret;

}

intmain(intargc,char*argvs[])

{

func1();

return0;

}

我们首先对它进行编译,然后查看编译后的信息。

#gcc–ooverflow1.o–coverflow1.c

#objdump–toverflow1.o

over3.o:

fileformatelf32-i386

SYMBOLTABLE:

00000000ldf*ABS*00000000over3.c

00000000ld.text00000000.text

00000000ld.data00000000.data

00000000ld.bss00000000.bss

00000004lO.data00000004sdata.1280

00000000ld.note.GNU-stack00000000.note.GNU-stack

00000000ld.comment00000000.comment

00000000gO.data00000004data

00000000gF.text00000012func1

00000012gF.text0000001emain

从结果中我们很容易找到data和sdata变量的size,section等信息。

如果想获取变量存储的地址,可以连接后在执行该命令。

但是对于局部ret,恐怕你不容易找到它的存放地址,那么ret的空间在哪里呢?

不要着急,我们继续。

#objdump–doverflow1.o

over3.o:

fileformatelf32-i386

Disassemblyofsection.text:

00000000:

0:

55push%ebp

1:

89e5mov%esp,%ebp

3:

83ec10sub$0x10,%esp

6:

c745fc00000000movl$0x0,-0x4(%ebp)

d:

8b45fcmov-0x4(%ebp),%eax

10:

c9leave

11:

c3ret

00000012

:

12:

8d4c2404lea0x4(%esp),%ecx

16:

83e4f0and$0xfffffff0,%esp

19:

ff71fcpushl-0x4(%ecx)

1c:

55push%ebp

1d:

89e5mov%esp,%ebp

1f:

51push%ecx

20:

e8fcffffffcall21

25:

b800000000mov$0x0,%eax

2a:

59pop%ecx

2b:

5dpop%ebp

2c:

8d61fclea-0x4(%ecx),%esp

2f:

c3ret

从汇编代码里面恐怕还是不明白ret在哪里存储吧?

不用担心,我们回头看看C源文件,在func1函数里有一个intret=0的声明,聪明的你现在是不是找到对应的汇编语句了,你猜对了,就是下面这句话:

6:

c745fc00000000movl$0x0,-0x4(%ebp)

也就是说,ret的空间分配在-0x4%(ebp)指向的空间中。

1:

89e5mov%esp,%ebp

你会发现ebp存放的是esp的内容,也就说-0x4%(ebp)指向的是栈空间地址,而ret就存放在哪里。

现在明白了变量的存放空间了,下面我们要继续讲解关于栈中其它的信息。

2.重要指令和寄存器

为了更好的了解缓存溢出,就要了解与其相关的指令和寄存器。

我在这部分内容中会讲解这些信息。

IP,CS,ebp,esp是我们要讲的寄存器。

CS:

IP指向将要执行的指令的存储地址。

一般的函数跳转指令和函数调用指令就是通过修改CS:

IP的值来达到跳转目的。

当指令段发生改变时,CS寄存器的数值才改变,在同一个指令段中,通常只改变IP的数值就可以了。

我们今天介绍的默认只是通过修改IP的值而达到跳转目的。

Esp寄存器存放的当前栈顶地址,而ebp作为一个备份寄存器,保存着进入新函数后esp的值。

在重要的指令中,主要有push,pop,call,ret,leave.Push和pop是一对栈操作指令,push完成入栈操作,将数据写入栈中,并更新esp的内容,而pop指令与其相反,它将数据从栈中取出,并更新esp的内容。

其中call指令是函数调用指令,它主要完成指令计数器寄存器(IP)的入栈操作(为了简单期间,这里不考虑CS入栈问题,有兴趣的同学可以去查看引用文献),类似于指令“puship”。

而ret指令与call指令相反,是一个函数返回指令,将IP的值从栈中弹出,类似”popip”。

Leave也可以看成一个符合指令,它类似于“movebp,esp;popebp”两个指令的效果。

了解了上面的基本知识,我们来分析一下汇编代码。

为了清楚期间,我们将overflow1.o进行连接,然后查看连接后的重要汇编代码片段。

#gcc–ooverflow1overflow.o

#objdump–doverflow1

…..

08048324:

8048324:

55push%ebp

8048325:

89e5mov%esp,%ebp

8048327:

83ec10sub$0x10,%esp

804832a:

c745fc00000000movl$0x0,-0x4(%ebp)

8048331:

8b45fcmov-0x4(%ebp),%eax

8048334:

c9leave

8048335:

c3ret

08048336

:

8048336:

8d4c2404lea0x4(%esp),%ecx

804833a:

83e4f0and$0xfffffff0,%esp

804833d:

ff71fcpushl-0x4(%ecx)

8048340:

55push%ebp

8048341:

89e5mov%esp,%ebp

8048343:

51push%ecx

8048344:

e8dbffffffcall8048324

8048349:

b800000000mov$0x0,%eax

804834e:

59pop%ecx

804834f:

5dpop%ebp

8048350:

8d61fclea-0x4(%ecx),%esp

….

从对func1函数开始调用开始,我们跟踪栈里面的内容。

当call指令执行后,计算机会跳到func1函数处继续执行,现在就将这些指令合并:

8048344:

e8dbffffffcall8048324

8048324:

55push%ebp

8048325:

89e5mov%esp,%ebp

8048327:

83ec10sub$0x10,%esp

804832a:

c745fc00000000movl$0x0,-0x4(%ebp)

执行后的结果是什么呢?

第一条指令是将IP压栈;

第二条指令将ebp压栈

第三条是将esp的值保存到ebp中

第四条指令更新esp的值,向前16bytes。

第五条指令给ret赋初值0,并且可以确定ret的地址是%ebp-4

因此,我们得到当前栈的值

IP0x88-0x8B;;Highaddress

Ebp->oldEBP0x84-0x87;;ebp=0x84

ret0x80-0x83

Nil0x7c-0x7f

Nil0x78-0x7b

Esp->Nil0x74-0x77;;esp=0x74

….….;;lowaddress

并且ebp会作为备份寄存器保留老的esp寄存器的值,当函数返回时,还原esp和ebp,以及IP。

缓存溢出就是在还原之前首先将栈中IP的值修改成其余的数值,从而是CPU跳转到一个错误地址或无效地址。

如果依照上面栈的地址,那么ret变量的地址应该是0x80,而老的IP数据的存储地址应该是0x88,如果在向ret进行数据拷贝时,数据过长,将会覆盖oldebp和IP的地址,从而导致程序在返回时,将错误的IP值弹出到指令计数器中,CPU将会跳转到该错误地址进行代码执行。

下面提供了两个案例程序,给大家参考。

Examples

Overflow2中是一个典型的内存溢出,作者通过向一个局部变量数组中写入过长数据,使程序无条件跳转的my_func()一个非法函数中。

#include

#include

charstrs[32]={0x1,0x2,0x3,0x4,0x5,0x6,0x7,0x8,\

0xc4,0x83,0x04,0x08,0xc4,0x83,0x04,0x08,\

0xc4,0x83,0x04,0x08,0xc4,0x83,0x04,0x08};

/*my_func的地址是0x080483c4*/

intmy_func(void)

{

printf("inMyFunc!

\n");

return87;

}

intprint(void)

{

inttmp=0x33;

intret=0x22;

charstr[4];

char*data;

strncpy(str,strs,24);

returnret;

}

intmain(intargc,char*argvs[])

{

intret=print();

printf("ret=%x\n",ret);

return0;

}

Overflow3.c是一个不通过函数调用,强制跳转到my_func()函数,并成功返回到主函数。

#include

#include

intmy_func(void)

{

printf("inMyFunc!

\n");

return87;

}

intprint(void)

{

intret=0x22;

intstr[4];

asm(\

"mov0(%%ebp),%%ebx;\

mov%%eax,0(%%ebp);\

push%%eax;\

sub$4,%%ebp;\

mov%%ebx,0(%%ebp)"\

:

\

:

"a"(my_func));

returnret;

}

intmain(intargc,char*argvs[])

{

intret=print();

printf("ret=%x\n",ret);

return0;

}

本文来自CSDN博客,转载请标明出处:

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 党团工作 > 入党转正申请

copyright@ 2008-2023 冰点文库 网站版权所有

经营许可证编号:鄂ICP备19020893号-2