09.03 2.16 EBP尋址

2.16 EBP尋址

為什麼要介紹EBP尋址?因為EBP為棧底指針,EBP的值在尋址時是不會發生變化的。

本節必須掌握的知識點:

EBP尋址

在上節中我們留下了一個疑問,“面對ESP尋址的壞處,我們有什麼好的解決方案”,有的,可以選擇用EBP尋址。接下來我們介紹EBP尋址。

2.16.1【什麼是EBP尋址】

EBP就是棧底指針。EBP尋址就是通過EBP尋找堆棧內存的地址。說的再明白點就是利用與EBP的相對位置來確定數據所在位置。

我們借用例題的形式給大家介紹EBP尋址。

例:編寫一個函數,使它能實現任意兩個整數相加。

PUSH 1

PUSH 2

CALL 0x12345678(假設函數體開始的位置為0x12345678)

PUSH EBP (保存EBP的值)

MOV EBP,ESP (將棧頂ESP的值複製一份給EBP)

SUB ESP,10 (提升棧頂ESP的值,重新劃分一塊堆棧空間給程序使用)

MOV EAX,DWORD PTR SS:[EBP+C] //加第一個參數

ADD EAX,DWORD PTR SS:[EBP+8] //加第二個參數:

MOV ESP,EBP //恢復堆棧

POP EBP

RETN 8

我們借用DTDebug.exe軟件,操作上面的例題,並一步步解釋說明。

第一步:用DTDebug.exe軟件打開飛鴿軟件,如圖2-16-1所示。

2.16 EBP尋址

第二步:輸入彙編指令,如圖2-16-2所示。

2.16 EBP尋址

2.16 EBP尋址

ESP

0x0018FF0

EBP

0x0018FFC

初始堆棧

第三步:將參數壓入棧,並執行CALL指令,如圖2-16-3所示。

2.16 EBP尋址

2.16 EBP尋址

ESP

CALL 返回地址

2

1

原ESP

0x0018FF0

EBP

0x0018FFC

傳入參數

傳遞參數

第四步:將ESP存入EBP中,提升堆棧,如圖2-16-4所示。

2.16 EBP尋址

2.16 EBP尋址

PUSH EBP這一步是保存EBP存儲的數據;

MOV EBP,ESP 這一步是將ESP存儲的數據移動到EBP,執行後EBP存儲的數據為0x0018FFE0,為我們以後EBP尋址做鋪墊;

SUB ESP,10 這一步提升堆棧空間,為什麼提升堆棧空間,因為一個函數在執行時會讀取臨時數據用到這段空間,在我們一般應用程序中,一段函數會預留一段空間,至於預留多少,這是編譯器決定的。

ESP

SUB ESP,10

PUSH EBP

CALL 返回地址

2

1

原ESP

0x0018FF0

EBP

0x0018FFC

提升堆棧

第五步:按F8執行,實現兩個參數相加,圖2-16-5所示。

2.16 EBP尋址

MOV EAX,DWORD PTR DS:[EBP+0xC]

ADD EAX,DWORD PTR DS:[EBP+0x8]

這兩步用EBP尋址的方式,實現兩個參數相加,並把得到的結果保存在EAX中。由於MOV指令和ADD指令並沒有使堆棧發生變話,所以就不再畫堆棧的變化。

第七步:恢復現場,EBP存儲的數據是在沒提升堆棧之前的ESP的數據,我們執行完了函數,這裡要恢復堆棧,執行MOV ESP,EBP,由於在執行函數時保存EBP的數據,我們還要恢復原EBP的數據,執行POP EBP,如圖2-16-6。

ESP

CALL 返回地址

2

1

原ESP

0x0018FF0

EBP

0x0018FFC

恢復現場

2.16 EBP尋址

第八步:平衡堆棧,執行RETN 8,如圖2-16-7所示。

2.16 EBP尋址

2.16 EBP尋址

上步驟是用EBP尋址執行函數的完整的步驟。

總結:

使用EBP尋址的步驟如下:

第一步:保存EBP的值;

第二步:將EBP的值等於ESP;

第三步:提升棧頂ESP的值,重新劃分一塊堆棧空間給程序使用。

執行一個函數,在運行時會產生讀取數據,改變ESP的變化,使用EBP尋址時,EBP和參數的位置不會有變動,通過EBP+偏移來尋址,快速、簡單、穩定。

下節介紹JCC指令。

練習:

1、使用EBP尋址,編寫一個函數,使它能實現任意2個整數相加、2個整數相減,並單步執行,觀察堆棧窗口變化。

2、自己總結ESP尋址和EBP尋址,並自己通過實驗總結出ESP尋址和EBP尋址的不同。


分享到:


相關文章: