前言:本教程使用的工具是DTDEBUG,讲解的是32位汇编。
1、什么是esp寻址
顾名思义,使用esp这个栈顶指针寄存器去寻找变量对应的地址,就叫做esp寻址。
如下就是一个简单的esp寻址:
像这样,我们通过esp的偏移来寻找参数的地址,就叫做esp寻址。
esp寻址的优缺点:
优点:便捷
缺点:当遇到复杂的、函数中对堆栈有操作的,esp寻址就会变得有些困难。
例如:
我们之前的测试两数相加,都是把参数从堆栈中取出,放在寄存器里,但实际开发中,寄存器里的值一般情况下都是有用的,说到底就是我们不能直接取出寄存器里的值,我们需要将值备份一份,然后再寻址,使用完成之后再将原来的值取出,如下:
这也就是esp寻址的缺点所在。
因此,便有了ebp寻址。
2、什么是ebp寻址
顾名思义,通过使用ebp寄存器来寻找变量的地址就叫做ebp寻址。
ebp寻址的优缺点:
优点:当遇到大量的堆栈操作的时候,寻址并不会变得困难
缺点:如果只有少量的堆栈操作,ebp还是相对复杂的。
这里我们就使用两个参数进行ebp寻址,知道原理即可:
此时的ebp和esp中间有十六个字节的堆栈是我们自己分配的一块内存,随便用,因为当我们把ebp中的值还给esp的时候,栈顶指针就相当于减了0x10
接下来我们将需要用到的寄存器中的值备份到ebp到esp之间的堆栈里:
为什么不能将eax,push到esp上面的堆栈呢?
加入我们备份寄存器中的值的时候,不使用ebp到esp之间的地址,我们使用push eax这个指令会怎么样呢?如下:
我们需要保证函数使用F8执行之后eax里得到的是两个数相加的值,而不是在函数里边得到相加的结果,但是函数执行完了eax又变成原来的值了,这样的函数是没有意义的
所以,我们应该把eax被分到ebp到esp之间的堆栈,函数结束后在401219的位置将eax原来的值取出来:
将esp的值还给esp,ebp的值还给ebp:
然后返回,这里尽量使用外平栈,不要用retn 8
因为我们之前将eax值被分到ebp也就是当前的esp+4的位置了,如果我们这个时候将栈顶指针再退两步,那么寻找eax原来的值就变麻烦了,所以先返回函数再取出eax备份,然后再外平栈
如下:
我们先执行完函数retn看看eax结果对不对:
没有问题,函数的职责尽到了。
然后取出eax里原来的值:
也没有问题。
最后外平栈:
至此,ebp寻址完美结束。
总结:esp寻址是用于对堆栈进行少量操作的函数,ebp寻址适用于对对战进行大量操作且需要备份的函数。
以上便是esp与ebp寻址的全部内容,如果有误望指出,以后大家一起进步。