国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
堆棧溢出

http://blog.csdn.net/searchsun/article/details/2885573

2008

本講的預備知識: 
首先你應該了解intel匯編語言,熟悉寄存器的組成和功能。你必須有堆棧和存儲分配方面
的基礎知識,有關這方面的計算機書籍很多,我將只是簡單闡述原理,著重在應用。其次,
你應該了解linux,本講中我們的例子將在linux上開發(fā)。 

1:首先復習一下基礎知識。 

從物理上講,堆棧是就是一段連續(xù)分配的內存空間。在一個程序中,會聲明各種變量。靜態(tài)
全局變量是位于數(shù)據(jù)段并且在程序開始運行的時候被加載。而程序的動態(tài)的局部變量則分配
在堆棧里面。 

從操作上來講,堆棧是一個先入后出的隊列。他的生長方向與內存的生長方向正好相反。我
們規(guī)定內存的生長方向為向上,則棧的生長方向為向下。壓棧的操作push=ESP-4,出棧的
操作是pop=ESP+4.換句話說,堆棧中老的值,其內存地址,反而比新的值要大。 
請牢牢記住這一點,因為這是堆棧溢出的基本理論依據(jù)。 

在一次函數(shù)調用中,堆棧中將被依次壓入:參數(shù),返回地址,EBP。如果函數(shù)有局部變量,
接下來,就在堆棧中開辟相應的空間以構造變量。函數(shù)執(zhí)行結束,這些局部變量的內容將被
丟失。但是不被清除。在函數(shù)返回的時候,彈出EBP,恢復堆棧到函數(shù)調用的地址,彈出返回
地址到EIP以繼續(xù)執(zhí)行程序。 

在C語言程序中,參數(shù)的壓棧順序是反向的。比如func(a,b,c)。在參數(shù)入棧的時候,是:
先壓c,再壓b,最后a.在取參數(shù)的時候,由于棧的先入后出,先取棧頂?shù)腶,再取b,最后取c。 
(PS:如果你看不懂上面這段概述,請你去看以看關于堆棧的書籍,一般的匯編語言書籍都
會詳細的討論堆棧,必須弄懂它,你才能進行下面的學習) 

2:好了,繼續(xù),讓我們來看一看什么是堆棧溢出。 

2.1:運行時的堆棧分配 

堆棧溢出就是不顧堆棧中分配的局部數(shù)據(jù)塊大小,向該數(shù)據(jù)塊寫入了過多的數(shù)據(jù),導致數(shù)據(jù)
越界。結果覆蓋了老的堆棧數(shù)據(jù)。 

比如有下面一段程序: 
程序一: 
#include <stdio.h> 
int main ( ) 

char name[8]; 
printf("Please type your name: "); 
gets(name); 
printf("Hello, %s!", name); 
return 0; 

編譯并且執(zhí)行,我們輸入ipxodi,就會輸出Hello,ipxodi!。程序運行中,堆棧是怎么操作的呢? 

在main函數(shù)開始運行的時候,堆棧里面將被依次放入返回地址,EBP。 

我們用gcc -S 來獲得匯編語言輸出,可以看到main函數(shù)的開頭部分對應如下語句: 

pushl %ebp 
movl %esp,%ebp 
subl $8,%esp 

首先他把EBP保存下來,,然后EBP等于現(xiàn)在的ESP,這樣EBP就可以用來訪問本函數(shù)的
局部變量。之后ESP減8,就是堆棧向上增長8個字節(jié),用來存放name[]數(shù)組。現(xiàn)在堆棧
的布局如下: 

內存底部 內存頂部 
name EBP ret 
<------ [ ][ ][ ] 
^&name 
棧頂部 堆棧底部 

執(zhí)行完gets(name)之后,堆棧如下: 

內存底部 內存頂部 
name EBP ret 
<------ [ipxodi/0 ][ ][ ] 
^&name 
棧頂部 堆棧底部 

最后,main返回,彈出ret里的地址,賦值給EIP,CPU繼續(xù)執(zhí)行EIP所指向的指令。 


2.2:堆棧溢出 

好,看起來一切順利。我們再執(zhí)行一次,輸入ipxodiAAAAAAAAAAAAAAA,執(zhí)行完
gets(name)之后,堆棧如下: 

內存底部 內存頂部 
name EBP ret 
<------ [ipxodiAA][AAAA][AAAA]....... 
^&name 
棧頂部 堆棧底部 

由于我們輸入的name字符串太長,name數(shù)組容納不下,只好向內存頂部繼續(xù)寫
‘A’。由于堆棧的生長方向與內存的生長方向相反,這些‘A’覆蓋了堆棧的
老的元素。 如圖 
我們可以發(fā)現(xiàn),EBP,ret都已經被‘A’覆蓋了。在main返回的時候,就會把
‘AAAA’的ASCII碼:0x41414141作為返回地址,CPU會試圖執(zhí)行0x41414141處
的指令,結果出現(xiàn)錯誤。這就是一次堆棧溢出。 

3:如何利用堆棧溢出 

我們已經制造了一次堆棧溢出。其原理可以概括為:由于字符串處理函數(shù)
(gets,strcpy等等)沒有對數(shù)組越界加以監(jiān)視和限制,我們利用字符數(shù)組寫
越界,覆蓋堆棧中的老元素的值,就可以修改返回地址。 

在上面的例子中,這導致CPU去訪問一個不存在的指令,結果出錯。 

事實上,當堆棧溢出的時候,我們已經完全的控制了這個程序下一步的動作。
如果我們用一個實際存在指令地址來覆蓋這個返回地址,CPU就會轉而執(zhí)行我
們的指令。 

 


 

本站僅提供存儲服務,所有內容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內容,請點擊舉報
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
函數(shù)在實現(xiàn)過程內存中的壓棧和出棧
【新提醒】[教程]逆向反匯編第二課
匯編語言跟C語言之間不得不說的秘密!
[原創(chuàng)]逆向學習筆記之匯編
換種方法學操作系統(tǒng)輕松入門Linux內核(與圖靈機不同馮諾依曼機是一個實際的體系結構)CPU就是從EIP指向的那個地址取過來一條指令執(zhí)行
通過一段匯編,加深對寄存器ESP和EBP的理解
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服