官术网_书友最值得收藏!

1.2 更為復(fù)雜C程序的運(yùn)行時(shí)結(jié)構(gòu)

在實(shí)際編程過(guò)程中會(huì)遇到更為復(fù)雜的問(wèn)題。要解決這樣的問(wèn)題,更加依賴對(duì)運(yùn)行時(shí)結(jié)構(gòu)的了解。下面我們來(lái)看一個(gè)比較復(fù)雜的案例,案例的兩個(gè)程序分別如下:

 #include <stdio.h>                                        #include <stdio.h>
#include <string.h>                                        #include <string.h>
void fun1()                                                void fun1()
{                                                          {
   int m =10;                                                     int m =10;
   char num[4];                                                   char hum[4];
   strcpy(num,"bbbbbbbbbbbbb\x0F\x10\x40\x00");                   strcpy(num, "bbbb");
)                                                          }
void fun2()                                                void fun2()
(                                                          {
   printf("You were attacked!!!\n");                              printf("You were attacked!!!\n");
}                                                          }
int main()                                                 int main()
(                                                          {
   fun1();                                                       fun1 ();
   return 0;                                                     return 0;
}                                                          }

這個(gè)案例中的兩個(gè)程序在代碼上只有微小的差別,但執(zhí)行結(jié)果卻不同,尤其是左邊的程序,執(zhí)行結(jié)果如下所示:

#include <stdio.h>
#include <string.h>
void fun1()
{
   int m =10;
   char num[4];
   strcpy(num,"bbbbbbbbbbbbb\x0F\x10\x40\x00");
)
void fun2()
(
   printf("You were attacked!!!\n");
}
int main()
(
   fun1();
   return 0;
}
    You were attacked!!!

這些字符顯然是fun2函數(shù)被調(diào)用時(shí)才會(huì)輸出的,但fun2這個(gè)函數(shù)在本程序中沒(méi)有被調(diào)用過(guò),這樣的輸出結(jié)果顯得有些不可思議了,程序執(zhí)行時(shí)到底發(fā)生了什么呢?下面我們一步一步地對(duì)比分析這個(gè)案例。我們先來(lái)看main函數(shù)調(diào)用fun1函數(shù)時(shí)的情景,fun1函數(shù)執(zhí)行后的返回地址被壓入棧中,跳轉(zhuǎn)到fun1函數(shù)執(zhí)行,此時(shí)兩邊程序的執(zhí)行沒(méi)有差異,情景如圖1-29所示。

圖1-29 兩個(gè)程序都跳轉(zhuǎn)到fun1后的整體比較

之后保存了main函數(shù)棧底的地址值,ebp被騰出來(lái),指向fun1函數(shù)的棧底,此時(shí)兩邊也沒(méi)有差異。情景如圖1-30所示。

圖1-30 兩個(gè)程序都保存了main棧底地址值并準(zhǔn)備為fun1建棧

m入棧,初始化為10,為num數(shù)組開(kāi)辟了棧空間,此時(shí)仍然沒(méi)有差異,情景如圖1-31所示。

圖1-31 兩個(gè)程序都為fun1函數(shù)的局部變量開(kāi)辟了棧空間

下面差異產(chǎn)生了。調(diào)用strcpy函數(shù),執(zhí)行的目的是把指定的字符串拷貝到num數(shù)組中,指定多少,拷貝多少。我們先來(lái)看右邊的程序。該程序會(huì)把指定的字符串拷貝給num數(shù)組,其長(zhǎng)度剛好填滿num數(shù)組,情景如圖1-32所示。

圖1-32 右邊程序?qū)?shù)組初始化

再看左邊程序,指定的字符串長(zhǎng)度已經(jīng)超出了num數(shù)組的長(zhǎng)度,所以在拷貝的時(shí)候,會(huì)把棧中前面的數(shù)據(jù)覆蓋掉,包括num的數(shù)組、main函數(shù)棧底地址值直至fun1函數(shù)執(zhí)行后的返回地址,全部被覆蓋,情景如圖1-33所示。

圖1-33 左邊程序?qū)?shù)組初始化后覆蓋了其他數(shù)據(jù)

覆蓋的結(jié)果使得fun1函數(shù)在返回并恢復(fù)現(xiàn)場(chǎng)時(shí)出現(xiàn)了問(wèn)題。

我們先來(lái)看右邊的程序,跳轉(zhuǎn)回main函數(shù),正常恢復(fù),情景如圖1-34所示。

圖1-34 右邊程序返回到main函數(shù)繼續(xù)執(zhí)行

再看左邊的程序,棧底地址值被覆蓋了,ebp會(huì)得到一個(gè)亂值,不再指向main函數(shù)的棧底,另外,由于fun1函數(shù)執(zhí)行后返回地址已經(jīng)被覆蓋,而且覆蓋的數(shù)值正好是fun2函數(shù)的起始地址,將這個(gè)數(shù)據(jù)傳遞給eip,那么eip自然跳轉(zhuǎn)到fun2函數(shù)執(zhí)行,相當(dāng)于調(diào)用了fun2函數(shù),也就輸出了fun2函數(shù)的打印信息。同時(shí),ebp成了亂值,程序最終將產(chǎn)生段錯(cuò)誤,情景如圖1-35所示。

圖1-35 左邊程序棧中數(shù)據(jù)被覆蓋后導(dǎo)致的后果

在C語(yǔ)言中,棧的方向是從高地址向低地址延伸,而數(shù)組中數(shù)據(jù)在棧中的存儲(chǔ)方向與此正好相反。字符串拷貝等數(shù)組操作是不對(duì)數(shù)據(jù)長(zhǎng)度做審核的,如果實(shí)際的數(shù)據(jù)長(zhǎng)度超過(guò)了棧中預(yù)留的空間,就會(huì)將棧中其他數(shù)據(jù)覆蓋,這種現(xiàn)象被稱為“棧溢出”。棧溢出可能導(dǎo)致一個(gè)不可預(yù)期的錯(cuò)誤,也可能導(dǎo)致一個(gè)精心策劃的執(zhí)行流程發(fā)生改變。可見(jiàn),是否能夠?qū)ψ约核鶎?xiě)程序的運(yùn)行時(shí)狀態(tài)做到心中有數(shù),是能否寫(xiě)出高質(zhì)量、安全代碼的前提保證。

以上兩節(jié)介紹的運(yùn)行時(shí)結(jié)構(gòu)都是由C程序所對(duì)應(yīng)的指令,在內(nèi)存中執(zhí)行,驅(qū)動(dòng)數(shù)據(jù)變化而產(chǎn)生的。C程序只有經(jīng)過(guò)編譯,才能生成目標(biāo)代碼。目標(biāo)代碼將與指令和全局?jǐn)?shù)據(jù)一一對(duì)應(yīng)。編譯的最終目標(biāo)就是能讓C程序的設(shè)計(jì)意圖體現(xiàn)在運(yùn)行時(shí)結(jié)構(gòu)中,這也使得編譯的每個(gè)階段的中心任務(wù)都要為形成運(yùn)行時(shí)結(jié)構(gòu)著想。下一節(jié)我們將概述編譯的過(guò)程。

主站蜘蛛池模板: 河西区| 德钦县| 邯郸县| 赫章县| 彰化市| 阳泉市| 延津县| 乐业县| 会宁县| 界首市| 贵溪市| 通榆县| 禹州市| 浦北县| 秦安县| 石门县| 恩平市| 定安县| 锡林浩特市| 民丰县| 疏勒县| 荣昌县| 化州市| 辉南县| 仲巴县| 武冈市| 阳高县| 铜川市| 巴南区| 新兴县| 富锦市| 阳原县| 修文县| 芮城县| 红安县| 呼图壁县| 无锡市| 赫章县| 玉屏| 十堰市| 阿克苏市|