利用反汇编手段解析C语言函数
利用反匯編手段解析C語言函數(shù)
?
通過在 Visual C++6.0 下反匯編一個 32 位 C語言程序的部分代碼來解析解釋函數(shù)調(diào)用的具體過程。
函數(shù)調(diào)用過程
函數(shù)調(diào)用過程主要由參數(shù)傳遞、地址跳轉(zhuǎn)、局部變量分配和賦初值、執(zhí)行函數(shù)體,結(jié)果返回等幾個步驟組成。
參數(shù)傳遞及函數(shù)跳轉(zhuǎn)
參數(shù)由實參傳遞給形參。在底層實現(xiàn)上,即是實參按照函數(shù)調(diào)用規(guī)定壓入堆棧。參數(shù)傳遞完成后就通過CALL指令由當前程序跳轉(zhuǎn)到子程序處。
局部變量分配并賦值
函 數(shù)的“{”被認為是分配局部變量空間的時機。在匯編層面局部變量分配體現(xiàn)為堆棧中以 EBP 寄存器為基址向低地址端分配的一個連續(xù)區(qū)域,通過 EBP 寄存器的相對尋址方式來尋址函數(shù)內(nèi)的局部變量。由于堆棧增長的方向是高地址端到低地址端,因此函數(shù)中先定義的局部變量地址較大,后定義的變量地址逐漸變小,相鄰定義的變量其地址一定相鄰。由于全局數(shù)據(jù)和局部數(shù)據(jù)定義在不用的數(shù)據(jù)區(qū)而并不與局部變量相鄰,根據(jù)程序局部性原理,相鄰的數(shù)據(jù)會被緩存,因此對相同的運算,局部變量作為操作數(shù)的運算效率就可能高于有全局變量參與的運算。同時,局部變量分配和回收只需要移動堆棧指針ESP,因此效率最高。
尋址函數(shù)的參數(shù)
參數(shù)存放在以 EBP 為基址的高地址端。對參數(shù)的訪問同樣是通過EBP 寄存器相對尋址操作來實現(xiàn)。
執(zhí)行函數(shù)體內(nèi)的語句
函數(shù)內(nèi)和具體功能相關(guān)的語句被轉(zhuǎn)化成一系列匯編語句。
返回值
return 語句將返回值返回到主調(diào)函數(shù)。在底層,參數(shù)是通過 EAX 寄存器或 EDX 寄存器傳遞給主調(diào)函數(shù)。
返回主調(diào)函數(shù)
函數(shù)的“}”被解釋為函數(shù)體已經(jīng)執(zhí)行完。遇到“}”時,會將堆棧中的局部變量、程序中壓入堆棧的寄存器的值全部彈出,將之前 CALL指令執(zhí)行時壓入堆棧的函數(shù)返回地址彈到指令指針寄存器 EIP,從而返回到主調(diào)函數(shù)。
堆棧平衡
堆棧平衡指的是將函數(shù)調(diào)用前壓入堆棧的參數(shù)彈出堆棧,使堆棧恢復到其調(diào)用前的狀態(tài)。由于函數(shù)調(diào)用完成后,參數(shù)就是無用的數(shù)據(jù)了,因此需要將其移出堆棧。
在 C語言中不需要進行堆棧平衡。而在匯編層面上卻根據(jù)調(diào)用約定來確定由主調(diào)函數(shù)或是被調(diào)函數(shù)完成堆棧平衡。
?
棧幀
參數(shù)由主調(diào)函數(shù)壓入堆棧,CALL 指令將函數(shù)返回地址入棧。進入子函數(shù)后,需要保存 EBP 原值、分配局部變量空間、保存寄存器初始值。函數(shù)內(nèi)通過“EBP-位移量”方式訪問局部變量,通過“EBP+位移量”方式訪問參數(shù)。
每發(fā)生一次函數(shù)調(diào)用,就會在堆棧中建立一個棧幀,棧幀在函數(shù)調(diào)用后釋放。但是系統(tǒng)的堆棧資源有限,因此如果函數(shù)調(diào)用(如遞歸調(diào)用)層數(shù)過多,則可能發(fā)生堆棧溢出錯誤。
?
反匯編
從 Call 指令可見 fuction函數(shù)編譯后加了“_”修飾符。
在函數(shù)內(nèi),遇到“{”時分配局部空間,并用值“0xCCH”進行初始化。未在定義時初始化的局部變量其初值就與“0xCCH”相關(guān)。因此 int 類型變量由于占四個字節(jié),其初值為 - 858993460(0xCCCCC-CCCH);兩個連續(xù)的 0xCCH 對應漢字“燙”字,因此當
以字符形式顯示函數(shù)內(nèi)未初始化的變量時會顯示為“燙燙…”;指針類型變量就指向了地址為 0xCCCC-CCH 的內(nèi)存。由此在調(diào)試模式下能很容易發(fā)現(xiàn)未初始化的變量。
總結(jié)
以上是生活随笔為你收集整理的利用反汇编手段解析C语言函数的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 一些 Windows 命令行学习
- 下一篇: 栈帧学习