最美情侣中文字幕电影,在线麻豆精品传媒,在线网站高清黄,久久黄色视频

歡迎光臨散文網(wǎng) 會員登陸 & 注冊

如何讀懂棧溢出攻擊,從這五點(diǎn)入手!

2022-05-07 14:17 作者:補(bǔ)給站Linux內(nèi)核  | 我要投稿

什么是棧

  • 簡單來說,棧 是一種 LIFO(Last In Frist Out,后進(jìn)先出) 形式的數(shù)據(jù)結(jié)構(gòu)。棧一般是從高地址向低地址增長,并且棧支持 push(入棧) 和 pop(出棧) 兩個(gè)操作。如下圖所示:


  • push 操作先將 棧頂(sp指針) 向下移動(dòng)一個(gè)位置,然后將數(shù)據(jù)寫入到新的棧頂;而 pop 操作會從 棧頂 讀取數(shù)據(jù),并且將 棧頂(sp指針) 向上移動(dòng)一個(gè)位置。

  • 例如,將 0x100 壓入棧,過程如下圖所示:


  • 我們再來看看 出棧 操作,如下圖所示:


棧幀

  • 棧幀,也就是 Sack Frame,其本質(zhì)就是一種棧,只是這種棧專門用于保存函數(shù)調(diào)用過程中的各種信息(參數(shù),返回地址,本地變量等)。

  • 棧幀 有 棧頂 和 棧底 之分,其中棧頂?shù)牡刂纷畹停瑮5椎牡刂纷罡?。SP(棧指針) 就是一直指向棧頂?shù)摹T?x86 的 32 位 CPU 中,我們用 %ebp 寄存器指向棧底,也就是基址指針;用 %esp 寄存器指向棧頂,也就是棧指針。下面是一個(gè)棧幀的示意圖:



  • 一般來說,我們將 %ebp 到 %esp 之間區(qū)域當(dāng)做棧幀。并不是整個(gè)棧空間只有一個(gè)棧幀,每調(diào)用一個(gè)函數(shù),就會生成一個(gè)新的棧幀。

  • 在函數(shù)調(diào)用過程中,我們將調(diào)用函數(shù)的函數(shù)稱為:調(diào)用者(caller),將被調(diào)用的函數(shù)稱為:被調(diào)用者(callee)。在這個(gè)過程中:

  1. 調(diào)用者 需要知道在哪里獲取 被調(diào)用者 返回的值(一般存放到 %eax 寄存器)。

  2. 被調(diào)用者 需要知道傳入的參數(shù)在哪里和調(diào)用完后的返回地址在哪里。

  3. 我們需要保證在 被調(diào)用者 返回后,%ebp 和 %esp 寄存器的值應(yīng)該和調(diào)用前一致。

【文章福利】小編推薦自己的Linux內(nèi)核技術(shù)交流群:【891587639】整理了一些個(gè)人覺得比較好的學(xué)習(xí)書籍、視頻資料共享在群文件里面,有需要的可以自行添加哦!!!前100名進(jìn)群領(lǐng)取,額外贈送一份價(jià)值699的內(nèi)核資料包(含視頻教程、電子書、實(shí)戰(zhàn)項(xiàng)目及代碼)? ?



  • 現(xiàn)在,我們來看看函數(shù)調(diào)用時(shí),棧幀是如何變化的。

  • 我們以一個(gè)函數(shù)調(diào)用的實(shí)例來解說,代碼如下:

我們使用命令 gcc -S -m32 stack.c 來編譯上面的代碼,獲取的匯編代碼如下所示(去掉一些無關(guān)緊要的信息):

  • 可能匯編代碼比較難看懂,我們用下面的插圖來說明這個(gè)調(diào)用過程:



  • 如上圖所示,調(diào)用過程如下:

  1. 在 main() 函數(shù)調(diào)用 add_func() 函數(shù)前,先將調(diào)用 add_func() 函數(shù)的參數(shù)壓棧。

  2. 在調(diào)用 add_func() 函數(shù)時(shí),會將 返回地址 壓棧,接著進(jìn)入 add_func() 函數(shù)。

  3. add_func() 函數(shù)執(zhí)行時(shí),會將原來的 ebp寄存器 的值壓棧,然后把 ebp寄存器 的設(shè)置為 esp寄存器 的值。

  4. 接著 add_func() 函數(shù)會為局部變量申請空間,也就是將 esp寄存器 向下移動(dòng)。

  5. 然后把局部變量 c 設(shè)置為參數(shù) a 的值,局部變量 d 設(shè)置為 參數(shù) b 的值。

  6. 最后將局部變量 c 和 d 的值相加,放置到 eax寄存器 中(C語言規(guī)定以 eax寄存器 傳遞返回值),然后調(diào)用 ret 指令返回到 main() 函數(shù)。

函數(shù)返回

  • 上面介紹了 函數(shù)調(diào)用 的過程,現(xiàn)在我們來介紹一下函數(shù)調(diào)用完畢后,從被調(diào)用函數(shù)返回到原來的函數(shù)過程是如何處理的。

  • 從 add_func() 函數(shù)的匯編代碼可以看到,當(dāng)被調(diào)用函數(shù)執(zhí)行完畢返回到調(diào)用函數(shù)前,會執(zhí)行 leave 指令,這條指令等價(jià)于:

  • 這兩條匯編指令的意思是,將 esp寄存器 和 ebp寄存器 恢復(fù)到調(diào)用函數(shù)前的值。

  • 然后,調(diào)用 ret 指令返回到原來的函數(shù)。ret 指令會從棧頂獲取 返回地址,然后跳轉(zhuǎn)到(jmp指令)此地址繼續(xù)執(zhí)行。這時(shí)的 棧幀 的結(jié)構(gòu)如下圖所示:



棧溢出攻擊

  • 前面說了那么,都是為了 棧溢出攻擊 這節(jié)作鋪墊的。通過前面的學(xué)習(xí),我們知道調(diào)用函數(shù)的 參數(shù) 、執(zhí)行完函數(shù)后的 返回地址 和被調(diào)用函數(shù)的 局部變量 都是存放在棧中的。

  • 如果在調(diào)用函數(shù)時(shí),不小心將 返回地址 覆蓋了,那么調(diào)用完函數(shù)后,將不會跳轉(zhuǎn)到原來的函數(shù)繼續(xù)執(zhí)行,而是跳轉(zhuǎn)到覆蓋后的地址執(zhí)行。如下圖所示:


  • 那么,怎樣才能把 返回地址 覆蓋呢?我們可以通過下面的例子來說明:

我們使用以下命令編譯上面代碼,并且執(zhí)行:

在編譯上面程序時(shí),一定要加上 -fno-stack-protector 參數(shù),否則將會觸發(fā)棧溢出保護(hù),導(dǎo)致執(zhí)行失敗。

  • 在上面的代碼中,我們并沒有直接調(diào)用 inject_callback() 函數(shù),而是通過把 inject_callback() 函數(shù)的地址復(fù)制到 func_call() 函數(shù)的局部變量 tmpBuf 中。

  • 由于局部變量 tmpBuf 的類型為字符串?dāng)?shù)組,而且大小為 16 個(gè)字節(jié)。但我們復(fù)制數(shù)據(jù)是從 24(16 + 8)處開始復(fù)制,已經(jīng)超出了局部變量 tmpBuf 的大小,如下圖所示:



  • 從上圖可以看出,func_call() 函數(shù)在調(diào)用 memcpy() 函數(shù)復(fù)制數(shù)據(jù)時(shí),由于不小心用 inject_callback() 函數(shù)的地址覆蓋了返回地址,導(dǎo)致 func_call() 函數(shù)執(zhí)行完畢后,跳轉(zhuǎn)到 inject_callback() 函數(shù)處執(zhí)行。

  • 這就是 棧溢出攻擊 的原理,而導(dǎo)致 棧溢出攻擊 的原因就是:調(diào)用 memcpy()、strcpy() 等函數(shù)復(fù)制數(shù)據(jù)時(shí),沒有對數(shù)據(jù)的長度進(jìn)行驗(yàn)證,從而 返回地址 被復(fù)制的數(shù)據(jù)覆蓋了。

  • 黑客可以利用 棧溢出攻擊 來把函數(shù)的返回地址修改成入侵代碼的地址,從而實(shí)現(xiàn)攻擊的目的。



如何讀懂棧溢出攻擊,從這五點(diǎn)入手!的評論 (共 條)

分享到微博請遵守國家法律
铜陵市| 乳源| 两当县| 西宁市| 图片| 图木舒克市| 阿瓦提县| 靖安县| 宜宾县| 宣武区| 南阳市| 秦安县| 炎陵县| 循化| 郎溪县| 谢通门县| 峨眉山市| 固安县| 彩票| 北流市| 太仓市| 化州市| 阳西县| 商丘市| 绩溪县| 界首市| 清丰县| 松溪县| 盐边县| 兰坪| 淮北市| 扬州市| 江门市| 南溪县| 新乐市| 吉木萨尔县| 东丰县| 武城县| 航空| 容城县| 镇赉县|