(C語言內存十七)棧溢出攻擊的原理是什么?


例子1

我們先來看下面的一個例子:

#include <stdio.h>
int main(){
    char str[10] = {0};
    gets(str);
    printf("str: %s\n", str);
    return 0;
}

在 main() 函數內部定義一個字符數組,並通過 gets() 為它賦值。

debug

在VS2010 Debug模式下運行程序,當輸入的字符不超過10個時,可以正確輸出,但是當輸入的字符過多時,就會出現運行時錯誤。例如輸入"12345678901234567890",就會出現下面的錯誤:
image

這是為什么呢?我們不妨先來看一下 main() 函數的棧:
image

局部數組也是在棧上分配內存,當輸入"12345678901234567890" 時,會發生數組溢出,占用“4字節空白內存”、“old ebp”和“返回地址”所在的內存,並將原有的數據覆蓋掉,這樣當 main() 函數執行完成后,會取得一個錯誤的返回地址,該地址上的指令是不確定的,或者根本就沒有指令,所以程序在返回時出錯。

C語言不會對數組溢出做檢測,這是一個典型的由於數組溢出導致覆蓋了函數返回地址的例子,我們將這樣的錯誤稱為“棧溢出錯誤”。
注意:這里所說的“棧溢出”是指棧上的某個數據過大,覆蓋了其他的數據,和《棧(Stack)是什么?棧溢出又是怎么回事?》一節中提到的棧溢出不是一回事。

例子2

局部數組在棧上分配內存,並且不對數組溢出做檢測,這是導致棧溢出的根源。除了上面講到的 gets() 函數,strcpy()、scanf() 等能夠向數組寫入數據的函數都有導致棧溢出的風險。

下面是使用 strcpy() 函數導致棧溢出的例子:

#include <stdio.h>
#include <string.h>
int main(){
    char *str1 = "這里是C語言啊";
    char str2[6] = {0};
    strcpy(str2, str1);
    printf("str: %s\n", str2);
    return 0;
}

將 str1 復制到 str2,顯然超出了 str2 的接受范圍,會發生溢出,覆蓋返回地址,導致 main() 函數返回時出錯。

棧溢出一般不會產生嚴重的后果,但是如果有用戶精心構造棧溢出,讓返回地址指向惡意代碼,那就比較危險了,這就是常說的棧溢出攻擊。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM