棧溢出

棧是從高地址向低地址方向增漲,堆的方向相反。

在一次函數調用中,棧中將被依次壓入:參數,返回地址,EBP。如果函數有局部變量,接下來,就在棧中開闢相應的空間以構造變量。

在C語言程序中,參數的壓棧順序是反向的。比如func(a,b,c)。在參數入棧的時候,是:先壓c,再壓b,最後a。在取參數的時候,由於棧的先入後 出,先取棧頂的a,再取b,最後取c。

C語言是不作棧溢出檢查,如下代碼可以正常編譯運行。

#include<stdio.h>
main(){
	char buf[2];
	printf("enter a string shorter than 2.\n");
	scanf("%s",buf);
	printf("buf=%s\n",buf);
}

如果函數局部變量發生棧溢出,就會依次覆蓋重寫EBP(4個字節)、返回地址(4個字節)、函數參數。函數的“返回地址”被重寫是非常危險的,因爲“返回地址”可能指向了一段惡意代碼而我們卻毫無察覺。

下面的代碼中funcA的局部變量發生棧溢出,使得funcA的返回地址成爲funcB的入口地址。不過幸好在運行的時候發現了這種行爲,報告了“segmentation fault”。

#include <stdio.h>
#include <string.h>

#define BUFLENGTH 2

void funcA(char* str)
{
    char buf[BUFLENGTH];
    strcpy(buf,str);    //危險,可能造成棧溢出
    printf("strlen(buf)=%d\tbuf=%s\n",strlen(buf),buf);
    printf("不安全的代碼被調用\n");
}

//下面的函數是惡意代碼
void funcB()
{
    printf("惡意代碼被調用\n");
}

void main()
{
	//以不安全的方式調用函數funcA
    char bufNasty[BUFLENGTH+8];
    memset(bufNasty,'A',sizeof(bufNasty));
    int *ptr=(int*)&bufNasty[BUFLENGTH+4];
    *ptr=0x65850408;
    funcA(bufNasty);
}

當然如何知道funcB的地址是0x65850408呢?可以使用反彙編工具查看:

objdump  -x  attack

也可以在使用gdb時通過在funcB處設置斷點看到funcB的地址。

gdb>b  funcB

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章