TA的每日心情 | 开心 2024-11-29 13:54 |
---|
|
1、调用一个CALL,堆栈在调用CALL的前后一定是要保持平衡的,所以看一个CALL有几个参数,有两种方法,
第一:只要看CALL的尾部retn 后面的值就可以推断出来,比如retn 8,那么就是有两个参数。
第二:有些CALL尾部直接retn,那么要看CALL下面有没有add esp,XX这样的代码,假设esp加了0C,那就是有三个参数。
2、入栈顺序:
从右向左,最后一个参数首先入栈,第一个参数最后入栈,接着是执行完CALL之后的下一条指令地址入栈,最后是ebp入栈,再将esp赋值给ebp,再开辟
堆栈空间用于存放局部变量。
push XXX
push XXX
call XXX (push 执行完CALL之后的下一条指令地址:00634B63)
CALL内部:
push ebp 保存ebp的值
mov ebp,esp 保存esp的值
…………
…………
…………
mov esp,ebp 恢复esp的值
pop ebp 恢复ebp的值
3、一般情况下将堆栈数据看成一个整体,如果esp或者ebp加一个很大的偏移,那么要注意看esp和ebp的值,是不是堆栈指针,有可能只是普通的偏移,
这时候就不用看成一个整体,而是直接找esp或者ebp的来源。
4、首先分清楚是局部变量还是上一层的参数
5、参数入栈顺序是从右往左,最后一个参数先入栈,第一个参数最后入栈
6、ebp+8一般是上一层的第一个参数(最后一个push),ebp-8一般是局部变量,在本层CALL内部赋值
7、esp的情况稍微复杂一些,比如esp+14,有可能是局部变量,也有可能是上一层的参数,让程序断下来,注意观察堆栈内的变化,
如果是局部变量,就在本层CALL内找来源,如果是上一层CALL的参数,就要计算在本层CALL内部往上还有多少个push(其他CALL的参数不算),从而计算出是上一层CALL的第几个参数
8、孰能生巧
|
|