1.前言
很多時候我們可以使用Spy++檢視某個視窗的消息,但是有一定的局限性。
以編輯控件為例,我們打開Spy++截獲應用程式的EM_GETTEXTRANGE消息,卻隻能看到TEXTRANGE結構的指針值,看不到結構的内容。
如果想要詳細檢視消息的WPARAM和LPARAM參數,Spy++是無能為力的。
但是可以通過WinDBG的條件斷點卻可以輕松實作。
我們先從最簡單的WinDBG斷點開始,将斷點打在USER32!SendMessage函數上,就可以看到應用程式傳遞了什麼參數。
2.WinDBG斷點
首先,設定符号路徑(假設放在本地的目錄E:\symbols):
SRV*E:\symbols*http://msdl.microsoft.com/download/symbols
然後,将WinDBG調試器附加到目标程序并且中斷程式。
接着,就可以打斷點了。
bp USER32!SendMessageW
bp USER32!SendMessageA
打完斷點之後,繼續執行程式。
g
觸發應用程式發送Windows消息,例如可以将滑鼠移動到程式客戶區将發送WM_MouseMOVE消息。輸入以下指令,可以看到函數調用堆棧和傳入的參數。
kvn
dd esp
整體效果如下圖所示:
可以看到 'kvn' 指令輸出的 '00'行,第二個值 '0a09c81'是函數傳回位址,第三個值開始就是函數參數。結合SendMessage的定義可以知道‘0022065c’為視窗句柄,‘00000229’為消息值。
根據'dd esp'輸出結果,可以看到,esp+4開始從左到右依次就是SendMessage的4個參數
現在萬事具備,如何加上條件呢?
3.WinDBG條件斷點
我們先來最簡單的。在斷點命中時,輸出一句'Hello SendMessage'
重新定義斷點:
bp USER32!SendMessageW " .printf \"Hello SendMessage\t\" "
這樣定義斷點的意義就是,斷點命中時,執行後面的WinDBG腳本。怎麼樣?是不是超簡單。
運作程式:
g
觸發應用程式發送Windows消息之後,可以得到以下結果:
可以看到,确實輸出了'Hello SendMessage’,并且執行中斷在了'User32!SendMessageW'。
接着,我們來嘗試篩選消息EM_GETTEXTRANGE。由2可以,esp+4就是視窗句柄,esp+8就是消息值。
重新定義斷點:
bp USER32!SendMessageW ".if(poi(esp+8) == 0x44B) {.printf \"EM_GETTEXTRANGE\n\"} .else {gc}"
腳本的意義是,執行一個if-else語句。當消息值為EM_GETTEXTRANGE時,列印文本,否則從斷點繼續執行。具體來講,poi的含義跟C/C++的解引用是類似的。
執行程式:
g
觸發應用程式發送EM_GETTEXTRANGE消息,可得到結果如下:
可以看到,指定的文本确實輸出了,程式也中斷了。說明應用程式确實發送了EM_GETTEXTRANGE消息。那麼怎麼檢視這條消息的參數呢?
如果想要更複雜的功能,我們通常就會使用腳本檔案來達到這個目的了,誰也不想在一行上寫完所有代碼邏輯。WinDBG裡也是支援這種功能的,我們可以指定命中斷點時,執行指定的腳本檔案。
中斷程式,重新定義斷點,假設腳本檔案在'D:\script.txt':
bp USER32!SendMessageW "$$>< D:\script.txt"
再次繼續執行程式
g
觸發應用程式發送EM_GETTEXTRANGE後,可以得到如下執行結果:
可以看到,我們輸出了更多的資訊,把 EM_GETTEXTRANGE的LPARAM參數指向的TEXTRANGE結構都列印出來了。下面給出腳本。
$$ put MessageID into presudo register t0
r $t0 = poi(esp + 8)
$$ put pointer to TEXTRANGE Structure into presudo register t1
r $t1 = poi(esp + 0x10)
.if($t0 == 0x44B) {
.printf "\nEM_GETTEXTRANGE\n"
.printf "TEXTRANGE Structure:\nchrg.cpMin = %d\nchrg.cpMax = %d\nlpstrText = 0x%x\n", poi($t1), poi($t1 + 4), poi($t1 + 8)
gu
du poi($t1 +8)
.printf "\n"
gc
} .else {
gc
}
其中:
'$$'開始的行是注釋
r $t0 = poi(esp + 8)則是定義了僞寄存器
當我們得到指定消息時,先列印參數情況,然後調用gu指令讓SendMessageW繼續執行後傳回,這樣我們就可以得到正确的結果。就儲存在TEXTRANGE結構的lpstrText裡。
怎麼樣,是不是非常簡單。5min立馬就學會了WinDBG條件斷點。