基於VSC++6.0的緩衝區溢位驗證實驗
0、概述
在緩衝區溢位在一些較為古早的系統或軟體中易於實現,因為這些系統或者軟 件的堆疊位數較低,一些較短的資料就可以衝出堆疊,實現緩衝區溢位。所以 在較為古早的軟體中驗證緩衝區溢位不失為一種可行方法。本次實驗採用的是VirtualC++ 6.0編譯器進行。
1、實驗目的
- 通過重現緩衝區溢位攻擊來理解此漏洞
2、實驗內容及步驟
-
實驗原理
-
堆疊的概念
堆疊是一個在計算機中常用的抽象資料型別,堆疊的一個標誌性特徵就是最後一個入棧的元素總是第一個被取出(LIFO)。堆疊定義了一些操作,其中push和pop操作是最重要的兩個操作,push在棧頂加入一個元素,pop則從棧頂移除一個元素,並將堆疊的大小減一。
-
堆疊的緩衝區溢位原理
函式呼叫時,返回值存放在堆疊中,區域性變數也存放在堆疊中,如果區域性變數中有一個字元陣列,且該程式使用了又緩衝區溢位風險的函式來操縱該字元陣列,就可以通過向該函式傳遞超長的字串來使得該字元陣列產生溢位,從而達到覆蓋返回地址、執行惡意程式碼的目的。
-
-
實驗過程
-
設計程式
首先需要設計一個擁有溢位風險的函式,該程式有如下功能:
構建func()函式,有記憶體拷貝函式memcpy來實現字元的複製功,待複製的字串長 度任意,這些字元將被複制到一個長為9的字串中,如果複製的內容過長,就有可能 發生溢位,程式中的加法用來做對比。在主函式中呼叫了func函式,使用if語句決定 將要複製的字元的長度,對比二者,分析緩衝區溢位。
程式stack.c:
#include <stdio.h> #include <string.h> #include <windows.h> int func(char *szIn , int nTest) { int a = 1 , b = 2 , c = 0; char szBuf[8]; memcpy(szBuf , szIn , strlen(szIn)); c = a + b; return c; } int main() { int i = 0 , j = 0; printf("1 for shorter one while 2 for longer one"); scanf("%d" , &i); if(i == 1){ char sz_In2[] = "abcdabcdabcdabcd"; j = func(sz_In2 , 512); }else if(i == 2){ char sz_In3[] = "abcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcdabcd"; i = func(sz_In3 ,512); }else{ char sz_In1[] = "abcd"; j = func(sz_In1 ,512); } return 0; }
-
儲存為.c檔案後,點選工具欄的“元件”,再點選其中的“編譯”,進行程式的編譯,中 間遇見異常報告,詢問下一步操作時選擇“是”選項。
-
按F9在程式中設定斷點,F5開始除錯
-
開始除錯後程序執行至斷點1,注意右上角的暫存器,其中各個暫存器的功能如下:
EBP:基址指標 ESP:堆疊指標 EAX:累加器 EBX:基址暫存器 ECX:計數暫存器 EDX:資料暫存器
-
按F5進行除錯,輸入1,選擇較短的字串進行操作,直至程式結束,沒有出現任何異常
-
重新開啟除錯,在輸入時轉為2,對較長的字串進行復制
一直按F5執行程式,會發現出現了報錯,不管它,繼續F5,程式最終異常終止,報錯依舊
此時檢視右上角的暫存器的資料,注意基址暫存器EBP的內容,正常情況下該指標永遠指 向系統棧最上面一個棧幀的底部,但是這時卻變成了64636261,這是ASCII碼中abcd,即 複製的字元內容,說明發生了緩衝區溢位的現象,將func函式的返回值地址覆蓋了。
ASCII碼錶部分:
-
3、實驗環境
計算機:Windows10、VisualC++6.0
4、驗證原理
1、緩衝區溢位:緩衝區溢位是常見並且危害很大的系統攻擊手段,通過向程 序的緩衝區寫入超出其長度的內容,造成緩衝區的溢位,從而破壞程式的堆 棧,使程式轉而執行其他指令,從而達到攻擊的目的。
2、C語言中,一些不作邊界檢查的字串複製函式,如strcpy,容易造成緩 衝區溢位。