堆栈

esp和msr可以删掉吗 esp和msr有什么用_栈

什么是堆栈?

程序执行的过程中由操作系统分配可使用的一块内存,要是用超了就是堆栈溢出。
ESP寄存器被称为栈指针寄存器,存储了当前的堆栈用到了哪里。

堆栈的使用

堆栈使用时是大地址往小地址用,每次使用后要修改栈顶指针ESP寄存器,防止数据被顶掉

PUSH指令

向堆栈压入数据,修改栈顶指针ESP寄存器(减)
PUSH imm8/imm16/imm32
PUSH r16/r32
PUSH m16/m32

POP指令

将栈顶数据存到寄存器或内存,修改栈顶指针ESP寄存器(加)
POP r16/r32
POP m16/m32

修改EIP的指令

EIP中记录的是CPU下一次要执行的地址,不可用普通的MOV指令修改

JMP指令

修改EIP的值
JMP imm32/r32/m32

CALL指令

修改EIP的值,并把当前指令的下一行地址存入堆栈中(修改了堆栈,所以ESP的值也会改动)。
CALL imm32/r32/m32

RET指令

本质上就是
ADD ESP,4
MOV EIP,[ESP-4]
RET后面可以跟一个imm,表示ESP加上这个imm,即在函数返回后再修改一次栈顶指针寄存器,用途为释放函数数据占用的堆栈。

反调试

单步步入(F7)单步步过(F8)
CALL指令时F7是一步一步执行,F8是全执行完

调试器实现原理

断点:0xCC
单步步入:设置EFLAGS的TF位
单步步过:在下一行设置断点,即无论你CALL有多少指令,最后都要停在CALL的下一行
小小的一个反调试的方法(仅对单步步过有用):
在CALL跳转的位置写:
MOV DWORD PTR DS:[ESP],004183D7(内存地址随意)
RET
这样的话,相当于修改了栈顶的值,使得RET返回时不会回到CALL的下一行,而是跳转到你输入的那个内存地址。,

反调试思路

写大量的CALL,大量的无意义代码,使得单步步入非常消耗耐心。

汇编眼中的函数

什么是函数?

函数就是一系列指令的集合,为了完成某个会重复使用的特定功能
调用函数:JMP和CALL指令,一般用CALL,因为用RET就能很方便的回来
参数:保存到堆栈,一般调用函数完的返回值保存到EAX

堆栈平衡

1.如果要返回父程序,则当我们在堆栈中进行堆栈的操作时,一定要保证在RET这条指令之前,ESP指向的是我们压入栈的地址,即RET能正确返回。
2.如果通过堆栈传递参数了,那么在函数执行完毕后,要平衡常数导致的堆栈变化。例如:先向堆栈压入了函数所用的数据,但是函数执行完成后却没有释放数据占用的堆栈,浪费空间。