2.11 修改EIP

为什么执行指令就会修改EIP寄存器存储的数据呢?因为EIP寄存器用来存储处理器(CPU)要读取指令的地址,处理器通过EIP寄存器读取即将要执行的指令。每次处理器执行完相应的汇编指令之后,EIP寄存器存储的数据就会增加。

本节必须掌握的知识点:

掌握EIP寄存器的知识

掌握JMP、CALL、RETN指令的工作原理并熟练运用

2.11.1【EIP寄存器的概念】

本节介绍一个非常重要的寄存器,不管我们执行哪条指令,该寄存器总是会被迫修改存储的数据,该寄存器是EIP寄存器。EIP寄存器是指令指针寄存器,是存放下次将要执行的指令在代码段的偏移量。 为什么执行指令就会修改EIP寄存器存储的数据呢?因为EIP寄存器用来存储处理器(CPU)要读取指令的地址,处理器通过EIP寄存器读取即将要执行的指令。每次处理器执行完相应的汇编指令之后,EIP寄存器存储的数据就会增加。

我们借用DTDebug.exe软件介绍EIP寄存器的工作原理,动手做以下例题。

例:假设将写入的PUSH EBP汇编指令为入口点。

第一步:将飞鸽应用程序用DTDebug.exe软件打开,如图2-11-1所示。

2.11 修改EIP

第二步:将汇编指令PUSH EBP写入汇编窗口,假设我们输入的这条汇编指令是程序的入口点,如图2-11-2所示。

2.11 修改EIP

此时,我们已经将汇编指令输入汇编窗口,且未执行PUSH EBP,EIP寄存器记录的是下一条处理器将要执行的指令,EIP当前存储的数据为0x77068E34,我们按F8执行。

第三步:按F8执行汇编指令并观察EIP寄存器存储的数据变化,如图2-11-3所示。

2.11 修改EIP

看图2-11-3中,按F8执行完了,PUSH指令我们在上一节已经介绍过了,这里不再介绍。EIP存储的数据由0x77068E34变成了0x77068E35。当我们按下F8的那一刻,处理器会读取EIP存储的数据0x77068E34,并找到EIP存储的数据相对应的指令PUSH EBP。执行指令PUSH EBP,之后修改EIP寄存器存储的数据变为0x77068E35。【这些是一条指令执行的大致流程,只限了解】。

介绍了EIP寄存器的知识,那么我们能修改EIP指令存储的数据吗?是可以修改的。那怎么修改哪?接下来介绍怎么修改,需要用哪些指令。修改EIP寄存器的数据,不能像之前修改通用寄存器那样使用MOV、ADD等指令。首先介绍JMP指令。

【JMP指令】

JMP指令是专门修改EIP的指令,在32位汇编里,CPU执行的地址为32位,所以它的格式为:JMP r32/m32/imm32

相当于MOV EIP,r32/m32/imm32 切记是不可以用MOV修改EIP寄存器的。

我们借用DTDebug.exe软件介绍JMP指令的工作原理,动手做以下例题。

例:

JMP 0x77068E42

JMP EAX

第一步:输入汇编指令JMP 0x77068E42,如图2-11-4所示。

2.11 修改EIP

第二步:按F8执行并观察EIP存储的数据是否被修改为0x77068E42,如图2-11-5所示。

2.11 修改EIP

看图2-11-5中,F8执行完,看到EIP的数据修改为0x77068E42,且汇编窗口中黑色定位光标在0x77068E42中。这使得EIP数据被正常修改。

总结:JMP 0x77068E42这条指令相当于把0x77068E42放到EIP寄存器中。

我们在把JMP EAX指令,输入到DTDebug.exe软件中,观察EIP的数据变化。

第一步:输入指令JMP EAX,如图2-11-6所示。

EAX存储的数据为0x004185B7

EIP存储的数据为0x77068E42

2.11 修改EIP

第二步:按F8执行并观察EIP存储的数据与EAX有什么关系,如图2-11-5所示。

2.11 修改EIP

看图2-11-6中,按F8执行后,EIP 存储的数据从0x77068E42变为了0x004185B7,

而EAX中存储的数据0x004185B7并没有变化。

总结:JMP EAX指令相当于 把EAX存储的数据直接放入EIP中。

本节只是介绍了JMP指令的简单用法,若是深入了解自己动手多实验多查资料,下面我们介绍一下CALL指令也可以修改EIP存储的数据。

【CALL指令】

CALL指令也是用来修改EIP存储的数据,但是比JMP指令要复杂一点。CALL指令和JMP指令工作原理类似,与JMP指令的唯一区别在于,CALL指令执行后,在堆栈中存储CALL指令下一行地址。

CALL指令格式:

CALL 立即数/寄存器/内存

我们借用DTDebug.exe软件介绍CALL指令的工作原理,动手做以下例题。

例:

CALL 0x0077068E42

第一步:输入汇编指令CALL 0x0077068E42,如图2-11-7所示。

EIP存储的数据为0x77068E34

ESP存储的数据为0x0019FFF0

2.11 修改EIP

第二步:按F7执行并观察EIP存储的数据与ESP栈顶的变化,如图2-11-8所示。

2.11 修改EIP

注意:遇见CALL指令一定要按F7执行。

看图2-11-8中,EIP存储的数据为0x77068E34变为了0x77068E42,ESP存储的数据为0x0019FFF0变成了0x0019FFEC,且将原执行地址的下一行指令地址写入内存地址为0x0019FFEC中。

总结:CALL指令不仅修改了EIP存储的数据,而且将原执行地址也就是CALL指令的下一行指令地址存入执行后的栈顶中,同时ESP减少4,相当于以下2条指令:

1、PUSH CALL指令的下一行地址

2、MOV EIP,imm32/m32/r32

本节只是介绍了CALL指令的简单用法,若是深入了解自己动手多实验多查资料。下面我们介绍RETN指令。

2.11.4【RETN指令】

在介绍RETN指令之前,我们先用实验观察一下RETN指令的工作原理,做完实验再总结。

我们借用DTDebug.exe软件介绍RETN指令的工作原理,动手做以下例题。

例:

RETN

第一步:输入RETN指令,2-11-9所示。

当前RETN指令所在内存地址为0x77068E42,EIP存储的数据为0x77068E42,ESP存储的数据为0x0019FFEC。

2.11 修改EIP

第二步:按F8执行并观察数据变化,如图2-11-10所示。

2.11 修改EIP

看图2-11-10中,按F8执行后,EIP存储的的数据为0x77068E42变成了数据为0x77068E39,ESP存储数据为0x0019FFEC变成了数据为0x0019FFF0。且内存地址0x77068E39正是上面CALL指令的下一行地址。

总结:把当前栈顶存储的值放入EIP里,同时让栈顶指针加4,相当于做了以下指令:

1、ADD ESP,4

2、JMP EIP,[ESP-4]

这两条指令也相当于POP EIP。

这里要强调一下,如果只记住了指令的格式,并没有自己动手实验,也没有自己去总结每条指令工作原理,到以后的章节学习中你会学起来很吃力。

下一节介绍汇编眼中的函数。

练习:

1、使用Call指令执行一段代码,然后返回到CALL XXX的下一行继续执行(如何返回没有要求)。

2、通过RETN实现JMP指令的功能。

3、通过JMP实现RETN指令的功能。

4、通过JMP实现Call指令的功能。

---摘自本人拙著编程达人内部教材《汇编、C语言基础教程》


分享到:


相關文章: