通過記憶體溢位理解棧的概念

2021-08-20 02:47:52 字數 2912 閱讀 8960

棧是一種有限儲存的資料結構–資料只能在棧的頂端進行新增或刪除,遵循lifo(後進先出)原則。棧支援兩種操作push和pop。

push:在棧頂新增乙個資料。

pop:從棧頂移除乙個資料。

接下來我們看一下一段c程式的記憶體結構在函式呼叫和返回時內容是如何變化的。

text:包含將要執行的**。

data:包含程式的全域性資訊。

stack:包含呼叫函式的入參,返回位址和函式區域性變數。這是乙個lifo的結構,向下增長(從高位址向低位址增長)。

heap:擁有動態分配的記憶體。當我們呼叫malloc動態記憶體時,就是從堆分配的。當請求分配記憶體時,堆在記憶體中是向上增長的(從低記憶體位址向高記憶體位址)。

接下來了解下基於intel的cpu暫存器

eip:指令暫存器

esp:棧暫存器

ebp:棧基址暫存器

esi:源暫存器

edi:目標暫存器

eax:累加暫存器

ebx:基址暫存器

ecx:計數暫存器

edx:資料暫存器

在這裡我們主要關心ebp,eip和esp暫存器。ebp指向了棧底的高記憶體位址,esp指向了棧頂的低記憶體位址,eip儲存下乙個執行指令的位址。eip是乙個唯讀暫存器,所以我們不能直接修改它的值。

當乙個函式被呼叫的時候,上下文資訊(主要是暫存器值)會被入棧儲存,一旦函式執行完成,相關的寄存哭喊會出棧恢復上下文。cpu需要知道從**繼續執行指令,這個返回位址在函式呼叫時入棧,函式返回時出棧(ret或retn)。

為方便理解,假設有乙個程式,main函式呼叫了func()函式,那麼當程式啟動時,main函式會被呼叫,並在棧開闢一段空間,然後再呼叫func()。而在執行func()函式前,main函式通過將返回位址入棧來標記當func()執行完畢後,將要從**繼續執行。

示例**

#include

#include

void function2()

void function1(char *str)

void main(int argc, char *argv)

上面的**包含兩個函式function1()和function2()

(1)、main()函式呼叫用function1並列印訊息」executed normally」;

(2)、function1()分配乙個長度為5的緩衝記憶體,然後將main()函式傳遞的字串拷貝到這個記憶體。

(3)、function2()列印」execution flow changed」,但並是通過main函式或function1函式呼叫。

我們的目的就是通過控制eip劫持程式的執行順序來執行function2函式。

編譯程式:gcc -g -fno-stack-protector -z execstack -o bufferoverflow overflow.c

-g告訴gcc新增額外的除錯資訊

-fno-stack-protector 關掉記憶體保護機制

-z execstack 讓棧空間可執行。

當執行程式並傳遞」aaaa」時,程式正常執行並顯示executed normally。

下一步試著讓程式崩潰,傳遞引數」aaaaaaaaaaaaaaaaaaaa」

我們用gdb開啟程式,使用list命令顯示源**,並function1呼叫,function1退出及strcpy函式設定斷點。

新增完斷點後傳入引數」aaaa」執行程式,分析斷點時esp和ebp的值,試著找出aaaa(0x41414141)儲存在**。

function呼叫時,ebp和esp:

strcpy呼叫時,ebp和esp:

回想下上面說的,」返回位址」就在ebp的下面。當返回位址被覆蓋後,gdb會出現段錯誤提示訊息0x414141 in ??()。這表示已經成功改寫了函式返回位址了,即eip的值。

接下來可以通過提供function2函式的位址進行劫持。function2()的位址可以通過下面的命令獲取

在進行下一步動作之前,我們再理一下,測試環境用的是intel cpu架構,在記憶體中是以小端進行儲存的,所以生成的payload需要轉換順序。我們用python生成目標payload。命令:run $(python -c 『print 「a」*17 + 「\x1b\x84\x04\x08″『)

當跑完所有斷點後,可以看到列印了訊息」execution flow changed」,然後程式崩潰。

為了再次檢查確認是否成功劫持程式執行,退出gdb,並執行如下命令:

這樣我們就成功利用了棧緩衝區溢位漏洞了。

**www.itgather.com

棧溢位,記憶體溢位

對於一台伺服器而言,每乙個使用者請求,都會產生乙個執行緒來處理這個請求,每乙個執行緒對應著乙個棧,棧會分配記憶體,此時如果請求過多,這時候記憶體不夠了,就會發生棧記憶體溢位。棧溢位是指不斷的呼叫方法,不斷的壓棧,最終超出了棧允許的棧深度,就會發生棧溢位,比如遞迴操作沒有終止,死迴圈。可以把記憶體比作...

棧溢位和棧記憶體溢位

棧記憶體溢位是指使用者棧的大小最多為8 10mb,分配超過棧大小的變數則會導致棧記憶體溢位。如char c 1024102411 11mb 棧溢位指的是程式向棧中某個變數中寫入的位元組數超過了這個變數本身所申請的位元組數,因而導致與其相鄰的棧中的變數的值被改變。如char c 10 memset c...

棧的概念以及棧溢位

對每個程式來說,棧能使用的記憶體是有限的,一般是 1m 8m,這在編譯時就已經決定了,程式執行期間不能再改變。如果程式使用的棧記憶體超出最大值,就會發生棧溢位 stack overflow 錯誤。乙個程式可以包含多個執行緒,每個執行緒都有自己的棧,嚴格來說,棧的最大值是針對執行緒來說的,而不是針對程...