- 帖子
- 3852
- 积分
- 13044
- 威望
- 16780
- 金钱
- 36761
- 在线时间
- 1139 小时
|
汇编基础专题一日一学习14
今天我们来学习下call和ret指令,它们都是转移指令,也都修改eip寄存器。他们经常的被用来实现在自程序设计。一般我们调用子程序都是通过call来实现的。
那么一般我们的call指令格式是
call 内存地址
这个内存地址就是我们子程序的地址,我们程序执行完call 内存 指令后,相应的eip=内存地址。
举例 call 00403020
执行指令后 eip寄存器= 00403020 。我们都直到我们的cpu每次读取数据执行都是先读取我们eip寄存器,然后定位内存地址,最后在将内存中的数据传送到指令缓存区,最后执行,那么相应eip也就+读取数据的字节大小。
但是转移指令是直接 eip = 转移的地址,例如我们之前学的jmp 和今天学的call 。
call最重要的还有一点是,这里我举例说明
假设此时call 00403020指令还没有执行。 假设此时cpu通过eip寄存器定位到了call 00403020指令上,此时读取指令到指令缓冲区(注意:此时并没有开始执行,转移指令的eip值是变化两次的),新eip值= 旧eip +指令字节大小,此时我们cpu会将新eip的值压入堆栈。等待我们子程序执行完后,用ret指令将其之前eip值返回,从而使程序继续运行。。 最后才开始执行call 00403020 ,然后设置eip = 00403020。
那么重定位的技巧就是利用call的这个特性:
call $4 ;$表示是当前的地址, $4就是当前的地址+4
pop eax
此时将我们的call 所在的内存地址+指令字节大小后值(也就是读取call $4到指令缓冲区后, eip的值)压入堆栈的数据,再通过pop eax 取出到eax寄存器中,然后计算重定位差。
ret指令呢,
就是将eip赋值为 eip = 此时esp指向堆栈中的数据(也就是之前压入堆栈中的地址)
并且将esp+4 。
也就是
esp = esp +4
有必要说下 一般我们程序的子程序的开头是,因为ebp是基址寄存器,并且是段地址是位于堆栈段的,所以我们高级语言都采用这样的形式来通过ebp做指针来进行间接的寻址。
push ebp
mov ebp, esp
;初始化
最后通过leave指令来恢复esp 和ebp寄存器。
;这些我们现在还没讲,所以大家知道具体功能是什么就可以了。
小作业:
今天我们主要是深入的来了解下call 以及ret指令,那么今天的作业改为手工作业,这里我写了一个子程序的例子,大家回去用ollydbg来分析下,注意看下call 以及ret指令 执行后esp eip 等寄存器的变化。。最后把自己的分析报告写到帖子中。 (分析报告的内容主要是:call执行后esp的发生的变化,以及ret指令后发生的变化) |
|