成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

一文讀懂|棧溢出攻擊

開發 前端
棧 是一種 LIFO(Last In Frist Out,后進先出) 形式的數據結構。棧一般是從高地址向低地址增長,并且棧支持 push(入棧) 和 pop(出棧) 兩個操作。

什么是棧

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

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

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

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

棧幀

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

棧幀 有 棧頂 和 棧底 之分,其中棧頂的地址最低,棧底的地址最高。SP(棧指針) 就是一直指向棧頂的。在 x86 的 32 位 CPU 中,我們用 %ebp 寄存器指向棧底,也就是基址指針;用 %esp 寄存器指向棧頂,也就是棧指針。下面是一個棧幀的示意圖:

一般來說,我們將 %ebp 到 %esp 之間區域當做棧幀。并不是整個??臻g只有一個棧幀,每調用一個函數,就會生成一個新的棧幀。

在函數調用過程中,我們將調用函數的函數稱為:調用者(caller),將被調用的函數稱為:被調用者(callee)。在這個過程中:

  • 調用者 需要知道在哪里獲取 被調用者 返回的值(一般存放到 %eax 寄存器)。
  • 被調用者 需要知道傳入的參數在哪里和調用完后的返回地址在哪里。
  • 我們需要保證在 被調用者 返回后,%ebp 和 %esp 寄存器的值應該和調用前一致。

函數調用

現在,我們來看看函數調用時,棧幀是如何變化的。

我們以一個函數調用的實例來解說,代碼如下:

// stack.c

int add_func(int a, int b)
{
int c, d;

c = a;
d = b;

return c + d;
}

int main(int argc, char *argv[])
{
int total;

total = add_func(1, 2);

return 0;
}

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

add_func:
pushl %ebp // 保存ebp寄存器到棧
movl %esp, %ebp // 把ebp進程設置為esp的值
subl $16, %esp // 為局部變量申請空間
movl 8(%ebp), %eax // 把參數a保存到eax寄存器中
movl %eax, -8(%ebp) // 把eax寄存器的值保存到局部變量c中(c = a)
movl 12(%ebp), %eax // 把參數b保存到eax寄存器中
movl %eax, -4(%ebp) // 把eax寄存器到值保存到局部變量d中(d = b)
movl -8(%ebp), %edx // 把d的值保存到edx寄存器中
movl -4(%ebp), %eax // 把c的值保存到eax寄存器中
addl %edx, %eax // 將eax寄存器與edx寄存器的值相加,保存到eax中(返回值)
leave
ret // 函數返回
...

可能匯編代碼比較難看懂,我們用下面的插圖來說明這個調用過程:

如上圖所示,調用過程如下:

  • 在 main() 函數調用 add_func() 函數前,先將調用 add_func() 函數的參數壓棧。
  • 在調用 add_func() 函數時,會將 返回地址 壓棧,接著進入 add_func() 函數。
  • add_func() 函數執行時,會將原來的 ebp寄存器 的值壓棧,然后把 ebp寄存器 的設置為 esp寄存器 的值。
  • 接著 add_func() 函數會為局部變量申請空間,也就是將 esp寄存器 向下移動。
  • 然后把局部變量 c 設置為參數 a 的值,局部變量 d 設置為 參數 b 的值。
  • 最后將局部變量 c 和 d 的值相加,放置到 eax寄存器 中(C語言規定以 eax寄存器 傳遞返回值),然后調用 ret 指令返回到 main() 函數。

函數返回

上面介紹了 函數調用 的過程,現在我們來介紹一下函數調用完畢后,從被調用函數返回到原來的函數過程是如何處理的。

從 add_func() 函數的匯編代碼可以看到,當被調用函數執行完畢返回到調用函數前,會執行 leave 指令,這條指令等價于:

movl %ebp, %esp
popl %ebp

這兩條匯編指令的意思是,將 esp寄存器 和 ebp寄存器 恢復到調用函數前的值。

然后,調用 ret 指令返回到原來的函數。ret 指令會從棧頂獲取 返回地址,然后跳轉到(jmp指令)此地址繼續執行。這時的 棧幀 的結構如下圖所示:

棧溢出攻擊

前面說了那么,都是為了 棧溢出攻擊 這節作鋪墊的。通過前面的學習,我們知道調用函數的 參數 、執行完函數后的 返回地址 和被調用函數的 局部變量 都是存放在棧中的。

如果在調用函數時,不小心將 返回地址 覆蓋了,那么調用完函數后,將不會跳轉到原來的函數繼續執行,而是跳轉到覆蓋后的地址執行。如下圖所示:

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

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdint.h>

#define PTR_SIZE 8 // 指針的大小
#define EBP_SIZE 8 // ebp寄存器的大小

void inject_callback()
{
printf("inject_callback called...\n");
exit(0);
}

void func_call(char *addr, int len)
{
char tmpBuf[16] = {0xff};

memcpy(tmpBuf + 16 + EBP_SIZE, addr, len);

printf("func_call called...\n");
}

int main(int argc, char** argv)
{
uint64_t injectPtr = (uint64_t)&inject_callback;

func_call(&injectPtr, PTR_SIZE);

printf("main exited...\n");

return 0;
}

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

$ gcc stack-overflow.c -fno-stack-protector -o stack-overflow
$ ./stack-overflow
func_call called...
inject_callback called...

在編譯上面程序時,一定要加上 -fno-stack-protector 參數,否則將會觸發棧溢出保護,導致執行失敗。

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

由于局部變量 tmpBuf 的類型為字符串數組,而且大小為 16 個字節。但我們復制數據是從 24(16 + 8)處開始復制,已經超出了局部變量 tmpBuf 的大小,如下圖所示:

從上圖可以看出,func_call() 函數在調用 memcpy() 函數復制數據時,由于不小心用 inject_callback() 函數的地址覆蓋了返回地址,導致 func_call() 函數執行完畢后,跳轉到 inject_callback() 函數處執行。

這就是 棧溢出攻擊 的原理,而導致 棧溢出攻擊 的原因就是:調用 memcpy()、strcpy() 等函數復制數據時,沒有對數據的長度進行驗證,從而 返回地址 被復制的數據覆蓋了。

黑客可以利用 棧溢出攻擊 來把函數的返回地址修改成入侵代碼的地址,從而實現攻擊的目的。


責任編輯:武曉燕 來源: Linux內核那些事
相關推薦

2023-12-22 19:59:15

2021-08-04 16:06:45

DataOps智領云

2018-09-28 14:06:25

前端緩存后端

2022-09-22 09:00:46

CSS單位

2025-04-03 10:56:47

2022-11-06 21:14:02

數據驅動架構數據

2023-11-27 17:35:48

ComponentWeb外層

2023-05-20 17:58:31

低代碼軟件

2022-07-05 06:30:54

云網絡網絡云原生

2022-07-26 00:00:03

語言模型人工智能

2022-12-01 17:23:45

2021-12-29 18:00:19

無損網絡網絡通信網絡

2022-10-20 08:01:23

2020-12-30 09:05:24

架構微內核系統

2017-05-04 20:29:12

HTTP服務器TCP

2018-09-29 04:53:37

IoT網關物聯網IoT

2024-01-03 08:54:17

Kubernetes策略工具

2021-05-18 09:48:58

前端開發架構

2025-01-10 08:10:00

點贊
收藏

51CTO技術棧公眾號

主站蜘蛛池模板: 日韩欧美高清 | 草b视频 | 久久精品视频网站 | 91在线视频免费观看 | 免费观看视频www | 午夜电影一区二区 | 国产精品久久久久久久久久免费 | av高清毛片| 久久成人精品 | 国产女人叫床高潮大片免费 | 日韩视频一区二区三区 | 亚洲综合视频 | 色欧美综合| 国产精品久久久久久高潮 | 亚洲情侣视频 | 天天综合91 | 国产精品久久久久久久久大全 | 91av视频在线观看 | 一区中文| 国产无套一区二区三区久久 | 毛片一区二区 | 97久久久久久 | 亚洲久在线 | 中文字幕一区二区三区不卡 | 中文av字幕 | 国产一区中文 | 精品久久国产老人久久综合 | 中文字幕乱码一区二区三区 | 日本成年免费网站 | 日本成人一区二区 | 国产国语精品 | 综合中文字幕 | 亚洲成人精选 | 午夜av电影院 | 在线国产欧美 | 中文字幕蜜臀 | 国产精品久久久久久吹潮 | 国产二区精品视频 | 美国黄色毛片 | 亚洲欧美在线一区 | 天天射视频 |