緩衝區溢位 函式呼叫時的堆疊變化

2021-06-19 04:13:24 字數 2744 閱讀 6221

乙個正常的程式在記憶體中通常分為程式段,資料端和堆疊三部分。程式段裡放著程式的機器碼和唯讀資料,這個段通常是唯讀,對它的寫操作是非法的。資料段放的是程式中的靜態資料。動態資料則通過堆疊來存放。

在記憶體中,它們的位置如下:

/――――――――\

記憶體低端

程式段――――――――― 

資料段――――――――― 

堆疊\―――――――――

/記憶體高階

堆疊是記憶體中的乙個連續的塊。乙個叫堆疊指標的暫存器(

sp)指向堆疊的棧頂。堆疊的底部是乙個固定位址。堆疊有乙個特點就是,後進先出。也就是說,後放入的資料第乙個取出。它支援兩個操作,

push

和pop

。push

是將資料放到棧的頂端,

pop是將棧頂的資料取出。

在高階語言中,程式函式呼叫和函式中的臨時變數都用到堆疊。為什麼呢?因為在呼叫乙個函式時,我們需要對當前的操作進行保護,也為了函式執行後,程式可以正確的找到地方繼續執行,所以引數的傳遞和返回值也用到了堆疊。通常對區域性變數的引用是通過給出它們對

sp的偏移量來實現的。另外還有乙個基址指標(

fp,在

intel

晶元中是

bp),許多編譯器實際上是用它來引用本地變數和引數的。通常,引數的相對

fp的偏移是正的,區域性變數是負的。

在c語言中,靜態變數是分配在資料段中的,動態變數是分配在堆疊段的。緩衝區溢位是利用堆疊段的溢位的。

當程式中發生函式呼叫時,計算機做如下操作:首先把引數壓入堆疊;然後儲存指令暫存器

(ip)

中的內容,做為返回位址

(ret)

;第三個放入堆疊的是基址暫存器

(fp)

;然後把當前的棧指標

(sp)

拷貝到fp

,做為新的基位址;最後為本地變數留出一定空間,把

sp減去適當的數值。

比如說下面這個程式:

void function(int a, int b, int c) 

void main() 

假設我們在

linux

下,用gcc

對這段原始碼進行編譯,產生彙編**輸出:

$ gcc -s -o example1.s example1.c 

看看輸出檔案中呼叫函式的那部分:

pushl $3 

pushl $2 

pushl $1 

call function 

這就將3

個引數推入堆疊裡了,並呼叫

function()

。指令call

會將指令指標

ip壓入堆疊。在返回時,

ret要用到這個儲存的

ip。在函式中,第一要做的事是進行一些必要的處理。每個函式都必須有這些過程(為了保護呀,不然就找不到了。):

pushl �p 

movl %esp,�p 

subl $20,%esp 

這幾條指令將

ebp,基址指標放入堆疊。然後將當前

sp拷貝到

ebp。然後,為本地變數分配空間,並將它們的大小從

sp裡減掉。由於記憶體分配是以字為單位的,因此,這裡的

buffer1用了8

位元組(2

個字,乙個字

4位元組)。

buffer2

用了12

位元組(3

個字)。所以這裡將

esp減了

20。這樣,現在,堆疊看起來應該是這樣的。

低端記憶體

高階記憶體

buffer2 buffer1 sfp ret a b c 

< ------ [ ] [ ] [ ] [ ] [ ] [ ] [ ] 

棧頂棧底

那是什麼導致了溢位呢?緩衝區溢位就是在乙個緩衝區裡寫入過多的資料。要怎麼樣利用呢?看下面這個程式:

void function(char *str)  

void main()  

這個程式是乙個經典的緩衝區溢位編碼錯誤。函式將乙個字串不經過邊界檢查,拷貝到另一記憶體區域。當呼叫函式

function()

時,堆疊如下:

低記憶體端

高記憶體端

buffer sfp ret *str 

< ------ [ ] [ ] [ ] [ ] 

棧頂 棧底

很明顯,程式執行的結果是

"segmentation fault (core 

dumped)"

或類似的出錯資訊。因為從

buffer

開始的256

個位元組都將被

*str

的內容'a'

覆蓋,包括

sfp, 

ret,

甚至*str

。'a'

的十六進值為

0x41

,所以函式的返回位址變成了

0x41414141, 

這超出了程式的位址空間,所以出現段錯誤。可見,緩衝區溢位允許我們改變乙個函式的返回位址,在這個例子中,我們可以通過修改

0x41414141

來改變程式返回後的入口位址。同樣通過這種方式,就可以改變程式的執行順序了。

存在象strcpy

這樣的問題的標準函式還有

strcat(),sprintf(),vsprintf(),gets(),scanf(),

以及在迴圈內的

getc(),fgetc(),getchar()等。

**

堆疊的緩衝區溢位

我們在做專案的過程中遇到過乙個問題 開啟底層板卡,對板卡進行讀寫的時候,板卡的控制代碼莫名奇妙改變了,而我們沒有顯式改變過它。其實這是一類問題,就是區域性變數莫名其妙被修改。這是由於堆疊的緩衝區溢位造成的,主要現象是 1.某些區域性變數莫名其妙被改 2.函式返回的時候崩潰 主要原因是 1.陣列越界 ...

堆疊式緩衝區溢位

通過這段 大家可以實驗一下,使用者的輸入真的把函式原先的返回位址給改變了,從而也就改變了程式的執行流向,而具體流向 也是完全可以控制的,而利用這類漏洞就是要將程式的執行流向重定向到一段執行使用者 這裡指攻擊者 希望的功能 例如種植特洛伊木馬 的機器碼處,這樣就能完全控制有這種漏洞的計算機了,當然,實...

簡單的緩衝區溢位

這是乙個簡單的緩衝區溢位程式,是我在oday上面學到的,嘿嘿嘿,每個人寫的shellcode不一樣所以實現的目的也不一樣。大家自由發揮吧。include include include include define password 1234567 int verify password char ...