Windbg查看調用堆棧(k*)


        無論是分析程序崩潰原因,還是解決程序hang問題,我們最常查看的就是程序調用堆棧。學會windbg調用堆棧命令,以及理解堆棧中的各個參數的意義就顯得至關重要。

上圖就是一個典型的Windbg堆棧,如果不理解ChildEBP、RetAddr、Args to Child等參數意義,以及它們之間的來龍去脈,調試工作將很難進行下去。

1. 函數參數

        函數的參數傳遞有二種方式:堆棧方式、寄存器方式。如果是堆棧方式傳遞的,就需要定義參數在堆棧中的傳遞順序,並約定函數被調用之后,由誰來平衡堆棧;如果是寄存器方式傳遞的,就需要確定參數存放在哪個寄存器中。每一種方式都有其優缺點,而且與使用的編程語言有關系,不存在哪種方式好與壞。

如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種調用約定。
假設調用函數int add(int a, int b), 按照不同的調用約定來調用它。從調用者的視角來看,其匯編代碼分別表示如下:

__cdecl

push b     ;參數按從右到左傳遞
push a
call add
add esp, 8 ;調用者在函數外部平衡堆棧

stdcall

push b     ;參數按從右到左傳遞
push a
call add   ;函數自己內部平衡堆棧

在函數調用過程中,參數入棧的過程:

上圖中,EBP和函數返回地址都是地址,在32位程序中地址占4個字節。在函數的一次調用過程中EBP是不會變化的,函數調用完之后會將EBP恢復為暫存在堆棧中的原EBP值。所以,通過EBP可以獲取函數各個參數的值:
參數a = EBP + 0x8
參數b = EBP + 0xC

2. Windbg堆棧命令

2.1 顯示堆棧信息k*

[~Thread] k[b|p|P|v] [c] [n] [f] [L] [M] [FrameCount]
[~Thread] k[b|p|P|v] [c] [n] [f] [L] [M] = BasePtr [FrameCount]
[~Thread] k[b|p|P|v] [c] [n] [f] [L] [M] = BasePtr StackPtr InstructionPtr
[~Thread] kd [WordCount]

參數:
Thread  指定顯示哪個線程的調用堆棧。如果省略該參數,則顯示當前線程的調用堆棧。*顯示所有線程的調用堆棧。

b  顯示每個函數的前3個參數。

p  顯示每個函數的所有參數。參數列表包括每個參數的類型、名稱、值。

        如上圖,可以看到函數的每個參數的類型,名稱,值。但是這個需要有對應的符號文件(pdb),沒有應用程序的符號文件只能顯示系統API的參數信息。

P  類似p。不同之處在於,每個參數顯示在單獨的行上面。

n  顯示調用堆棧中每幀的序號(一般稱棧幀,如棧幀3)。

FrameCount  指定顯示調用堆棧的幀數,即調用堆棧的深度。默認為16進制格式。默認幀數為0x14=20

2.2 切換到指定幀信息.frame

        調用堆棧顯示出來之后,如果想知道調用某幀時的相關信息,可以使用.frame 來切換指定幀,然后就可以使用如dv命令顯示局部變量等。

.frame [/c] [/r] [FrameNumber] 

/c

/r  顯示執行該幀時寄存器的值。

FrameNumber  指定要切換到的幀號。

3. 實例分析

kbn 顯示堆棧信息:

棧幀12
調用add函數,參數1=00000001,參數2=000000002,EBP=0015fc0c
根據圖1得知,函數返回地址=EBP+4,我們使用dw命令來驗證。

參考:
《軟件調試》張銀奎 著
《格蠹匯編》張銀奎 著
《加密與解密》第三版 段剛編著


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM