2.10堆栈相关指令
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
2.10 堆栈相关指令
本节必须掌握的知识点:
本节介绍堆栈相关的知识,在介绍之前,我们回顾一下DTDebug.exe界面,首先打开DTDebug.exe软件,将飞鸽软件拖到DTDebug.exe软件中,如图2-10-1所示,DTDebug.exe界面包括汇编窗口、寄存器窗口、内存窗口、堆栈窗口,本节主要介绍堆栈窗口和寄存器窗口中的两个寄存器,这两个寄存器分别为ESP、EBP。
2.10.1【堆栈知识点】
我们知道每个应用程序都有独立的4GB内存空间,是不是当前运行的应用程序拥有的4GB内存空间都可以使用哪?当然不是,虽然说名义上有4GB内存空间,但是在你真正要用某一块内存时,一定要向操作系统申请,换句话说你要告诉操作系统,我们把这个过程称为内存申请。
不同的语言,在申请内存时写法是不同的,但他们的本质是相同的,都是申请内存。至于怎么申请,怎么实现,由于我们当前的进度还没有介绍到C语言,所以就不介绍了。
堆栈就是一块内存,操作系统启动时已经分配好的供程序使用的。在这里说明一下,本节介绍的堆栈与数据结构中的堆栈无关。为什么要有堆栈?堆栈是程序执行过程中必须使用的一块内存,任何一个程序需要用到的关键数据、临时数据等,都会在堆栈中一定的体现,我们可以把堆栈看成程序的心脏。
看图2-10-1堆栈窗口中的内存,都是已经向操作系统申请过的。那么我们怎么知道申请了多少堆栈哪?看图2-10-1寄存器窗口中有FS位,它对应的数据是0x00272000,在DTDebug.exe软件中找到命令窗口,输入dd 0x00272000,如图2-10-2所示:
点击键盘上的Enter键,如图2-10-3所示:
在内存窗口中,内存地址0x00272004对应的数据是0x001A0000 (Top of thread's stack),
内存地址0x00272008对应的数据是0x0019D000 (Bottom of thread's stack)。这就是操作系统为我们分配的堆栈地址,从0x0019D000到0x001A0000,堆栈窗口中的内存地址就在这个范围的。不同的系统分配的大小会有差异。由于堆栈是操作系统专门给程序用的,程序在执行过程中必须使用堆栈,所以它又可以看做是一块特殊的内存。
堆栈窗口中的内存地址是从高内存地址到低内存地址用的,也就是从内存地址0x001A0000开始使用到内存地址0x0019D000结束,如果用完了,就会报错,提示堆栈溢出。那我们怎么知道当前程序堆栈使用到哪里了?比如图2-10-3汇编窗口中,当前程序停在了0x77068E34,我们看寄存器窗口中,ESP寄存器存储的数据为0x0019FFF0,则0x0019FFF0为当前程序堆栈使用到的地方。那么从内存地址0x001A0000到内存地址0x0019FFF0都已经被使用过了如图2-10-4所示:
为什么是ESP寄存器哪?为什么不是别的寄存器?在之前我们介绍过,32位汇编中8个通用寄存器都有各自的用途,ESP为栈指针,用于指向栈的栈顶,也就是说当前使用到的存储数据的内存地址。有指向栈顶的指针,肯定有指向栈底的指针,那就是ESB寄存器,ESP 为帧指针,指向当前活动记录的底部。
我们知道了堆栈的知识,那我们该怎么使用堆栈哪?接下来介绍堆栈的使用
2.10.2【堆栈的使用】
我们当前程序执行到某个阶段时,中间会产生大量的数据,而这些数据将会暂时保存在堆栈中。如果我们现在要使用堆栈,假如有临时数据0x00000001和临时数据0x00000002,我们怎么能让这些临时数据暂时保存在堆栈中哪?如图2-10-4寄存器窗口中ESP存储的当
前数据为0x0019FFF0,说明堆栈已经使用到了内存地址为0x0019FFF0,临时数据只能存储在内存地址0x0019FFEC往上的地方。知道存储在哪了,接下来就是写汇编指令将临时数据保存在堆栈中了。
我们可以用已经学过的指令:
第一步:输入指令,如图2-10-5所示:
MOV DWORD PTR DS:[0x0019FFEC],0x00000001
MOV DWORD PTR DS:[0x0019FFE8],0x00000002
第二步:按F8执行,并观察如图2-10-6、2-10-7所示。
两次按F8执行后,临时数据0x00000001和临时数据0x00000002都已经暂时存储在了堆栈中。但ESP寄存器存储的数据并没有发生变化,这时我们要告诉堆栈当前已经使用到内存地址为0x0019FFE8的地方,若不告诉堆栈,则下一次再存储数据时可能会覆盖掉之前存储的临时数据,那么该如何告诉堆栈哪?
第一步:输入指令,如图2-10-8所示:
SUB ESP,4
SUB ESP,4
因为向堆栈中写入了2次数据且堆栈中的数据是从高地址到低地址,所以将esp的值减少8个字节,也可写成SUB ESP,8。
第二步:按F8执行并观察ESP寄存器存储的数据变化及堆栈窗口的变化,如图2-10-9、2-10-10所示:
图2-10-9堆栈窗口中的黑色定位光标显示在了内存地址0x0019FFEC中,而ESP存储的数据为0x0019FFEC,说明堆栈已经记录了数据0x00000001。我们接着按F8观察。
图2-10-10堆栈窗口中的黑色定位光标显示在了内存地址0x0019FFE8中,而ESP存储的数据为0x0019FFE8,说明堆栈已经记录了数据0x00000002。
我们以后再使用数据时,可以先提升栈顶,再存入数据。比如再向堆栈中存入临时数据0x33333333,我们先提升栈顶, 在输入数据。
第一步:先提升栈顶,如图2-10-11,ESP存储的数据为0x0019FFE8。
SUB ESP,4
第二步:按F8执行并观察数据变化如图2-10-12所示。
图2-10-12堆栈窗口中的黑色定位光标显示在了内存地址0x0019FFE4中,而ESP存储的数据为0x0019FFE4,说明堆栈已经提升了。
第三步:向堆栈中写入数据,如图2-10-13所示,当前ESP存储的数据为0x0019FFE4,