Bufbomb内存炸弹Word格式.docx
- 文档编号:16450637
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:12
- 大小:418.56KB
Bufbomb内存炸弹Word格式.docx
《Bufbomb内存炸弹Word格式.docx》由会员分享,可在线阅读,更多相关《Bufbomb内存炸弹Word格式.docx(12页珍藏版)》请在冰豆网上搜索。
key3-1(这里减1就是地址上减4,因为int型占4字节)。
那么key3就求出来了,key3=-1,接下来就是通过地址相差的值求key4了,
还是看下汇编语言吧:
原函数执行完后返回地址为第一行也就是:
0040138E,我们想要它变成的返回地址为最后一行也就是004013BB,从process_keys34函数(*(((int*)&
key3)+*key3)+=*key4;
)可以看出:
原值加上key4的值就是修改后的值,那么key4=0x004013BB–0x0040138E=0x2D,转化为十进制就是45,即key4=45.
describingthelineofsourcecodethatisexecutedwhenthefirstcalltoprocess_keys34returns.
解析过程上面已经说过,第一次调用process_keys34函数后,将返回到上面截图中的最后一行代码msg2=extract_message2(start,stride)中执行。
(原因见上一小题解析)。
Themeaningofthethirdandfourthkeysintermsofvariablesandaddressesinthedecoderprogram.
详细解析上面解释了。
----------------------------------------------------------------------------------------------------------------------
Swap
开始->
Next—>
Next->
在调用swap1函数时,调用函数将形参b、a的值压入栈中,然后再调用函数。
在进入被调用函数时,会自动保存返回的地址,即地址0x00401413。
这个可以通过esp的改变看出,进入函数时,esp改变小,说明栈压入了新的值,而根据这个值我们可以看到,它是一个地址,而这个地址正是我们的返回地址:
0x00401413。
压入旧的ebp,esp减小。
主要是为了保存主函数的ebp,在被调用函数返回时可以找到它
将esp的值赋给ebp由于被调用函数和调用函数的分配空间是紧邻的,所以调用函数的栈顶就是被调用函数的栈底
给被调用函数分配44h大小的空间(这个空间大小是随机的),esp变为:
0012fea0
将x的值赋给temp,我们可以观察temp的地址,它是在esp和edp之间的某个地址,也就是当前帧栈的某个空间。
调用函数结束,做一些例行操作之后,将ebp的值赋给esp,即将栈底改为栈顶,为回到调用函数做准备。
之后压出一个值,将这个值赋给ebp,还记得调用时压入的那个旧的ebp吗?
就是将这个值还原给ebp。
现在要做的就是回到以前的执行地址也就是最开始保存的返回地址0x00401413,而ret就是这个作用。
sp和ebp都回到了被调用前的值
我们可以看到,调用swap1后,a、b的值并没有交换,跟据上面的分析可以知道,其实主函数中的a,b与swap1中的a,b其实是不同的,他们分别保存在不同的地址,所以主函数中a、b的值并不会被调换。
现在我们开始来看调用swap2的过程。
前期准备和后期处理都一样这里不再赘述。
但swap2中压入的是变量b和a的地址。
现在进入被调用函数swap2。
同样的分配44h的空间,同样的改变esp和ebp。
对比swap1和swap2的汇编代码会发现不同之处,swap2是通过地址的方式来改变变量的值,而这个地址和主函数中a、b的地址相同,所以这个地址里面的值已经被改变。
所以当swap2结束后,变量a、b的值已经交换。
个人总结:
函数调用都会在栈中形成独立的栈帧,值传递的函数中,形参会在被调用函数中声明,但它的生存期也就仅仅存在于调用函数的生存期,而地址传递引用的是相同的地址空间。
Bufbomb
理解题目意思:
看源程序可以发现,好像无论输入什么数据,其返回结果都是1,因为在getbuf()函数中最后一行就是return1,也就是函数按照正常来说会返回1,所以理论上无论输入是什么打印出来的都是0x1。
看起来要达到预期目标:
让程序返回0xdeadbeef。
我们首先想到的方法肯定是把return语句改成returndeadbeef,但是不允许修改源码,所以仔细分析程序的编译、链接、执行的过程即可知道,我们又有一个思路了:
由函数栈帧调用过程可以知道,过程调用时要将参数和返回地址压入栈中,然后进入被调过程执行,待从被调过程返回时,弹出返回地址,将该地址存入%eip寄存器,并转到该地址开始执行。
入栈和出栈均是对%esp指向的内存操作,其基地址为%ebp。
假设,如果我们输入的是机器码,存放于该缓冲区中,注意到程序中的缓冲区只有16字节,利用缓冲区溢出,将本应存放test调用getbuf的返回地址的内存单元修改为存放可执行的机器码的地址,而这个地址就是我们的缓冲区地址,那么在调用完getbuf后会返回到缓冲区地址处执行我们输入的机器码,在机器码中让程序输出oxdeadbeef,并正确返回继续执行。
这样会不会达到目标?
直白一点说吧:
简单来讲,就是输入的时候会超过16字节(缓冲区大小),输入内容覆盖掉ebp(test程序调用getbuf后会把自己的ebp压入栈)与返回地址(getbuf的返回地址)。
想法是将存放test调用getbuf的返回地址的内存单元的内容修改为buf缓冲区的地址。
在缓冲区执行代码:
第一、给eax寄存器赋值deadbeef,也就是更改返回值;
第二、实现ret语句,这一句的作用是保证程序正常运行,不会报错,但是在这之前我们已经改变了返回值!
在编译之前我们来看下test调用getbuf的栈帧结构:
栈底部->
高地址=================
Main函数的栈帧部分
=================
Test函数栈帧基址ebp1->
Test函数栈帧基址
------------------------------
+4retAddr(实际上就是test函数中printf语句地址)
=================
Getbuf函数栈帧基址ebp->
ebp1(作用是保存test函数基址)
------------------------------
Getbuf函数的栈帧
^
|
Buf|
|
Bufaddr
-----------------------------
Getbuf的栈顶esp->
retAddr1getbuf返回地址
==================
Getxs的栈帧
==================
地地址
栈顶->
(基本的注明上面都已经标出来了,就说下====是栈帧分隔线)
分析:
我们输入的数据存放在buf指向的一段内存中,且数据由低地址到高地址存放(图中向上箭头所示)。
如果输入的数据不覆盖ebp+4指向的内存,即buf不溢出,getbuf将永远返回1。
如果输入的数据覆盖ebp+4指向的内存呢?
也就是覆盖retAddr,但考虑到程序正常运行,不能覆盖ebp指向的内存(意思是可以覆盖,只要不改变值就行),即其中的ebp1不能被修改,如果被修改,程序将不能正确返回出现错误。
如果ebp+4指向的内存被修改为新地址,即retAddr被覆盖而存入新地址,则test调用getbuf后将返回到新地址中执行,这个新地址就可以存放一段可执行的代码,做一些我们想要发生的事了!
!
。
接下来要考虑,从程序来看,新地址只有可能是buf了(16字节长)。
如果新填入ebp+4的新地址是buf缓冲区的起始地址,而且地址中已经输入了一些我们想要执行的代码,嘿嘿,接下来就有戏了!
即test调用getbuf后将返回到buf的起始地址处执行我们想要执行的代码,并且“正常”返回,嘿嘿~。
分析完之后我们就可以确定输入了:
可执行机器码
Ebp1
新地址
好了,可以解释下了:
其中ebp1必须还是存放在ebp指向的内存中,这样才能保证程序不会出错,新地址存放在%ebp+4指向的内存中,而且新地址=buf的地址。
还有就是
输入数据的长度:
16B+4B+4B(我们期望执行的机器码不够16字节就补0)。
目标明确后就开始找值了,首先得确定机器码,到底是啥?
首先,我们应该确定可执行机器码的功能:
让程序返回0xdeadbeef
返回到%ebp+4指向的返回地址retAddr处继续执行。
我们看下源程序的返回:
我们要写改的是36下面那条语句,我们要执行的返回语句写成汇编语句就是:
Moveax,0xdeadbeef
第一点完成了,第二点,要返回到%ebp+4指向的返回地址retAddr处继续执行,看下test函数对应的汇编代码:
可以看出,实际上返回地址就是44那条printf语句,也就是0040126A(上面那条汇编代码)
所以昨晚第一步我们只要让程序返回到0040126A继续执行就ok了,就是要将该地址压入栈中,当遇到ret指令时,再将retAddr=0x0040126A从栈中弹出,并跳转到0x0040126A处继续执行,就能保证程序正确返回到test中,并继续执行。
而从getbuf中返回时,返回值在eax中,其值就是0xdeadbeef。
保证机器码执行后返回到retAddr=0x0040126A处继续执行的机器码对应的汇编代码为:
Push0x0040126A
Ret
到此为止,我们已经得到了想要执行的汇编代码,转化为机器码就行了,至于怎么变为机器码VC反汇编里直接可以看到:
-------转化为机器码-------
b8efbeadde
686A124000
C3
0000000000(补齐16字节)
接下来就是确定ebp1和buf地址了:
我们在getbuf函数入口设一个端点:
也就是当程序执行到text函数将要调用getbuf函数时看下ebp值:
0018FEAC
从下图也可以看到,调用getbuf函数时首先会保存text函数的基址:
从第一句就可以看到,pushebp(保存text栈帧基址),此时ebp寄存器的只看下就知道了:
0018FEAC,所以很显然我们得到了ebp1的值了,接下来最后一步,看buf的地址了:
Buf地址为0018FE44。
到此为止,我们已得到了全部要输入的内容:
b8efbeadde686A124000C30000000000
0x0018FEAC
0x0018FE44
考虑到后面两个地址在计算机中是按小端存储的,所以我们的最终输入信息为:
b8efbeadde686A124000C30000000000ACFE180044FE1800
程序运行结果截图如下:
Wonderful!
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- Bufbomb 内存 炸弹
![提示](https://static.bdocx.com/images/bang_tan.gif)