https://www.52pojie.cn/thread-664189-1-1.html 無論是分析程式崩潰原因,還是解決程式hang問題,我們最常檢視的就是程式調用堆棧。學會windbg調用堆棧指令,以及了解堆棧中的各個參數的意義就顯得至關重要。上圖就是一個典型的Windbg堆棧,如果不了解ChildEBP、RetAddr、Args to Child等參數意義,以及它們之間的來龍去脈,調試工作将很難進行下去。![]()
Windbg檢視調用堆棧(k*) 1. 函數參數 2. Windbg堆棧指令 3. 執行個體分析
函數的參數傳遞有二種方式:堆棧方式、寄存器方式。如果是堆棧方式傳遞的,就需要定義參數在堆棧中的傳遞順序,并約定函數被調用之後,由誰來平衡堆棧;如果是寄存器方式傳遞的,就需要确定參數存放在哪個寄存器中。每一種方式都有其優缺點,而且與使用的程式設計語言有關系,不存在哪種方式好與壞。
如Visual Studio中的C++工程,可以C++ --> 進階 --> 調用約定中進行設定:
常用的調用約定類型有__cdecl、stdcall、PASCAL、fastcall。除了fastcall可以支援以寄存器的方式來傳遞函數參數外,其他的都是通過堆棧的方式來傳遞函數參數的。
堆棧是一種“後進先出”的資料結構,ESP寄存器始終指向棧頂。棧中資料位址從底部到頂部依次減小,也就是說,棧底對應高位址,棧頂對應低位址。
調用函數時,調用者依次把參數壓棧,然後調用函數,函數被調用之後,在堆棧中取得參數資料。函數調用結束以後,堆棧需要恢複到函數調用之前的樣子,具體由調用者來恢複還是由函數自身來恢複,根據不同的調用約定類型采用不同的方式。
約定類型
__cdecl
stdcall
PASCAL
fastcall
參數傳遞順序
從右到左
從左到右
使用寄存器
平衡堆棧者
調用者
函數自身
cdcel是C/C++/MFC程式預設的調用約定。
stdcall是Win32中絕大多數 API函數的約定方式,也有少部分使用cdcel約定方式,如wsprintf等。
在windows C/C++開發中常用的就是__cdecl和stdcall這2種調用約定。
假設調用函數<code>int add(int a, int b)</code>, 按照不同的調用約定來調用它。從調用者的視角來看,其彙編代碼分别表示如下:
在函數調用過程中,參數入棧的過程:
上圖中,EBP和函數傳回位址都是位址,在32位程式中位址占4個位元組。在函數的一次調用過程中EBP是不會變化的,函數調用完之後會将EBP恢複為暫存在堆棧中的原EBP值。是以,通過EBP可以擷取函數各個參數的值:
參數a = EBP + 0x8
參數b = EBP + 0xC
參數:
Thread 指定顯示哪個線程的調用堆棧。如果省略該參數,則顯示目前線程的調用堆棧。*顯示所有線程的調用堆棧。
b 顯示每個函數的前3個參數。
p 顯示每個函數的所有參數。參數清單包括每個參數的類型、名稱、值。
如上圖,可以看到函數的每個參數的類型,名稱,值。但是這個需要有對應的符号檔案(pdb),沒有應用程式的符号檔案隻能顯示系統API的參數資訊。
P 類似p。不同之處在于,每個參數顯示在單獨的行上面。
n 顯示調用堆棧中每幀的序号(一般稱棧幀,如棧幀3)。
FrameCount 指定顯示調用堆棧的幀數,即調用堆棧的深度。預設為16進制格式。預設幀數為0x14=20
調用堆棧顯示出來之後,如果想知道調用某幀時的相關資訊,可以使用<code>.frame</code> 來切換指定幀,然後就可以使用如dv指令顯示局部變量等。
/c
/r 顯示執行該幀時寄存器的值。
FrameNumber 指定要切換到的幀号。
<code>kbn</code> 顯示堆棧資訊:
棧幀12:
調用add函數,參數1=00000001,參數2=000000002,EBP=0015fc0c
根據圖1得知,函數傳回位址=EBP+4,我們使用dw指令來驗證。
參考: 《軟體調試》張銀奎 著 《格蠹彙編》張銀奎 著 《加密與解密》第三版 段剛編著
怎麼删除?