這里我們?yōu)榱说竭_(dá)實(shí)驗(yàn)的要求,先來(lái)編寫(xiě)1個(gè)最簡(jiǎn)單的存在緩沖區(qū)溢出隱患的程序。這個(gè)程序我使用VC++6.0進(jìn)行編寫(xiě),并在Windows XP下履行。(這里請(qǐng)大家注意的是,如果你使用的是新版本的VC,由于微軟加入了GS機(jī)制來(lái)避免緩沖區(qū)溢出情況的出現(xiàn),那末本實(shí)驗(yàn)就沒(méi)法實(shí)現(xiàn)。)
首先新建1個(gè)Win32控制臺(tái)利用程序,然后輸入以下C語(yǔ)言代碼:
圖1
可見(jiàn)程序已得到了正確的履行與輸出。但是我在程序中所創(chuàng)建出來(lái)的是1個(gè)8字節(jié)長(zhǎng)度的數(shù)組,而我在程序中的輸入是7個(gè)字節(jié)。如果我的輸入超過(guò)8個(gè)字節(jié)會(huì)怎樣樣呢?無(wú)妨試1下。
這次再次運(yùn)行程序,嘗試輸入“jiangyejiangye”,運(yùn)行結(jié)果以下:
圖2
可見(jiàn),程序雖然也能夠正確輸出,但是卻彈出了毛病提示對(duì)話框。為何會(huì)出現(xiàn)這類(lèi)情況?我們接下來(lái)就來(lái)研究1下。
圖3
這些都是系統(tǒng)自動(dòng)生成的,與我們的實(shí)驗(yàn)無(wú)關(guān),我們?cè)诖艘矡o(wú)需關(guān)注這些代碼的功能。對(duì)本次實(shí)驗(yàn)來(lái)講,我們只要找到main函數(shù),從而進(jìn)1步分析便可。那末應(yīng)當(dāng)如何尋覓main函數(shù)呢?固然我們可以不斷地按F8單步履行,通過(guò)視察獲得,但是這樣未免需要1定的經(jīng)驗(yàn),而且也比較麻煩。所以這里無(wú)妨利用IDA Pro來(lái)打開(kāi)我們的實(shí)驗(yàn)程序,以下圖所示:
圖4
可見(jiàn),IDA已幫我們獲得了main函數(shù)的入口地址,即0x00401010,那末我們此時(shí)可以在OD中,跳到該地址,按F2下1個(gè)斷點(diǎn)。以下圖所示:
圖5
由上面的截圖,我們除可以知道m(xù)ain函數(shù)的位置外,我們還從下面那段話“Jump from 00401005”得知main函數(shù)是由位于0x00401005位置處的語(yǔ)句跳過(guò)來(lái)的。由于緩沖區(qū)溢出是與??臻g緊密相干的,所以我們現(xiàn)在應(yīng)當(dāng)分析調(diào)用(CALL)main函數(shù)前后,棧空間的情況,所以這里我們就需要定位究竟是哪條語(yǔ)句調(diào)用了main函數(shù)。如果僅僅通過(guò)OD,我們是比較難定位的,所以這里我還是使用IDA Pro。
由于已知道m(xù)ain函數(shù)的地址是0x00401010,那末我們?cè)贗DA中,用鼠標(biāo)在該地址點(diǎn)1下,以后利用快捷鍵“Ctrl+X”打開(kāi)“交叉援用窗口”,就來(lái)到了jmp到此的函數(shù)位置:
圖6
然后在0x00401005的地址處,再次利用“交叉援用”功能,我們就可以夠找到調(diào)用main函數(shù)的位置了:
圖7
現(xiàn)在就已知道,是位于0x00401694處的語(yǔ)句調(diào)用了main函數(shù),那末我們下1步的工作就是分析該語(yǔ)句履行前后,堆棧的情況。
圖8
可以看到,CALL下面的語(yǔ)句的地址是0x00401699。這個(gè)地址之所以重要,是由于我們的程序在進(jìn)入每個(gè)CALL之前,都會(huì)首先將CALL下面那條語(yǔ)句的地址入棧,然后再履行CALL語(yǔ)句。這樣當(dāng)CALL履行完后,程序再將該地址出棧,這樣就可以夠知道下1步應(yīng)當(dāng)履行哪條指令。我們1般也將這個(gè)地址稱為“返回地址”,它告知程序:“CALL履行完后,請(qǐng)履行這個(gè)地址處的語(yǔ)句?!?/p>
我們先看1下當(dāng)前棧的情況:
圖9
注意??臻g由下至上是高地址往低地址處走的。然后我們按下F7,步入這個(gè)CALL,此時(shí)再看1下棧空間:
圖10
可見(jiàn),返回地址0x00401669已入棧。這就是CALL語(yǔ)句對(duì)棧空間的影響,而這個(gè)返回地址在后面的漏洞利用中,其影響相當(dāng)重要,請(qǐng)大家牢記。
圖11
在上圖中,比較重要的是最后兩行。其中最后1行在之前已講過(guò)了,是非常重要的返回地址,它決定了當(dāng)main函數(shù)履行終了后,程序所要履行的語(yǔ)句的地址,而倒數(shù)第2行是父函數(shù)的EBP,關(guān)于這個(gè),我們知道便可,再往上,就是我們的main函數(shù)的局部變量空間。這里大家可能會(huì)有疑惑,既然是分配給我們的空間,那末為何還會(huì)有其它的數(shù)據(jù)呢?關(guān)于這個(gè)大家不要急,當(dāng)我們履行完0x0040DA36的語(yǔ)句后,再看1下這段棧的空間:
圖12
可見(jiàn)這段空間都被0xCC填充了。程序?yàn)榱巳蒎e(cuò)性與保持本身的硬朗性,因而利用0xCC,即int 3斷點(diǎn)來(lái)填充滿這段區(qū)域,這樣1來(lái),如果有未知的程序跳到這片區(qū)域,就不會(huì)出現(xiàn)崩潰的情況,而是直接斷下來(lái)了。固然,這個(gè)問(wèn)題與我們的緩沖區(qū)溢出沒(méi)甚么關(guān)系,大家知道便可。
然后繼續(xù)履行,查找反匯編代碼strcpy函數(shù)的位置,先來(lái)看1看正常情況下,履行這個(gè)函數(shù)前后,堆棧的情況:
圖13
這里可以看到,strcpy的第2個(gè)參數(shù),就是所接收的字符串所保存的地址位置,其保存位置為0x0012FF78。接下來(lái)看看當(dāng)“jiangye”這段字符串拷貝到這段區(qū)域時(shí),棧中的情況:
圖14
對(duì)照上1張圖可以發(fā)現(xiàn),棧中的地址0x0012FF20位置處,保存的是strcpy第2個(gè)參數(shù)的地址,OD幫我們解析出了,其內(nèi)容為“jiangye”。而在棧中地址為0x0012FF78處,則是我們真實(shí)的保存“jiangye”這段字符串的內(nèi)存空間。這并沒(méi)有甚么問(wèn)題,程序能夠取得正常履行。那末如果我將strcpy的第1個(gè)參數(shù)改寫(xiě)為“jiangyejiangye”會(huì)如何呢?利用OD打開(kāi)OverrunTest_2.exe,來(lái)到一樣的位置,以下圖所示:
圖15
可以發(fā)現(xiàn),由于我們所輸入的字符串太長(zhǎng),使得本來(lái)位于棧中0x0012FF80處的父函數(shù)EBP和本來(lái)位于棧中0x0012FF84處的返回地址全都被改寫(xiě)了。這里我們主要關(guān)注位于0x0012FF84處的返回地址,原來(lái)它所保存的值為0x00401669,也就告知了程序,在履行完main函數(shù)后,需要履行該地址處的指令??墒乾F(xiàn)在那個(gè)棧中的內(nèi)容被破壞了,變成了0x00006579,即當(dāng)main函數(shù)履行終了后,程序會(huì)跳到地址為0x00006579處繼續(xù)履行。那末會(huì)產(chǎn)生甚么問(wèn)題呢?我們無(wú)妨繼續(xù)履行看看:
圖16
到這里,main函數(shù)需要返回,可以看到它要返回到0x00006579的地址處,來(lái)履行該地址處的指令,我們?cè)賳尾竭\(yùn)行1下:
圖17
此時(shí)我們發(fā)現(xiàn)了兩件事,1件是OD中的反匯編代碼窗口是空的,說(shuō)明0x00006579地址處不存在指令,或說(shuō)它就是1個(gè)無(wú)效地址。第2件事是OD彈出了毛病對(duì)話框,提示我們?cè)摰刂烦鲥e(cuò),這與我們直接履行程序時(shí)所彈出的毛病對(duì)話框有幾分類(lèi)似。
至此,大家應(yīng)當(dāng)已了解了緩沖區(qū)溢出漏洞的原理,它就是由于我們輸入了太長(zhǎng)的字符,而緩沖區(qū)本身又沒(méi)有有效的驗(yàn)證機(jī)制,致使太長(zhǎng)的字符將返回地址覆蓋掉了,當(dāng)我們的函數(shù)需要返回的時(shí)候,由于此時(shí)的返回地址是1個(gè)無(wú)效地址,因此致使程序出錯(cuò)。
那末根據(jù)這個(gè)原理,假定我們所覆蓋的返回地址是1個(gè)有效地址,而在該地址處又包括著有效的指令,那末我們的系統(tǒng)就會(huì)絕不猶豫地跳到該地址處去履行指令。因此,如果想利用緩沖區(qū)溢出的漏洞,我們就能夠構(gòu)造出1個(gè)有效地址出來(lái),然后將我們想讓計(jì)算機(jī)履行的代碼寫(xiě)入該地址,這樣1來(lái),我們就通進(jìn)程序的漏洞,讓計(jì)算機(jī)履行了我們自己編寫(xiě)的程序。而具體的關(guān)于漏洞利用的知識(shí),我會(huì)在下1節(jié)課中給大家詳細(xì)講授。