爲什麼執行指令就會修改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所示。

第二步:將彙編指令PUSH EBP寫入彙編窗口,假設我們輸入的這條彙編指令是程序的入口點,如圖2-11-2所示。

此時,我們已經將彙編指令輸入彙編窗口,且未執行PUSH EBP,EIP寄存器記錄的是下一條處理器將要執行的指令,EIP當前存儲的數據爲0x77068E34,我們按F8執行。

第三步:按F8執行彙編指令並觀察EIP寄存器存儲的數據變化,如圖2-11-3所示。

看圖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所示。

第二步:按F8執行並觀察EIP存儲的數據是否被修改爲0x77068E42,如圖2-11-5所示。

看圖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

第二步:按F8執行並觀察EIP存儲的數據與EAX有什麼關係,如圖2-11-5所示。

看圖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

第二步:按F7執行並觀察EIP存儲的數據與ESP棧頂的變化,如圖2-11-8所示。

注意:遇見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。

第二步:按F8執行並觀察數據變化,如圖2-11-10所示。

看圖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語言基礎教程》

相關文章