棧溢出


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

在一次函數調用中,棧中將被依次壓入:參數,返回地址,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


免責聲明!

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



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