02.棧溢出實驗-利用淹沒返回值控制程序執(zhí)行流程

棧溢出實驗

利用淹沒返回值控制程序執(zhí)行流程


一.  實驗環(huán)境:

操作系統(tǒng):Windows XP SP3

開發(fā)環(huán)境:VC++ 6.0

調(diào)試器:Ollydbg


二.  實驗代碼:

#include <stdio.h>

#include<string.h>

#define PASSWORD "1234567"

int verify_password (char *password)

{

    int authenticated;

    char buffer[8];

    authenticated=strcmp(password,PASSWORD);

    strcpy(buffer,password);

    return authenticated;

}

main()

{

    int valid_flag=0;

    char password[1024];

    while(1)

    {

        printf("please input password:       ");

        scanf("%s",password);

        valid_flag = verify_password(password);

        if(valid_flag)

        {

            printf("incorrect password!nn");

        }

        else

        {

            printf("Congratulation! You have passed the verification!n");

            break;

        }

    }

}


三.  溢出原理


程序未對輸入的密碼進行長度檢測,接收密碼的緩沖區(qū)只有8,而輸入的密碼最長可以輸入1024。判斷密碼是否正確的變量authenticated存儲在棧中,當輸入的密碼長度大于8時,輸入的字符串將沖破緩沖區(qū),淹沒authenticated所處的位置。當密碼錯誤時authenticated的值是1,正確的時候authenticated的值是0.這就意味著我們可以構造一個合適的輸入字符串來改變判斷結果。


本次的程序與上一節(jié)的程序的區(qū)別為由控制臺輸入改為讀取文件。這是因為很多字符無法由控制臺直接輸入。


四.  實戰(zhàn)調(diào)試


本次的程序與上一節(jié)只有讀取文件和控制臺輸入的區(qū)別,故此不再詳細分析。著重分析如何通過覆蓋返回值來控制程序執(zhí)行流程。


1.   首先我們隨便在password.txt中隨便輸入一個字符串保存,然后調(diào)試程序,進入main函數(shù)開始分析。


2.         因為這次的目的是淹沒返回值控制程序流程,所以在進入密碼比對函數(shù)之前,先記錄下函數(shù)位置。


3.         單步進入密碼比對函數(shù),在剛剛進入函數(shù)的時候可以看到ESP的位置就是函數(shù)的返回地址。


4.         在經(jīng)過strcpy函數(shù)之后,可以看到password.txt內(nèi)的字符串成功的覆蓋了函數(shù)比對結果變量,那么我們可以看到在附近還存儲著函數(shù)返回地址,那么我們是否可以通過加長password.txt內(nèi)的文本內(nèi)容,覆蓋掉返回地址。我們可以看到距離返回地址我們需要12個長度的文本,你那么這次我們將password.txt的內(nèi)容修改為123456781234567812345678,再次調(diào)試程序。


5.         再次調(diào)試可以看到堆棧內(nèi)的函數(shù)返回地址已經(jīng)被成功覆蓋了,但是執(zhí)行后會報錯,因為38373635的位置上并沒有執(zhí)行,是一片非法內(nèi)存。


6.         那么我們可以看到在0012FB20的位置上的字符串是1234,根據(jù)上下文,我們可以看出是第三個1234,那么我們就把它覆蓋成我們想要地址。比如輸出比對成功字符串的位置。


7.         那么我們把password.txt中第三個1234改成輸出字符串的地址,但是需要注意兩點。第一,我們要按照小端序倒著輸入返回地址,第二需要修改的是HEX而不是字符串。因此我們需要使用十六進制編輯器010editer進行如下編輯。


8.         然后我們再次調(diào)試程序??梢钥吹蕉褩V蟹祷氐刂芬呀?jīng)被我們成功覆蓋了。


9.         運行一下,可以看到成功的運行到了我們想要的位置,雖然隨后就因為堆棧不平衡導致程序崩潰,但是這是后續(xù)需要解決的問題,這一節(jié)的目的我們已經(jīng)成功達到了。


?