国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
利用反匯編手段解析C語言函數(shù)


【【技匠志】利用反匯編手段解析C語言函數(shù)】https://toutiao.com/group/6792908403560677900/?app=explore_article&timestamp=1588344767&req_id=202005012252460100140530921E55BDFA&group_id=6792908403560677900&tt_from=copy_link&utm_source=copy_link&utm_medium=toutiao_ios&utm_campaign=client_share 



1、問題的提出

函數(shù)是 C語言中的重要概念。利用好函數(shù)能夠充分利用系統(tǒng)庫的功能寫出模塊獨立、易于維護和修改的程序。函數(shù)并不是 C 語言獨有的概念,其他語言中的方法、過程等本質上都是函數(shù)。

2、解決方法

在《微機原理》 課程介紹了堆棧、匯編語言等必要的相關知識之后,通過在高級語言開發(fā)環(huán)境下反匯編C 語言程序代碼,使得學生通過分析匯編代碼來理解函數(shù)調用中的堆棧變化,可以在實踐中理解高級語言和低級語言的底層映射關系,理解函數(shù)調用的實質。本文通過在 Visual C 6.0 下反匯編一個 32 位 C語言程序的部分代碼來解析解釋函數(shù)調用的具體過程。

3、函數(shù)調用過程

函數(shù)調用過程主要由參數(shù)傳遞、地址跳轉、局部變量分配和賦初值、執(zhí)行函數(shù)體,結果返回等幾個步驟組成[1]。

3.1、參數(shù)傳遞及函數(shù)跳轉

參數(shù)由實參傳遞給形參。在底層實現(xiàn)上,即是實參按照函數(shù)調用規(guī)定壓入堆棧。參數(shù)傳遞完成后就通過CALL指令由當前程序跳轉到子程序處。

3.2、局部變量分配并賦值

函 數(shù)的'{'被認為是分配局部變量空間的時機。在匯編層面局部變量分配體現(xiàn)為堆棧中以 EBP 寄存器為基址向低地址端分配的一個連續(xù)區(qū)域,通過 EBP 寄存器的相對尋址方式來尋址函數(shù)內(nèi)的局部變量。由于堆棧增長的方向是高地址端到低地址端,因此函數(shù)中先定義的局部變量地址較大,后定義的變量地址逐漸變小,相鄰定義的變量其地址一定相鄰[2]。由于全局數(shù)據(jù)和局部數(shù)據(jù)定義在不用的數(shù)據(jù)區(qū)而并不與局部變量相鄰,根據(jù)程序局部性原理,相鄰的數(shù)據(jù)會被緩存,因此對相同的運算,局部變量作為操作數(shù)的運算效率就可能高于有全局變量參與的運算。同時,局部變量分配和回收只需要移動堆棧指針ESP,因此效率最高。

3.3、尋址函數(shù)的參數(shù)

參數(shù)存放在以 EBP 為基址的高地址端。對參數(shù)的訪問同樣是通過EBP 寄存器相對尋址操作來實現(xiàn)。

3.4、執(zhí)行函數(shù)體內(nèi)的語句

函數(shù)內(nèi)和具體功能相關的語句被轉化成一系列匯編語句。

3.5、返回值

return 語句將返回值返回到主調函數(shù)。在底層,參數(shù)是通過 EAX 寄存器或 EDX 寄存器傳遞給主調函數(shù)。

3.6、返回主調函數(shù)

函數(shù)的'}'被解釋為函數(shù)體已經(jīng)執(zhí)行完。遇到'}'時,會將堆棧中的局部變量、程序中壓入堆棧的寄存器的值全部彈出,將之前 CALL指令執(zhí)行時壓入堆棧的函數(shù)返回地址彈到指令指針寄存器 EIP,從而返回到主調函數(shù)。

3.7、堆棧平衡

堆棧平衡指的是將函數(shù)調用前壓入堆棧的參數(shù)彈出堆棧,使堆棧恢復到其調用前的狀態(tài)[3]。由于函數(shù)調用完成后,參數(shù)就是無用的數(shù)據(jù)了,因此需要將其移出堆棧。

在 C語言中不需要進行堆棧平衡。而在匯編層面上卻根據(jù)調用約定來確定由主調函數(shù)或是被調函數(shù)完成堆棧平衡。

C語言函數(shù)調用堆棧常見形式如圖 1 所示[4]:

參數(shù)由主調函數(shù)壓入堆棧,CALL 指令將函數(shù)返回地址入棧。進入子函數(shù)后,需要保存 EBP 原值、分配局部變量空間、保存寄存器初始值。函數(shù)內(nèi)通過'EBP-位移量'方式訪問局部變量,通過'EBP 位移量'方式訪問參數(shù)[5]。

每發(fā)生一次函數(shù)調用,就會在堆棧中建立一個棧幀,棧幀在函數(shù)調用后釋放。但是系統(tǒng)的堆棧資源有限,因此如果函數(shù)調用(如遞歸調用)層數(shù)過多,則可能發(fā)生堆棧溢出錯誤。

4.反匯編代碼分析

以下將函數(shù) function 的調用相關代碼在VisualC 6.0 Debug模式反匯編,通過對匯編代碼的分析揭示函數(shù)調用的關鍵點和細節(jié)。完整的 C語言程序代碼如圖 2 所示:

Function(i,&j)語句的反匯編代碼如圖 3 所示:

先 找到主函數(shù)中的局部變量 i,j(其在堆棧中位置為 EBP- 8和 EBP- 4),將其壓入堆棧。Visual C/C 的編譯器對 C 語言程序的默認函數(shù)約定為 _cdecl[6]。此參數(shù)入棧約定為自右向左,并且對函數(shù)名前加'_'修飾符。先將 j 的地址壓入堆棧,后將 i 的值壓入堆

棧。通過 call 指令調用函數(shù)。從 Call 指令可見 fuction函數(shù)編譯后加了'_'修飾符。Call 指令執(zhí)行時自動將函數(shù)的返回地址入棧,之后轉到 function 定義處開始執(zhí)行此函數(shù)。

對funciton函數(shù)的'{'的反匯編結果如圖 4 所示:

在函數(shù)內(nèi),遇到'{'時分配局部空間,并用值'0xCCH'進行初始化。未在定義時初始化的局部變量其初值就與'0xCCH'相關。因此 int 類型變量由于占四個字節(jié),其初值為 - 858993460(0xCCCCC-CCCH);兩個連續(xù)的 0xCCH 對應漢字'燙'字,因此當

以字符形式顯示函數(shù)內(nèi)未初始化的變量時會顯示為'燙燙…';指針類型變量就指向了地址為 0xCCCC-CCH 的內(nèi)存。由此在調試模式下能很容易發(fā)現(xiàn)未初始化的變量。

堆?;镜拇鎯挝粸樗淖止?jié),對于小于四字節(jié)的數(shù)據(jù)按四字節(jié)對齊方式分配空間。因此 char 類型變量 ch 雖然數(shù)據(jù)本身需要兩個字節(jié),也分配了四個字節(jié)空間。array 字節(jié)數(shù)組分配空間時每個字符占一個字節(jié),不夠四個字符時按四字節(jié)對齊存放。因此局部變量

空間總數(shù)為 40H 4 4×2 4=50H。局部變量 ch 的地址為 EBP- 4,a、b 的地址分別為 EBP- 8 ,EBP- 0CH,array數(shù)組的地址為 EBP- 10h。函數(shù)左括號右括號間的所有的語句反匯編結果如圖 5 所示:

若變量有初值,則反匯編就會為其生成一條 Mov指令為其賦值。對于沒有初值的變量其每個字節(jié)都為0xCCH。對于字符數(shù)組,情況稍微復雜一些。字符串常量'abc'被存放在全局數(shù)據(jù)區(qū)中。當需要引用其值對數(shù)組進行初始化時,實際是將全局數(shù)據(jù)拷貝到堆棧中的

局部數(shù)組 array里。由于寄存器是 32 位,每次最多只能賦值 4 個字符,因此對數(shù)組賦初值的語句反匯編后可能產(chǎn)生一至多條匯編語句。對數(shù)組內(nèi)容的訪通過[ 'EBP 數(shù)組首地址 偏移量]的寄存器間址來完成,因此局部數(shù)組初始化費時但訪問時的效率高。

在函數(shù)內(nèi)訪問局部變量和參數(shù)通過 [EBP 位移量 /- 位移量]來完成。函數(shù)返回值被放到 EAX 寄存器中供主調函數(shù)使用。

可見,在匯編層面上,函數(shù)內(nèi)部并不存儲局部變量,局部變量只有當函數(shù)調用發(fā)生時才會在棧上為函數(shù)分配空間。因此當函數(shù)調用后返回局部變量的值是錯誤的。

遇到函數(shù)'}'時的操作如圖 6 所示:

將寄存器 EDI、ESI、EBX 恢復原值;將 ESP 調回到 EBP 處;將 EBP原值彈出。此時 ESP 指向函數(shù)返回地址。執(zhí)行出棧指令,將函數(shù)的返回地址彈入 EIP 寄存器返回到主調函數(shù)。此時堆棧中只殘留有調用函數(shù)時壓入的參數(shù)還沒有清理。

主調函數(shù)中的堆棧平衡語句如圖 7 所示:

根據(jù) _cdecl 約定,需要由主調函數(shù)完成堆棧平衡。主調函數(shù)根據(jù)壓入堆棧的參數(shù)的數(shù)目 2 和參數(shù)大小,利用指令 add ESP,8 將參數(shù)全部彈出。此時堆棧就恢復到其調用前的狀態(tài)。一個完整的函數(shù)調用過程完成。

本站僅提供存儲服務,所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
通過一段匯編,加深對寄存器ESP和EBP的理解
C語言函數(shù)調用棧(一)
[C/C++] 函數(shù)調用的棧分配
C/C++ 中的函數(shù)參數(shù)傳遞機制
一起學習計算機第0012篇【UEFI中64位匯編的常識】
【新提醒】[教程]逆向反匯編第二課
更多類似文章 >>
生活服務
分享 收藏 導長圖 關注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服