天天看點

EIP&EBP&ESP 寄存器

接觸過緩沖區溢出的朋友對這個絕對不陌生,EIP,EBP,ESP寄存器。這裡先不解釋,先看一段代碼吧。

char a[8] = "zpf06188";
    for (int i=0;i<8;i++)
    {
        printf("%# x \n",&a[i]);
    }      

在VC6.0編譯器裡面,這樣的代碼是會報一個array bounds overflow的錯,下标越界了。這是編譯器直接對數組下标的檢查,換一種方法,用拷貝函數呢?

#include<stdio.h>
#include<string.h>
char name[] = "abcdefghijklmnopqrstuvwxyz";
int main()
{
    char output[8];
    strcpy(output, name);
    for(int i=0;i<8;i++)
        printf("%# x  ",output[i]);
    return 0;
}      

輸出結果就成了:

EIP&amp;EBP&amp;ESP 寄存器

調試結果指向:

EIP&amp;EBP&amp;ESP 寄存器

注意這裡的值70 6F 6E 6D 分别是什麼?對照碼表就可以查出來是ponm,當然存儲方式應該是mnop。

EIP&amp;EBP&amp;ESP 寄存器

堆棧的存儲是低位向高位存儲,整個操作完成,main函數執行完畢之後,堆棧中的EBP,EIP要回複回去,但是由于在strcpy的時候,拷貝的字元長度已經超過了數組限定的值,這就導緻寫入的值覆寫了EIP,EBP。最後彈出EIP的時候卻發現,它原來的東西沒了,被寫成了6d6e6f70了。是以出錯了。

EBP是"基址指針"(BASE POINTER), 它最經常被用作進階語言函數調用的"架構指針"(frame pointer). 在破解的時候,經常可以看見一個标準的函數起始代碼:

ESP 專門用作堆棧指針,被形象地稱為棧頂指針,堆棧的頂部是位址小的區域,壓入堆棧的資料越多,ESP也就越來越小。在32位平台上,ESP每次減少4位元組。

EIP:寄存器存放下一個CPU指令存放的記憶體位址,當CPU執行完目前的指令後,從EIP寄存器中讀取下一條指令的記憶體位址,然後繼續執行。

棧的基本模型:

參數N ↓高位址
參數… 函數參數入棧的順序與具體的調用方式有關
參數 3
參數 2
參數 1
EIP 傳回本次調用後,下一條指令的位址
EBP 儲存調用者的EBP,然後EBP指向此時的棧頂。
臨時變量1
臨時變量2
臨時變量3
臨時變量…
臨時變量5
void fun(void)
{
   printf("hello world");
}
void main(void)
{
  fun()
  printf("函數調用結束");
}