OD中如何下消息斷點--by icefisher


【文章作者】: icefisher
【作者郵箱】: 181712814@qq.com
【軟件下載】: 
【軟件名稱】: echap518.exe(只是供學習的crackme)
【加殼方式】: 里面直接有個unpacked.ExE,是脫過殼的見【原創】我也來談談消息斷點二
【保護方式】: 
【使用工具】: OllyICE
【文章日期】: 20080813

-----------------------------------------------------------------------
   第一篇原創希望大家支持下,首先我想和我一樣菜的好多新人,一定都看過了論壇上的那個ollydbg教程,其中的消息斷點真是讓人難以理解,痛苦不堪啊,那么今天我就講講我自己的體會吧,希望望大家共勉。

  首先,我覺得我們應該先了解消息,什么是消息,而談到消息,就不能不說到windows程序設計的結構(大家放心。。。我大概講下,不是什么重點)。
  如下,這是一個典型windows程序結構,其中很多細節地方我都略去了,

  1 /*------------------------------------------------------------------------
  2   HELLOWIN.C -- Displays "Hello, Windows 98!" in client area
  3         
  4                  (c) Charles Petzold, 1998
  5         
  6 -----------------------------------------------------------------------*/
  7         
  8 #include <windows.h>
  9     LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;
 10         
 11 
 12 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)
 13         
 14 {
 15         
 16     static TCHAR szAppName[] = TEXT ("HelloWin") ;
 17         
 18     HWND   hwnd ;
 19         
 20     MSG    msg ;
 21     //前面都是變量定義,不關注。
 22         
 23     WNDCLASwndclass ;
 24         
 25 
 26     wndclass.style        = CS_HREDRAW | CS_VREDRAW ;
 27         
 28     wndclass.lpfnWndProc  = WndProc ;  //關鍵句,指出消息的處理函數所在位置
 29         
 30     wndclass.cbClsExtra   = 0 ;
 31         
 32     wndclass.cbWndExtra   = 0 ;
 33         
 34     wndclass.hInstance    = hInstance ;
 35         
 36     wndclass.hIcon        = LoadIcon (NULL, IDI_APPLICATION) ;
 37         
 38     wndclass.hCursor      = LoadCursor (NULL, IDC_ARROW) ;
 39         
 40     wndclass.hbrBackground= (HBRUSH) GetStockObject (WHITE_BRUSH) ;
 41         
 42     wndclass.lpszMenuNam  = NULL ;
 43         
 44     wndclass.lpszClassName= szAppName ;
 45         
 46     //這一連串的wndclass是在定義一類窗口的屬性,形象地說就是在定義一個模子,然后后面可以用這個模子去建立更多的窗口,其中這個模子中我們需要注意的就是紅字的  wndclass.lpfnWndProc  = WndProc ;,他指出了這個模子的消息處理函數是哪個?也就是說這個窗口內發生的一切事件,比如說點擊,雙擊,鼠標移動,按鍵,按下按鈕這一切都會生消息,而系統會自動調用WndProc去處理這些問題。*/
 47     if (!RegisterClass (&wndclass))
 48         
 49     {
 50         
 51             MessageBox (  NULL, TEXT ("This program requires Windows NT!"),
 52         
 53                                   szAppName, MB_ICONERROR) ;
 54         
 55             return 0 ;
 56         
 57     }
 58         //上面的是很簡單的一個注冊模子,你開始定義了這個模子wndclass,那你得讓系統知道啊,這部分就是這個功能,不須太關注。
 59     hwnd = CreateWindow( szAppName,      // window class name
 60         
 61                    TEXT ("The Hello Program"),   // window caption
 62         
 63                    WS_OVERLAPPEDWINDOW,  // window style
 64         
 65                    CW_USEDEFAULT,// initial x position
 66         
 67                    CW_USEDEFAULT,// initial y position
 68         
 69                    CW_USEDEFAULT,// initial x size
 70         
 71                    CW_USEDEFAULT,// initial y size
 72         
 73                    NULL,                 // parent window handle
 74         
 75                    NULL,            // window menu handle
 76         
 77                    hInstance,   // program instance handle
 78         
 79                    NULL) ;      // creation parameters
 80         
 81    //注意上面便是利用這個模子,再加上一些自己獨有的特點建立了一個窗口,大家不需關注
 82         
 83     ShowWindow (hwnd, iCmdShow) ;
 84         
 85     UpdateWindow (hwnd) ;
 86         
 87         
 88    while (GetMessage (&msg, NULL, 0, 0))
 89         
 90     {
 91         
 92             TranslateMessage (&msg) ;
 93         
 94             DispatchMessage (&msg) ;
 95         
 96     }
 97         //上面這個需要關注,前面提到過,如果窗口產生了消息我們需要調用WndProc來處理,那么之前我們需要上面的哪個while循環先處理下,這個現在我們也不需要了解。
 98     return msg.wParam ;
 99         
100 }
101         
102 
103 LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)        
104 {
105         
106     HDC                   hdc ;
107         
108     PAINTSTRUCT ps ;
109         
110     RECT          rect ;
111         
112         //重點來了,大家注意當我們到了WndProc這個消息處理函數中時,我們會不自然地想到:那么多種的消息,系統如何分辨是那個呢,這是我們就要注意到UINT message,他說明了消息的種類,而WPARAM,LPARAM都是消息具體的參數,大家這時看下面,因為message表示的消息不同,系統使用了switch來選擇對應的處理程序,這里要注意WM_CREATE:像這些WM_開頭的都是消息,而實質上都是數字,不過是頭文件定義了一些等價字符串而已。
113     switch (message)
114         
115     {
116         
117     case WM_CREATE:
118         
119     PlaySound (TEXT ("hellowin.wav"), NULL, SND_FILENAME | SND_ASYNC) ;
120         
121             return 0 ;
122 
123     case   WM_PAINT:
124         
125             hdc = BeginPaint (hwnd, &ps) ;
126         
127             GetClientRect (hwnd, &rect) ;
128 
129    DrawText (hdc, TEXT ("Hello, Windows 98!"), -1, &rect,
130         
131                    DT_SINGLELINE | DT_CENTER | DT_VCENTER) ;
132         
133                  EndPaint (hwnd, &ps) ;
134         
135                    return 0 ;
136         
137    case   WM_DESTROY:
138         
139             PostQuitMessage (0) ;
140         
141             return 0 ;
142     } 
143   return DefWindowProc (hwnd, message, wParam, lParam) ;    
144 }

Ok,大家是不是覺得很抽象,大家只要把我的注釋看下,大概了解這是干嘛就可以了,其實為了理解消息,只需要注意我紅字標出的部分,wndclass.lpfnWndProc  = WndProc ;這個就是我們的重點,他指出了這類windows窗口的消息處理交給了那個函數。然后重點就是CALLBACK,里面根據不同的消息轉到不同的處理地方。


而大家在crackme中廣為使用的則是對話框,比窗口實現方便些,他調用

1 DialogBox (    hInstance,
2                TEXT("AboutBox"),
3                hwnd,
4                AboutDlgProc
5            )

 

來實現,其中最后一個參數即為消息處理函數,等同於上面所說的WndProc

===========================================================================

好了當我們大概理解消息處理函數后我們就可以來看看這個例子了,首先ollyice載入unpacked.exe。F8單步運行。
此圖已經縮小,點擊察看原圖。
如圖地方F7,進入后F8,
此圖已經縮小,點擊察看原圖。
如圖地方F7,進入后可以看到F8幾步就可以看到
此圖已經縮小,點擊察看原圖。
回想起上篇我提到過的DialogBox (
hInstance,
TEXT("AboutBox"),
hwnd,
AboutDlgProc
)

因為DialogBoxParamA比DialogBox 最后多一個參數用來做記錄,不影響我們理解,
(當然我們也可以用Ctrl+N查找函數DialogBoxParamA來直接定位到這里
名稱:  2.jpg&#13;&#10;查看次數: 257&#13;&#10;文件大小:  29.5 KB


我們看到DLGProc=004015A1,那么我們明顯可以理解4015A1處是消息處理函數所在。我們Ctrl+G跟過去看,此圖已經縮小,點擊察看原圖。

我們會看到cmp eax,110 或者cmp eax,111之類的比較,
此圖已經縮小,點擊察看原圖。
回想起上篇,這就等同於
switch (message)
        
    {
        
    case WM_CREATE:
        
  

    case   WM_PAINT:
        
           
        
    case   WM_DESTROY:

}

而其中我們需要知道的是WM_COMMAD =111(用來定位按鈕的消息) 
WM_LBUTONUP =202(鼠標左鍵放開)
而且我們還要注意一個地方回想上次我提到的
WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
當我們產生一個消息時,必然是調用這個函數,那么根據windows函數調用進棧法則,我們不難得到在消息處理函數開頭如果下斷點,棧結果必然如此
{
返回地址
hwnd
message
wParam
lParam
}

好了,基礎講完,就再看程序(因為前面push ebp,所以后面在取message時,為ebp+C,大家應該能明白吧),好了我們先F9運行次程序,在查看->窗口明顯我們可以看到Check的id值為1。
名稱:  18.jpg&#13;&#10;查看次數: 256&#13;&#10;文件大小:  41.1 KB
     現在我們來仔細看看這個消息處理函數,他首先從ebp+C中取出了message,存入了eax中,然后開始switch的過程,他不斷比較這些以確定是哪個消息,
     好了,我們知道按下按鈕會產生WM_COMMAD(111) 消息,那么當我們看到cmp eax,111,je跳走時,我們離目標已經很近了,跟蹤je到目的地,我們會奇怪,怎么還比較啊,這是因為按鈕有很多個,每一個按下都會產生WM_COMMAD(111),那么這時我們需要再次判斷是哪個按鈕?
此圖已經縮小,點擊察看原圖。

我們利用的就是wParam的低四位,他記錄了按下按鈕的ID值,所以就有了movz eax,
[ebp+10],好了我們已經知道了Check的ID值為1,那么我們看到
cmp eax,1 
je xxxxxxxx
跟過去下斷點,這時我們就完成了對check的斷點,只要一按check必然會來到此處,后續的也會從這里開始,一切就會光明無比








方法二 
當我們面對一個很龐雜的系統時我們又該如何來找那關鍵的消息處理函數呢?茫茫多的程序中又如何去發現
cmp eax,111 與cmp eax,1呢
回到前題,我覺得消息處理函數無論他在那里,當他被調用時,棧中的內容必然是
{
返回地址
hwnd
message
wParam
lParam
}只要我們能抓住他時,我覺得我們就能抓住一切。

首先當我們無法找到消息處理函數時,也許代碼太多我們遺漏了,也許有別的技巧可以隱藏。但是我們可以先F9運行起來,在查看->窗口中,我們選擇他們的共有父窗口,點擊跟隨ClassProc
此圖已經縮小,點擊察看原圖。
然后我們進入了系統領空,然后在第一句上下條件斷點:
[ESP+8]==WM_COMMAND&&[ESP+c]==1
名稱:  11.jpg&#13;&#10;查看次數: 252&#13;&#10;文件大小:  17.8 KB
然后我們在對話框中輸入數據,點擊check,我們發現我們會中斷在系統領空,並且注意觀察棧
名稱:  13.jpg&#13;&#10;查看次數: 254&#13;&#10;文件大小:  44.9 KB
名稱:  10.jpg&#13;&#10;查看次數: 254&#13;&#10;文件大小:  21.2 KB
大家都明白了吧,然后在查看->內存,代碼段下內存訪問斷點,F9運行下,直接到達消息處理函數
名稱:  14.jpg&#13;&#10;查看次數: 255&#13;&#10;文件大小:  37.7 KB
這時我們這需要靜靜的F8一路跟蹤就可以了

 

 

個人總結,記住[ESP+8]==WM_COMMAND&&[ESP+c]==按鈕ID


免責聲明!

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



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