函數(shù)過程調(diào)用棧分析

首先寄存器使用慣例:
eip :指令地址寄存器鞍陨,保存程序計(jì)數(shù)器的值,當(dāng)前執(zhí)行的指令的下一條指令的地址值添怔,16位中為ip湾戳,32位為eip贤旷。eip不可以直接賦值广料,一般都是cpu自動(dòng)加1來更新,指令call和ret以及jmp可以改變eip的值幼驶。
另外匯編代碼格式有ATT和intel格式艾杏,gcc和objdump的默認(rèn)格式就是ATT。幾個(gè)小區(qū)別盅藻,1首先是指令A(yù)TT匯編指令后面有一個(gè)l购桑,比如intel格式為mov,ATT格式為movl
2寄存器氏淑,ATT格式有%勃蜘,比如intel格式為ebp,ATT格式為%ebp
3還有一個(gè)最主要的區(qū)別就是操作指令的假残,操作數(shù)的順序是相反的缭贡,源操作數(shù)和目的操作數(shù)的順序相反。
關(guān)于棧中的寄存器:
esp :棧指針辉懒,又叫棧頂寄存器阳惹,總是指向棧頂元素,已經(jīng)壓入棧的最頂上的那個(gè)元素眶俩,而不是待壓入的莹汤。棧指針可以移動(dòng),通過上下移動(dòng)實(shí)現(xiàn)棧的開辟和釋放颠印。棧是向小地址方向生長(zhǎng)的纲岭。esp寄存器中保存的是當(dāng)前棧的棧頂元素的地址抹竹。
ebp :幀指針,又叫椈挠拢基址寄存器柒莉,總是指向當(dāng)前棧的棧底元素。保存的是當(dāng)前棧的棧底元素的地址沽翔。幀指針不可以移動(dòng)兢孝,用來作為當(dāng)前棧的基址,通過對(duì)基址ebp的偏移來尋址訪問棧中的其他元素的值仅偎。比如:0x8(%ebp)ebp所指向的地址值在加上0x8的地址跨蟹。
ebp永遠(yuǎn)都是針對(duì)當(dāng)前棧的,所以當(dāng)一個(gè)函數(shù)調(diào)用了另外一個(gè)函數(shù)的時(shí)候橘沥,就需要先將調(diào)用函數(shù)的棧的ebp給入棧保存窗轩,這樣避免了與被調(diào)用函數(shù)的棧ebp沖突,然后在被調(diào)用函數(shù)的棧結(jié)束調(diào)用釋放的時(shí)候座咆,恢復(fù)現(xiàn)場(chǎng)的時(shí)候痢艺,在將調(diào)用函數(shù)的ebp彈出來,這樣又可以回到調(diào)用函數(shù)的棧了介陶。
棧通過棧指針棧頂esp和幀指針棧底ebp來固定椀淌妫框。
eax :保存函數(shù)的返回值的慣用寄存器
% :直接尋址寄存器
( ) :內(nèi)存間接尋址
$ :立即數(shù)
例如:movl $8, %eax #把立即數(shù)8存到寄存器eax中
movl $8, (%esp) #把立即數(shù)8存到內(nèi)存esp所指的內(nèi)存地址中哺呜。
這里主要來通過函數(shù)調(diào)用來徹底弄清楚棧的過程舌缤,這里直接利用bufbomb中的一段簡(jiǎn)單的c代碼,通過反匯編來分析一下其匯編代碼某残。這個(gè)c代碼很簡(jiǎn)單国撵,就是test函數(shù)中調(diào)用了getbuf函數(shù)。



其反匯編代碼為:



這里的匯編代碼比較長(zhǎng)我們來截取一下只看關(guān)于棧和函數(shù)調(diào)用的部分:





來看一下不管是test還是getbuf都有的幾句匯編語言:


函數(shù)的實(shí)現(xiàn)過程都是通過棧過程玻墅,一開始我們已經(jīng)講過了棧有兩個(gè)指針用來固定椊檠溃框的,ebp棧底指針和而esp棧頂指針澳厢。
push %ebp #保存舊的ebp的值环础,也就是保存當(dāng)前函數(shù)的調(diào)用者的棧的棧基址赏酥。(因?yàn)槊恳粋€(gè)棧都有一個(gè)ebp是不可以移動(dòng)的喳整,但是名字又一樣,怎么區(qū)分呢裸扶,那就是開始時(shí)先把原來的ebp保存起來框都,然后生成自己的,調(diào)用結(jié)束后,在把原來的恢復(fù)魏保,彈出來熬尺,自己的釋放掉,這樣人家原來的ebp又可以繼續(xù)在自己的棧中作為基址了谓罗。不然就覆蓋了回不去了)相對(duì)于test來說可能就是main之類的調(diào)用test的函數(shù)的棧的ebp粱哼,對(duì)于getbuf來說就是test的ebp。將ebp壓入棧中檩咱,這個(gè)時(shí)候esp自動(dòng)-4揭措,指向新壓入的ebp元素的位置處。
mov %esp,%ebp #使幀指針ebp指向當(dāng)前的esp處刻蚯,也就是初始化生成一個(gè)當(dāng)前棧的基址幀指針ebp绊含,也就是當(dāng)前棧的棧底表示出來固定住。對(duì)于test來說就是test的棧底炊汹,對(duì)于getbuf來說就是getbuf的棧的棧底躬充。
sub $0x38,%esp #通過棧指針esp向下移動(dòng)為當(dāng)前函數(shù)開辟自己的棧,esp指向了棧頂讨便,從ebp到esp為當(dāng)前函數(shù)的棾渖酰空間。
以上三條指令就是所有棧都有的棧開辟匯編指令霸褒。
接下來來看棧釋放的匯編指令:



這里是兩個(gè)函數(shù)中不同的棧釋放恢復(fù)指令伴找,有點(diǎn)不一樣但是原理是一樣的。
add $0x24,%esp #釋放當(dāng)前棧開辟的空間傲霸,在test函數(shù)開始的時(shí)候通過棧指針esp減0x24移動(dòng)來開辟了當(dāng)前test函數(shù)自己的椊澹空間∶挤矗現(xiàn)在將esp加上0x24也就是使esp從新移動(dòng)到了棧底ebp處昙啄,就將原來開辟的棧空間釋放掉了寸五。另外一條常用的匯編指令是:
mov %ebp,%esp #將ebp的值給esp梳凛,也就是把esp指向當(dāng)前的棧底
pop %ebx #把之前保存的寄存器ebx恢復(fù)
pop %ebp #彈出舊的ebp,也就是把調(diào)用test函數(shù)的函數(shù)的棧的ebp彈出恢復(fù)梳杏。
ret # 彈出返回地址韧拒。這一條指令相當(dāng)于
pop %eip 將指令寄存器恢復(fù),也就是讓調(diào)用test函數(shù)的函數(shù)的棧知道接下來應(yīng)該繼續(xù)執(zhí)行的哪一條指令十性。
leave # 是將當(dāng)前棧的空間釋放掉叛溢,彈出舊的ebp,相當(dāng)于下面兩條匯編指令:
mov %ebp,%esp
pop %ebp
由此可見棧的釋放就是三個(gè)過程:
釋放當(dāng)前棧的空間
彈出舊的ebp
彈出返回地址

過程與esp的移動(dòng)結(jié)合:(有很多人不明白劲适,我這里已經(jīng)用自己的話寫的非常白話了楷掉,我覺得最后的理解方式是通過gdb調(diào)試一下,那里不明白就調(diào)試出來里面到底是什么就會(huì)自己豁然開朗)

棧釋放主要包括:1將當(dāng)前開放的椣际疲空間釋放掉烹植,通過esp的向上移動(dòng)斑鸦,移動(dòng)到自己的棧底ebp處(保存的舊的調(diào)用者的ebp的位置處),2恢復(fù)原來的現(xiàn)場(chǎng)草雕,主要包括兩部分巷屿,一部分是將原來的棧基址幀指針ebp復(fù)原墩虹,也就是在自己棧中保存的ebp彈出來嘱巾,這個(gè)時(shí)候esp自動(dòng)加4,變到原來保存舊ebp處位置上上面一個(gè)位置(一般為調(diào)用者的棧中保存的返回地址的地方诫钓,返回地址是調(diào)用當(dāng)前函數(shù)時(shí)浓冒,結(jié)束后回來繼續(xù)應(yīng)該執(zhí)行的下一條指令的eip的地址。比如call指令的下一條指令的eip的地址


比如說上面test中call getbuf這條eip的下一條eip的地址為0x8048e50
在執(zhí)行call指令的時(shí)候相當(dāng)于:
push eip(0x8048e50) (系統(tǒng)自動(dòng)將返回地址壓入棧尖坤,輸入調(diào)用者的一部分稳懒,比如這里在test的棧中,而getbuf的棧是從getbuf壓入test的ebp開始慢味,也就是getbuf的棧底元素是test的ebp)
jmp getbuf(0x8049262)
)场梆,這個(gè)時(shí)候保存的舊的ebp已經(jīng)彈出,之前為當(dāng)前棧生成的棿柯罚基址幀指針ebp也就沒有了已經(jīng)或油。也就是被調(diào)用函數(shù)開辟的棧已經(jīng)完全復(fù)原了,像什么沒有發(fā)生一樣驰唬。第二個(gè)部分也是最后一個(gè)部分顶岸,就是調(diào)用者需要知道我應(yīng)該繼續(xù)執(zhí)行那一條指令(不然回來了找不到原來的指令執(zhí)行到哪里了),也就是把返回地址eip的地址彈出來叫编,esp自動(dòng)加4指向原來保存返回地址的位置上面一個(gè)位置辖佣。這樣調(diào)用函數(shù)又繼續(xù)正常執(zhí)行了。

圖解函數(shù)調(diào)用過程:
1首先是test函數(shù)的棧結(jié)構(gòu)搓逾,其中黃色是test函數(shù)的棧卷谈,綠色是調(diào)用test函數(shù)的函數(shù)的棧,比如main函數(shù)之類的霞篡。


2 test執(zhí)行到call指令:
call 8049262 <getbuf>
首先 系統(tǒng)自動(dòng)壓入返回地址 push eip 這里call的下一條eip的地址是0x8048e50
然后 Jmp到j(luò)mp getbuf(0x8049262)
隨著返回地址的入棧世蔗,esp自動(dòng)下移,esp-4:這個(gè)時(shí)候仍是黃色的朗兵,因?yàn)槲覀冊(cè)谇懊嬉呀?jīng)分析過污淋,返回地址是屬于調(diào)用者的棧結(jié)構(gòu)的。


3跳到getbuf的函數(shù)的入口地址以后開始getbuf的棧余掖,藍(lán)色的代表getbuf的棧
push %ebp #保存舊的ebp的值寸爆,也就是保存當(dāng)前函數(shù)的調(diào)用者的棧的棧基址。對(duì)于getbuf來說就是test的ebp而昨。將ebp壓入棧中救氯,這個(gè)時(shí)候esp自動(dòng)-4,指向新壓入的ebp元素的位置處歌憨。
mov %esp,%ebp #使幀指針ebp指向當(dāng)前的esp處着憨,也就是初始化生成一個(gè)當(dāng)前棧getbuf棧的基址幀指針ebp,也就是當(dāng)前棧的棧底表示出來固定住务嫡。對(duì)于getbuf來說就是getbuf的棧的棧底甲抖。


4 getbuf繼續(xù)棧開辟
sub $0x38,%esp 通過esp移動(dòng)開辟一個(gè)getbuf的棧空間心铃,esp此時(shí)指向getb這個(gè)棧的棧頂准谚,此時(shí)getbuf的棧框已經(jīng)固定住去扣。


接下來再來看函數(shù)調(diào)用完以后返回到test函數(shù)柱衔,現(xiàn)場(chǎng)恢復(fù):
1leave的第一步:
mov %ebp,%esp #將ebp的值給esp,也就是把esp指向當(dāng)前的棧底愉棱,把開辟的藍(lán)色空間收回


2 leave的第二步:
pop %ebp #彈出舊的ebp唆铐,也就是把調(diào)用test函數(shù)的函數(shù)的棧的ebp彈出恢復(fù)。此時(shí)藍(lán)色框已經(jīng)完全沒有了奔滑,ebp也沒有了艾岂,為了getbuf開的空間也已經(jīng)完全釋放了。


3 ret 彈出返回地址以后:


這里以上僅是簡(jiǎn)單的函數(shù)調(diào)用朋其,調(diào)用的函數(shù)不需要傳入?yún)?shù)王浴,還有調(diào)用的函數(shù)需要傳入?yún)?shù)的時(shí)候等,在bufbomb中我們會(huì)具體遇到梅猿。再具體分析氓辣。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市粒没,隨后出現(xiàn)的幾起案子筛婉,更是在濱河造成了極大的恐慌簇爆,老刑警劉巖癞松,帶你破解...
    沈念sama閱讀 211,042評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異入蛆,居然都是意外死亡响蓉,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,996評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門哨毁,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枫甲,“玉大人,你說我怎么就攤上這事∠牖茫” “怎么了粱栖?”我有些...
    開封第一講書人閱讀 156,674評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)脏毯。 經(jīng)常有香客問我闹究,道長(zhǎng),這世上最難降的妖魔是什么食店? 我笑而不...
    開封第一講書人閱讀 56,340評(píng)論 1 283
  • 正文 為了忘掉前任渣淤,我火速辦了婚禮,結(jié)果婚禮上吉嫩,老公的妹妹穿的比我還像新娘价认。我一直安慰自己,他們只是感情好自娩,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,404評(píng)論 5 384
  • 文/花漫 我一把揭開白布用踩。 她就那樣靜靜地躺著,像睡著了一般忙迁。 火紅的嫁衣襯著肌膚如雪捶箱。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,749評(píng)論 1 289
  • 那天动漾,我揣著相機(jī)與錄音丁屎,去河邊找鬼。 笑死旱眯,一個(gè)胖子當(dāng)著我的面吹牛晨川,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播删豺,決...
    沈念sama閱讀 38,902評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開眼共虑,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了呀页?” 一聲冷哼從身側(cè)響起妈拌,我...
    開封第一講書人閱讀 37,662評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蓬蝶,沒想到半個(gè)月后尘分,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,110評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丸氛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年培愁,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片缓窜。...
    茶點(diǎn)故事閱讀 38,577評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡定续,死狀恐怖谍咆,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情私股,我是刑警寧澤摹察,帶...
    沈念sama閱讀 34,258評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站倡鲸,受9級(jí)特大地震影響港粱,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旦签,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,848評(píng)論 3 312
  • 文/蒙蒙 一查坪、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧宁炫,春花似錦偿曙、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,726評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至竿秆,卻和暖如春启摄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背幽钢。 一陣腳步聲響...
    開封第一講書人閱讀 31,952評(píng)論 1 264
  • 我被黑心中介騙來泰國(guó)打工歉备, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人匪燕。 一個(gè)月前我還...
    沈念sama閱讀 46,271評(píng)論 2 360
  • 正文 我出身青樓蕾羊,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親帽驯。 傳聞我的和親對(duì)象是個(gè)殘疾皇子龟再,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,452評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容