淺談一下緩衝區溢位

來源:互聯網
上載者:User

標籤:style   http   color   使用   os   資料   ar   2014   

0x01 緩衝出溢出概念

  緩衝區是使用者為程式運行時在電腦中申請的一段連續記憶體,它儲存了給定類型的資料。

  緩衝區溢位就是在向緩衝區寫入資料時,由於沒有做邊界檢查,導致寫入緩衝區的資料超過預先分配的邊界,從而使溢出資料覆蓋在合法資料上而引起系統異常的一種現象。

  緩衝區溢位包括堆疊溢位和堆溢出。

0x02 進程記憶體的劃分

  要清楚緩衝區溢位的原理,就先要對電腦執行程式的記憶體結構加以分析。

  根據不同的作業系統,一個進程可能被分配到不同的記憶體地區去執行,但不管什麼樣的作業系統、什麼樣的電腦架構,進程使用的記憶體都可以按照功能分為下面4個部分:

  1. 程式碼片段:儲存著執行程式的二進位機器代碼,電腦會到這個地區取指令並執行。

  2. 資料區段:用於儲存全域變數、靜態變數等資料。

  3. 堆區:進程可以在通過malloc等函數動態地在堆區申請一定大小的記憶體,並在用完之後釋放記憶體。

  4. 堆棧區:用於動態地儲存函數之間的調用關係,以保證被調用的函數在返回時恢複到母函數中繼續執行。函數調用時的參數和局部變數都儲存在堆棧中。由系統自動分配。例如,在函數中聲明一個局部變數int b;系統自動在棧中為b開闢空間。

  需要注意的是,Intel x86機器上的堆棧被認為是反向的,即堆棧是由高端地址向下增長的。即當一個資訊被壓棧時,ESP減少,新元素被寫入目標地址,當一個資訊被彈出時,則從ESP指標所指向的地址中讀出一個元素,ESP 增加,向上邊界移動並壓縮堆棧。

  在Windows下,棧是向低地址擴充的資料結構,是一塊連續的記憶體的地區。這句話的意思是棧頂的地址和棧的最大容量是系統預先規定好的,總之是一個編譯時間就確定的常數,如果申請的空間超過棧的剩餘空間時,將提示overflow。因此,能從棧獲得的空間較小。

0x03 函數調用過程

  堆棧(簡稱棧)是一種先進後出的資料表結構。棧有兩種常用操作:壓棧和出棧。棧有兩個重要屬性:棧頂和棧底。

  記憶體的棧區實際上指的是系統棧。系統棧由系統自動維護,用於實現進階語言的函數調用。

  每一個函數在被調用時都有屬於自己的棧幀空間。當函數被調用時,系統棧會為這個函數開闢一個新的棧幀,並把它壓入棧中,所以正在啟動並執行函數總是在系統棧的棧頂。當函數返回時,系統棧會彈出該函數所對應的棧幀空間。

  win32系統提供了兩個特殊的寄存器來標識系統棧最頂端的棧幀。

  ESP:擴充堆棧指標。該寄存器存放一個指標,它指向系統棧最頂端那個函數棧幀的棧頂。
  EBP:擴充基指標。該寄存器存放一個指標,它指向系統棧最頂端那個函數棧幀的棧底。
  此外,EIP寄存器(擴充指令指標)對於堆棧的操作非常重要, EIP包含將要被執行的下一條指令的地址。

  函數棧幀:ESP和EBP之間的空間為當前棧幀,每一個函數都有屬於自己的ESP和EBP指標。ESP表示了當前棧幀的棧頂,EBP標識了當前棧的棧底。

在函數棧幀中,一般包含以下重要的資訊:

  1. 局部變數:系統會在該函數棧幀上為該函數運行時的局部變數分配相應的記憶體空間。

  2. 函數返回地址:存放了本函數執行完後應該返回到調用本函數的母函數(主調函數)中繼續執行的指令的位置。

在Win32 作業系統中,當程式裡出現函數調用時,系統會自動為這次函數調用分配一個堆棧結構。函數的調用大概包括下面幾個步驟:

  1. 參數入棧:一般是將被調函數的參數從右至左依次壓入系統棧(即調用該函數的母函數的函數棧幀)中。

  2. 返回地址入棧:把當前EIP的值(當前代碼區正在執行指令的下一條指令的地址)壓入棧中,作為返回地址。

  3. 代碼區跳轉:將EIP指向被調用函數的入口處。

  4. 棧幀調整:主要是用來保持堆棧平衡,這個過程可以由被調用函數執行,也可以由母函數執行,具體由編譯器決定。首先是將EBP壓入棧中(用於調用返回時恢複原堆棧),並把母函數的ESP的值送入寄存器EBP中,作為新的基址(新棧幀的EBP實際上儲存的是母函數的ESP),最後,為本地變數留出空間,把ESP減去適當的值(注意:記憶體配置是以字為單位的)

main() {      ……      sub(arg1,arg2,arg3); //調用sub 子函數,參數為arg1,arg2,arg3        return ; }   sub( int  arg1, int  arg2, int  arg3) {      char  a,b[10]; //sub 子函數裡面的局部變數      …… }

以上面的代碼為例。在子函數sub 中,定義了兩個局部變數,一個是字元變數a,一個是字元陣列變數b[10]。這兩個局部變數在棧上的分布情況:

    如果sub子函數中存在對b[10]進行寫入操作時,如果沒有對寫入資料的長度進行檢查,系統為b[10]申請的記憶體空間將不夠用,這時就會發生緩衝區溢位。發生緩衝區溢位時,寫入的資料會把記憶體中與b[10]數組相鄰的記憶體空間也覆蓋掉(從記憶體低地址向記憶體高地址依次覆蓋)。首先被覆蓋的是變數a,如果變數a會影響程式的處理邏輯(如根據a的內容的不同進行不同的操作),這隻是會使程式的處理邏輯出現問題,這還不是最致命的。

  當寫入b[10]的資料溢出足夠多時,將會覆蓋sub函數的EBP棧幀和函數的返回地址。上一節提到的函數的返回過程中,函數在執行完之後會將返回地址的值彈出給EIP,繼而轉到相應的位置繼續執行。如果我們寫入的資料覆蓋了返回地址的話,那麼我們就可以修改EIP的值,使得程式跳轉到我們指定的記憶體位址去執行代碼。這就產生了一個堆棧緩衝區溢位漏洞。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.