堆栈和汇编指令延伸

简单初步理解堆栈:

1、就是一块内存,操作系统在程序启动时候就分配好的,供程序执行使用。

2、很重要就对了!对底层安全尤为重要,需要认真学。

3、堆栈是程序执行所用,从下往上使用,如果堆栈用完,会“堆栈溢出”程序也会崩溃。

4、栈指针寄存器(ESP):指向当前栈的地址,可以右键选择“flow”

在这里插入图片描述

堆栈使用

mov指令

我们仍可以继续使用mov指令往堆栈中存入数据,具体操作如下:

1、首先在ESP指针定位到目前栈的位置。

2、使用mov指令存入数据。

3、使用sub指令更改ESP指向地址。

转成汇编指令就是:

1
2
3
4
5
6
CODE
MOV DEWORD PTR DS:[18FF88],12345678

SUB ESP,4 //DWORD 是四个字节,堆栈是从下往上使用,所以要减4;

ADD ESP,4 //将栈恢复到使用前,数据不用删除,会被再次覆盖

使用MOV指令进行操作时,必须手动更改ESP指向的地址,否则刚存入的数据会被覆盖,更改多少取决于用了多少。

这也解决了之前学c语言产生的一些疑惑。为什么c语言局部变量不赋初值就会导致结果错误,正是因为编译系统使用之前随便的一个堆栈,导致局部变量初始化的值未必是零。

实际上有更简单的指令可以进行堆栈操作,这里仍使用MOV指令是为了能对堆栈有一个更深刻的理解。并且汇编不能死板,如果只记住push能对栈进行操作的话会画地为牢。

PUSH指令

1
2
CODE
push 3

push指令完美解决了需要手动更改栈指针和定位栈位置的问题,直接使用上述指令结果就是将3入栈,并且会自动更改栈指针指向地址。

也可以栈到栈:

1
2
CODE
PUSH DWORD PTR DS:[18FFA4]

但是还是要养成看ESP指针的习惯,要知道程序往栈里push了多大的数据。

POP指令

有些时候,将数据压入栈中还需要再次取出来使用,用MOV指令表示的话就是:

1
2
3
4
CODE
MOV ECX,DWORD PTR DS:[ESP] //将ESP指针指向的栈数据存入ECX

ADD ESP,4 //将栈指针恢复

同样,也可以使用更加简单的指令:POP

和push一样,不仅能拿出来当前栈指针指向的数据,并且会自动恢复栈指针。

指令延伸

JMP指令

在解释JMP指令之前需要先了解一个概念:

EIP寄存器:EIP中存储着cpu要读取的指令地址,每次CPU执行完相应的汇编指 令之后,EIP寄存器的值就会增加。

JMP指令:jmp指令的作用就是更改EIP中存储的数值,从而实现cpu执行指令的 跳跃。所以说,jmp指令的本质就是更改eip的值,指令跳跃只是 EIP值被更改所产生的效果。不能笼统的认为jmp指令就是用来跳转 指令的。

同样,这里也体现一下最基础的修改EIP存储数据的方式;

1
2
3
4
5
6
CODE
MOV EIP,寄存器/立即数/memory

简写为

JMP 立即数/寄存器/memory

CALL指令

call指令的作用和JMP相似,他们都可以更改EIP中的数据。但是CALL指令比JMP指令多了一个功能:

还会把当前指令的下一行指令地址(非跳转),压入栈中并且同步修改ESP(栈指针寄存器)的值。也可以达到F8欺骗进行反调试的作用。

PS:

call将下一个指令地址压入栈中的原理是,将 当前EIP+指令长度 压入栈中。

RET指令

ret(return)指令的本质就是,将当前栈(ESP指向)里存储的数据存到EIP中,并且ESP的值自动加4。至于他能够实现什么功能,先不深究,我们先把每个指令的本质搞清楚。不能流于表面。

同样也可以用mov指令表示

1
2
3
4
CODE
MOV EIP,ESP

ADD ESP,4

汇编本来就难学,如果再想着投机取巧忽略本质,那就基本不可能有提高。

学习指令的时候,不能只了解这个指令的表面含义,要知道这个指令到底做了什么事情。并且要上手实验。