堆栈和汇编指令延伸
简单初步理解堆栈:
1、就是一块内存,操作系统在程序启动时候就分配好的,供程序执行使用。
2、很重要就对了!对底层安全尤为重要,需要认真学。
3、堆栈是程序执行所用,从下往上使用,如果堆栈用完,会“堆栈溢出”程序也会崩溃。
4、栈指针寄存器(ESP):指向当前栈的地址,可以右键选择“flow”
堆栈使用
mov指令
我们仍可以继续使用mov指令往堆栈中存入数据,具体操作如下:
1、首先在ESP指针定位到目前栈的位置。
2、使用mov指令存入数据。
3、使用sub指令更改ESP指向地址。
转成汇编指令就是:
MOV DEWORD PTR DS:[18FF88],12345678
SUB ESP,4 //DWORD 是四个字节,堆栈是从下往上使用,所以要减4;
ADD ESP,4 //将栈恢复到使用前,数据不用删除,会被再次覆盖
使用MOV指令进行操作时,必须手动更改ESP指向的地址,否则刚存入的数据会被覆盖,更改多少取决于用了多少。
这也解决了之前学c语言产生的一些疑惑。为什么c语言局部变量不赋初值就会导致结果错误,正是因为编译系统使用之前随便的一个堆栈,导致局部变量初始化的值未必是零。
实际上有更简单的指令可以进行堆栈操作,这里仍使用MOV指令是为了能对堆栈有一个更深刻的理解。并且汇编不能死板,如果只记住push能对栈进行操作的话会画地为牢。
PUSH指令
push 3
push指令完美解决了需要手动更改栈指针和定位栈位置的问题,直接使用上述指令结果就是将3入栈,并且会自动更改栈指针指向地址。
也可以栈到栈:
PUSH DWORD PTR DS:[18FFA4]
但是还是要养成看ESP指针的习惯,要知道程序往栈里push了多大的数据。
POP指令
有些时候,将数据压入栈中还需要再次取出来使用,用MOV指令表示的话就是:
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存储数据的方式;
MOV EIP,寄存器/立即数/memory
简写为
JMP 立即数/寄存器/memory
CALL指令
call指令的作用和JMP相似,他们都可以更改EIP中的数据。但是CALL指令比JMP指令多了一个功能:
还会把当前指令的下一行指令地址(非跳转),压入栈中并且同步修改ESP(栈指针寄存器)的值。也可以达到F8欺骗进行反调试的作用。
RET指令
ret(return)指令的本质就是,将当前栈(ESP指向)里存储的数据存到EIP中,并且ESP的值自动加4。至于他能够实现什么功能,先不深究,我们先把每个指令的本质搞清楚。不能流于表面。
同样也可以用mov指令表示
MOV EIP,ESP
ADD ESP,4
汇编本来就难学,如果再想着投机取巧忽略本质,那就基本不可能有提高。
学习指令的时候,不能只了解这个指令的表面含义,要知道这个指令到底做了什么事情。并且要上手实验。