逆向工程核心原理笔记(四)——栈

逆向工程核心原理笔记(四)——堆栈

堆栈(Stack),是一种常用的数据结构类型名,我们可以将堆栈抽象为一种一个管子,我们可以向管子中投入豆子,那么很显然,最先投进去的豆子,一定是最后才能取出。

堆栈有两种最基本的操作:压入(Push)和弹出(Pop):

​ 压入:将数据放入堆栈顶端

​ 弹出:将堆栈顶端的数据弹出

堆栈的特点和队列的特点有所不同,堆栈中元素满足先入后出,后入先出的特点,并且除了头尾的节点之外,堆栈中每个元素都有一个前驱和一个后继。

接下来我们通过在管子中存取豆子来理解什么是堆栈:

首先我们需要使用一个指针来指向堆栈中最靠前元素的位置,这里我们使用豆子的编号来表示,如下图,我们有一个管子和许多豆子:
逆向工程核心原理笔记(四)——栈_第1张图片
我们尝试将一个豆子放入管子中来模拟压栈的过程:
逆向工程核心原理笔记(四)——栈_第2张图片
上图我们将一个豆子压入管子中,并将这个豆子编号为1,让一个指针指向这个豆子的位置为1,接下来我们再将一个豆子放入管子中:
逆向工程核心原理笔记(四)——栈_第3张图片
此时,指向豆子位置的指针上移并指向了第二个豆子。

接下来我们尝试模仿弹出的操作,我们将管子中一个豆子取出,因为只能取最上面的豆子,所以最后放入的二号豆子被取出,二号豆子被取出后,指向顶端位置的指针下移重新指向一号位置:
逆向工程核心原理笔记(四)——栈_第4张图片
如上模仿了堆栈的工作原理。

堆栈内存再进程中的作用如下:

​ 1.暂时保存函数内的局部变量

​ 2.调用函数时传递参数

​ 3.保存函数返回后的地址

我们尝试通过 OD 的运行来理解栈是如何运行的

将书中给定的 Stack.exe 进行反编译,反编译得到的结果如下:
逆向工程核心原理笔记(四)——栈_第5张图片
之前讲解 IA-32 寄存器的时候讲解了 ESP 是栈指针寄存器,在这里栈顶指针为 0019FF74,接下来我们逐步运行这个程序,使用 F7 逐步运行程序,将程序运行到 401000 处,程序将数值 100 压入栈中:
逆向工程核心原理笔记(四)——栈_第6张图片
栈顶指针由 0019FF74 指向了 0019FF70,即将数字压入栈中后,栈顶指针向上移动,减少了四个字节,正好是一个 int 的大小,接下来我们继续执行程序,执行 00401005 这条语句:
逆向工程核心原理笔记(四)——栈_第7张图片
此时,程序将顶部元素执行 POP 命令,进行弹出,指针重新向下移动,因此增大了4个字节,变为和初始状态相同的 0019FF74 。

因此,将数据压入栈中后,栈顶指针减小,指针向低地址移动;从栈中弹出数据后,栈顶指针增大,指针向高地址移动。

因此,将数据压入栈中后,栈顶指针减小,指针向低地址移动;从栈中弹出数据后,栈顶指针增大,指针向高地址移动。

在程序调试的过程中,堆栈和栈顶指针的变化十分重要,在调试的过程中需要密切注意。

你可能感兴趣的:(CTF,re逆向分析的点点滴滴)