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