堆棧溢出攻擊原理

轉(zhuǎn)載掉蔬,詳見原文:https://blog.csdn.net/aemperor/article/details/47310593
eax, ebx, ecx, edx, esi, edi, ebp, esp等都是X86 匯編語(yǔ)言中CPU上的通用寄存器的名稱嚷往,是32位的寄存器栗竖。如果用C語(yǔ)言來(lái)解釋攒暇,可以把這些寄存器當(dāng)作變量看待指巡。

比方說(shuō):add eax,-2 ; //可以認(rèn)為是給變量eax加上-2這樣的一個(gè)值。

這些32位寄存器有多種用途,但每一個(gè)都有“專長(zhǎng)”振峻,有各自的特別之處。

EAX 是"累加器"(accumulator), 它是很多加法乘法指令的缺省寄存器择份。

EBX 是"基地址"(base)寄存器, 在內(nèi)存尋址時(shí)存放基地址扣孟。

ECX 是計(jì)數(shù)器(counter), 是重復(fù)(REP)前綴指令和LOOP指令的內(nèi)定計(jì)數(shù)器。

EDX 則總是被用來(lái)放整數(shù)除法產(chǎn)生的余數(shù)荣赶。

ESI/EDI分別叫做"源/目標(biāo)索引寄存器"(source/destination index),因?yàn)樵诤芏嘧址僮髦噶钪? DS:ESI指向源串,而ES:EDI指向目標(biāo)串.

EBP是"基址指針"(BASE POINTER), 它最經(jīng)常被用作高級(jí)語(yǔ)言函數(shù)調(diào)用的"框架指針"(frame pointer). 在破解的時(shí)候,經(jīng)撤锛郏可以看見一個(gè)標(biāo)準(zhǔn)的函數(shù)起始代碼:

push ebp ;保存當(dāng)前ebp
mov ebp,esp ;EBP設(shè)為當(dāng)前堆棧指針
sub esp, xxx ;預(yù)留xxx字節(jié)給函數(shù)臨時(shí)變量.
...

這樣一來(lái),EBP 構(gòu)成了該函數(shù)的一個(gè)框架, 在EBP上方分別是原來(lái)的EBP, 返回地址和參數(shù). EBP下方則是臨時(shí)變量. 函數(shù)返回時(shí)作 mov esp,ebp/pop ebp/ret 即可.

ESP 專門用作堆棧指針,被形象地稱為棧頂指針拔创,堆棧的頂部是地址小的區(qū)域利诺,壓入堆棧的數(shù)據(jù)越多,ESP也就越來(lái)越小剩燥。在32位平臺(tái)上慢逾,ESP每次減少4字節(jié)。

esp:寄存器存放當(dāng)前線程的棧頂指針
ebp:寄存器存放當(dāng)前線程的棧底指針
eip:寄存器存放下一個(gè)CPU指令存放的內(nèi)存地址灭红,當(dāng)CPU執(zhí)行完當(dāng)前的指令后侣滩,從EIP寄存器中讀取下一條指令的內(nèi)存地址,然后繼續(xù)執(zhí)行变擒。

一般寄存器:AX胜卤、BX、CX赁项、DX
AX:累積暫存器葛躏,BX:基底暫存器,CX:計(jì)數(shù)暫存器悠菜,DX:資料暫存器

索引暫存器:SI舰攒、DI
SI:來(lái)源索引暫存器,DI:目的索引暫存器

堆疊悔醋、基底暫存器:SP摩窃、BP
SP:堆疊指標(biāo)暫存器,BP:基底指標(biāo)暫存器

EAX芬骄、ECX猾愿、EDX、EBX:為ax,bx,cx,dx的延伸账阻,各為32位元
ESI蒂秘、EDI、ESP淘太、EBP:為si,di,sp,bp的延伸姻僧,32位元

棧的基本模型

參數(shù)N

↓高地址

參數(shù)…

函數(shù)參數(shù)入棧的順序與具體的調(diào)用方式有關(guān)

參數(shù) 3

參數(shù) 2

參數(shù) 1

EIP

返回本次調(diào)用后规丽,下一條指令的地址

EBP

保存調(diào)用者的EBP,然后EBP指向此時(shí)的棧頂撇贺。

臨時(shí)變量1

臨時(shí)變量2

臨時(shí)變量3

臨時(shí)變量…

臨時(shí)變量5

↓低地址

EIP赌莺,EBP,ESP都是系統(tǒng)的寄存器松嘶,里面存的都是些地址艘狭。
為什么要說(shuō)這三個(gè)指針,是因?yàn)槲覀兿到y(tǒng)中棧的實(shí)現(xiàn)上離不開他們?nèi)齻€(gè)翠订。
我們DC上講過(guò)棧的數(shù)據(jù)結(jié)構(gòu)巢音,主要有以下特點(diǎn):
后進(jìn)先處。(這個(gè)強(qiáng)調(diào)過(guò)多)

其實(shí)它還有以下兩個(gè)作用:
1.棧是用來(lái)存儲(chǔ)臨時(shí)變量蕴轨,函數(shù)傳遞的中間結(jié)果港谊。
2.操作系統(tǒng)維護(hù)的骇吭,對(duì)于程序員是透明的橙弱。
我們可能只強(qiáng)調(diào)了它的后進(jìn)先出的特點(diǎn),至于棧實(shí)現(xiàn)的原理燥狰,沒怎么講棘脐?下面我們就通過(guò)一個(gè)小例子說(shuō)說(shuō)棧的原理。
先寫個(gè)小程序:
void fun(void)
{
printf("hello world")龙致;
}
void main(void)
{
fun()
printf("函數(shù)調(diào)用結(jié)束");
}
這是一個(gè)再簡(jiǎn)單不過(guò)的函數(shù)調(diào)用的例子了蛀缝。
當(dāng)程序進(jìn)行函數(shù)調(diào)用的時(shí)候,我們經(jīng)常說(shuō)的是先將函數(shù)壓棧目代,當(dāng)函數(shù)調(diào)用結(jié)束后屈梁,再出棧。這一切的工作都是系統(tǒng)幫我們自動(dòng)完成的榛了。
但在完成的過(guò)程中在讶,系統(tǒng)會(huì)用到下面三種寄存器:
1.EIP
2.ESP
3.EBP
當(dāng)調(diào)用fun函數(shù)開始時(shí),三者的作用霜大。
1.EIP寄存器里存儲(chǔ)的是CPU下次要執(zhí)行的指令的地址构哺。
也就是調(diào)用完fun函數(shù)后,讓CPU知道應(yīng)該執(zhí)行main函數(shù)中的printf("函數(shù)調(diào)用結(jié)束")語(yǔ)句了战坤。
2.EBP寄存器里存儲(chǔ)的是是棧的棧底指針曙强,通常叫棧基址途茫,這個(gè)是一開始進(jìn)行fun()函數(shù)調(diào)用之前碟嘴,由ESP傳遞給EBP的。(在函數(shù)調(diào)用前你可以這么理解:ESP存儲(chǔ)的是棧頂?shù)刂纺也罚彩菞5椎刂吠畏馈#?br> 3.ESP寄存器里存儲(chǔ)的是在調(diào)用函數(shù)fun()之后眠菇,棧的棧頂。并且始終指向棧頂袱衷。

當(dāng)調(diào)用fun函數(shù)結(jié)束后捎废,三者的作用:
1.系統(tǒng)根據(jù)EIP寄存器里存儲(chǔ)的地址,CPU就能夠知道函數(shù)調(diào)用完致燥,下一步應(yīng)該做什么登疗,也就是應(yīng)該執(zhí)行main函數(shù)中的printf(“函數(shù)調(diào)用結(jié)束”)。
2.EBP寄存器存儲(chǔ)的是棧底地址嫌蚤,而這個(gè)地址是由ESP在函數(shù)調(diào)用前傳遞給EBP的辐益。等到調(diào)用結(jié)束,EBP會(huì)把其地址再次傳回給ESP脱吱。所以ESP又一次指向了函數(shù)調(diào)用結(jié)束后智政,棧頂?shù)牡刂贰?br> 其實(shí)我們對(duì)這個(gè)只需要知道三個(gè)指針是什么就可以,可能對(duì)我們以后學(xué)習(xí)棧溢出的問題以及看棧這方面的書籍有些幫助箱蝠。當(dāng)有人再給你說(shuō)EIP,ESP,EBP的時(shí)候续捂,你不能一頭霧水,那你水平就顯得洼了許多宦搬。其實(shí)不知道我們照樣可以編程,因?yàn)槲覀兪荂級(jí)別的程序員牙瓢,而不是ASM級(jí)別的程序員

通過(guò)堆棧溢出來(lái)獲得root權(quán)限是目前使用的相當(dāng)普遍的一項(xiàng)黑客技術(shù)。事實(shí)上這是一個(gè)黑客在系統(tǒng)本地已經(jīng)擁有了一個(gè)基本賬號(hào)后的首選攻擊方式间校。
他也被廣泛應(yīng)用于遠(yuǎn)程攻擊矾克。通過(guò)對(duì)daemon進(jìn)程的堆棧溢出來(lái)實(shí)現(xiàn)遠(yuǎn)程獲得rootshell的技術(shù),已經(jīng)被很多實(shí)例實(shí)現(xiàn)憔足。
在windows系統(tǒng)中胁附,同樣存在著堆棧溢出的問題。而且滓彰,隨著internet的普及控妻,win系列平臺(tái)上的internet服務(wù)程序越來(lái)越多,低水平的win程序就成為你系統(tǒng)上的致命傷因?yàn)樗鼈兺瑯訒?huì)被遠(yuǎn)程堆棧溢出找蜜,而且饼暑,由于win系統(tǒng)使用者和管理者普遍缺乏安全防范的意識(shí),一臺(tái)win系統(tǒng)上的堆棧溢出洗做,如果被惡意利用弓叛,將導(dǎo)致整個(gè)機(jī)器被敵人所控制。進(jìn)而诚纸,可能導(dǎo)致整個(gè)局域網(wǎng)落入敵人之手撰筷。
本系列講座將系統(tǒng)的介紹堆棧溢出的機(jī)制,原理畦徘,應(yīng)用毕籽,以及防范的措施抬闯。希望通過(guò)我的講座,大家可以了解和掌握這項(xiàng)技術(shù)关筒。而且溶握,會(huì)自己去尋找堆棧溢出漏洞,以提高系統(tǒng)安全蒸播。
堆棧溢出系列講座
入門篇

本講的預(yù)備知識(shí):
首先你應(yīng)該了解intel匯編語(yǔ)言睡榆,熟悉寄存器的組成和功能袍榆。
你必須有堆棧和存儲(chǔ)分配方面的基礎(chǔ)知識(shí)胀屿,有關(guān)這方面的計(jì)算機(jī)書籍很多包雀,我將只是簡(jiǎn)單闡述原理,著重在應(yīng)用才写。
其次,你應(yīng)該了解linux琅摩,本講中我們的例子將在linux上開發(fā)铁孵。
1:首先復(fù)習(xí)一下基礎(chǔ)知識(shí)锭硼。
從物理上講房资,堆棧是就是一段連續(xù)分配的內(nèi)存空間。在一個(gè)程序中檀头,會(huì)聲明各種變量轰异。靜態(tài)全局變量是位于數(shù)據(jù)段并且在程序開始運(yùn)行的時(shí)候被加載。而程序的動(dòng)態(tài)的局部變量則分配在堆棧里面暑始。
從操作上來(lái)講搭独,堆棧是一個(gè)先入后出的隊(duì)列。他的生長(zhǎng)方向與內(nèi)存的生長(zhǎng)方向正好相反廊镜。我們規(guī)定內(nèi)存的生長(zhǎng)方向?yàn)橄蛏涎栏危瑒t棧的生長(zhǎng)方向?yàn)橄蛳隆簵5牟僮鱬ush=ESP-4嗤朴,出棧的操作是pop=ESP+4.換句話說(shuō)配椭,堆棧中老的值,其內(nèi)存地址雹姊,反而比新的值要大股缸。請(qǐng)牢牢記住這一點(diǎn),因?yàn)檫@是堆棧溢出的基本理論依據(jù)吱雏。
在一次函數(shù)調(diào)用中敦姻,堆棧中將被依次壓入:參數(shù)瘾境,返回地址,EBP镰惦。如果函數(shù)有局部變量迷守,接下來(lái),就在堆棧中開辟相應(yīng)的空間以構(gòu)造變量旺入。函數(shù)執(zhí)行結(jié)束盒犹,這些局部變量的內(nèi)容將被丟失。但是不被清除眨业。在函數(shù)返回的時(shí)候急膀,彈出EBP,恢復(fù)堆棧到函數(shù)調(diào)用的地址,彈出返回地址到EIP以繼續(xù)執(zhí)行程序龄捡。
在C語(yǔ)言程序中卓嫂,參數(shù)的壓棧順序是反向的。比如func(a,b,c)聘殖。在參數(shù)入棧的時(shí)候晨雳,是:先壓c,再壓b,最后壓a.在取參數(shù)的時(shí)候奸腺,由于棧的先入后出餐禁,先取棧頂?shù)腶,再取b,最后取c突照。(PS:如果你看不懂上面這段概述帮非,請(qǐng)你去看以看關(guān)于堆棧的書籍,一般的匯編語(yǔ)言書籍都會(huì)詳細(xì)的討論堆棧讹蘑,必須弄懂它末盔,你才能進(jìn)行下面的學(xué)習(xí))
2:好了座慰,繼續(xù),讓我們來(lái)看一看什么是堆棧溢出。
2.1:運(yùn)行時(shí)的堆棧分配
堆棧溢出就是不顧堆棧中分配的局部數(shù)據(jù)塊大小版仔,向該數(shù)據(jù)塊寫入了過(guò)多的數(shù)據(jù)游盲,導(dǎo)致數(shù)據(jù)越界。結(jié)果覆蓋了老的堆棧數(shù)據(jù)蛮粮。
比如有下面一段程序:
程序一:

include

int main ( )
{
char name[8];
printf("Please type your name: ");
gets(name);
printf("Hello, %s!", name);
return 0;
}
編譯并且執(zhí)行益缎,我們輸入ipxodi,就會(huì)輸出Hello,ipxodi!蝉揍。程序運(yùn)行中,堆棧是怎么操作的呢又沾?
在main函數(shù)開始運(yùn)行的時(shí)候弊仪,堆棧里面將被依次放入返回地址,EBP励饵。
我們用gcc -S 來(lái)獲得匯編語(yǔ)言輸出,可以看到main函數(shù)的開頭部分對(duì)應(yīng)如下語(yǔ)句

pushl %ebp
movl %esp,%ebp
subl $8,%esp
首先他把EBP保存下來(lái)颓鲜,典予,然后EBP等于現(xiàn)在的ESP,這樣EBP就可以用來(lái)訪問本函數(shù)的局部變量衣摩。之后ESP減8捂敌,就是堆棧向上增長(zhǎng)8個(gè)字節(jié),用來(lái)存放name[]數(shù)組∨葑欤現(xiàn)在堆棧的布局如下:
內(nèi)存底部 內(nèi)存頂部
name EBP ret
<------ [ ][ ][ ]
^&name
堆棧頂部 堆棧底部
執(zhí)行完gets(name)之后逆济,堆棧如下:
內(nèi)存底部 內(nèi)存頂部
name EBP ret
<------ [ipxodi/0 ][ ][ ]
^&name
堆棧頂部 堆棧底部
最后,main返回纹腌,彈出ret里的地址升薯,賦值給EIP击困,CPU繼續(xù)執(zhí)行EIP所指向的指令。

2.2:堆棧溢出
好阅茶,看起來(lái)一切順利。我們?cè)賵?zhí)行一次蹦浦,輸入ipxodiAAAAAAAAAAAAAAA,執(zhí)行完
gets(name)
之后撞蜂,堆棧如下:
內(nèi)存底部 內(nèi)存頂部
name EBP ret
<------ [ipxodiAA][AAAA][AAAA].......
^&name
堆棧頂部 堆棧底部
由于我們輸入的name字符串太長(zhǎng),name數(shù)組容納不下溉贿,只好向內(nèi)存頂部繼續(xù)寫‘A’。由于堆棧的生長(zhǎng)方向與內(nèi)存的生長(zhǎng)方向相反宇色,這些‘A’覆蓋了堆棧的老的元素。如圖我們可以發(fā)現(xiàn)例隆,EBP裳擎,ret都已經(jīng)被‘A’覆蓋了思币。在main返回的時(shí)候,就會(huì)把‘AAAA’的ASCII碼:0x41414141作為返回地址谷饿,CPU會(huì)試圖執(zhí)行0x41414141處的指令,結(jié)果出現(xiàn)錯(cuò)誤绸贡。這就是一次堆棧溢出听怕。
3:如何利用堆棧溢出
我們已經(jīng)制造了一次堆棧溢出虑绵。其原理可以概括為:由于字符串處理函數(shù)(gets,strcpy等等)沒有對(duì)數(shù)組越界加以監(jiān)視和限制翅睛,我們利用字符數(shù)組寫越界,覆蓋堆棧中的老元素的值疏旨,就可以修改返回地址檐涝。
在上面的例子中,這導(dǎo)致CPU去訪問一個(gè)不存在的指令谁榜,結(jié)果出錯(cuò)。
事實(shí)上喊暖,當(dāng)堆棧溢出的時(shí)候陵叽,我們已經(jīng)完全的控制了這個(gè)程序下一步的動(dòng)作丛版。如果我們用一個(gè)實(shí)際存在指令地址來(lái)覆蓋這個(gè)返回地址,CPU就會(huì)轉(zhuǎn)而執(zhí)行我們的指令页畦。
在UINX系統(tǒng)中豫缨,我們的指令可以執(zhí)行一個(gè)shell,這個(gè)shell將獲得和被我們堆棧溢出的程序相同的權(quán)限燃箭。如果這個(gè)程序是setuid的,那么我們就可以獲得root shell招狸。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末裙戏,一起剝皮案震驚了整個(gè)濱河市厕诡,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌木人,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評(píng)論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異稠曼,居然都是意外死亡客年,警方通過(guò)查閱死者的電腦和手機(jī)漠吻,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)扔傅,“玉大人,你說(shuō)我怎么就攤上這事猎塞≤ⅲ” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵倘屹,是天一觀的道長(zhǎng)慢叨。 經(jīng)常有香客問我插爹,道長(zhǎng),這世上最難降的妖魔是什么力穗? 我笑而不...
    開封第一講書人閱讀 58,242評(píng)論 1 292
  • 正文 為了忘掉前任当窗,我火速辦了婚禮寸宵,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘巫员。我一直安慰自己简识,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,269評(píng)論 6 389
  • 文/花漫 我一把揭開白布奢赂。 她就那樣靜靜地躺著颈走,像睡著了一般。 火紅的嫁衣襯著肌膚如雪轧钓。 梳的紋絲不亂的頭發(fā)上聋迎,一...
    開封第一講書人閱讀 51,215評(píng)論 1 299
  • 那天,我揣著相機(jī)與錄音枣耀,去河邊找鬼霉晕。 笑死,一個(gè)胖子當(dāng)著我的面吹牛捞奕,可吹牛的內(nèi)容都是我干的牺堰。 我是一名探鬼主播,決...
    沈念sama閱讀 40,096評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼颅围,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼伟葫!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起院促,我...
    開封第一講書人閱讀 38,939評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤筏养,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后常拓,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體渐溶,經(jīng)...
    沈念sama閱讀 45,354評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,573評(píng)論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了拖陆。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片依啰。...
    茶點(diǎn)故事閱讀 39,745評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡灌闺,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出鸠匀,到底是詐尸還是另有隱情缀棍,我是刑警寧澤爬范,帶...
    沈念sama閱讀 35,448評(píng)論 5 344
  • 正文 年R本政府宣布萧诫,位于F島的核電站帘饶,受9級(jí)特大地震影響镀裤,放射性物質(zhì)發(fā)生泄漏暑劝。R本人自食惡果不足惜铃岔,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,048評(píng)論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望纺且。 院中可真熱鬧猜嘱,春花似錦朗伶、人聲如沸论皆。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至捐康,卻和暖如春解总,著一層夾襖步出監(jiān)牢的瞬間花枫,已是汗流浹背敦锌。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留听想,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,776評(píng)論 2 369
  • 正文 我出身青樓垫卤,卻偏偏與公主長(zhǎng)得像穴肘,于是被迫代替她去往敵國(guó)和親梢褐。 傳聞我的和親對(duì)象是個(gè)殘疾皇子耿眉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,652評(píng)論 2 354