In the debugger program OllyDbg, How do I set a breakpoint when the left mouse button is pressed? It doesn't matter what it clicks on, so upon mouse click, the breakpoint stops the debugger.
2 Answers
All messages in a gui application passes through the Application Defined Callback WinProc whose prototype is
LRESULT CALLBACK WindowProc(
_In_ HWND hwnd,
_In_ UINT uMsg,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
so when you have breakpointed on a wndproc
esp -> return Address
esp+4 -> hwnd
esp+8 -> uMsg
.....
** MSDN Doc For List of messages**
to know a windoproc or class proc use alt+w shortcut in ollydbg (opens a list of windows ) right click to open the context menu and follow Either Wndproc or ClassProc for the appropriate window of choice
hit shift+f4 and set a log breakpoint that never pauses and set the function type to be WndProc (Assume Function Of Type DropDown)
and run the app
go to log window and observe you will see a lot of logs like this
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00010236 hWnd = 00010236, class = CalcFrame, text = Calculator
00000210 Msg = WM_PARENTNOTIFY
00000204 Event = WM_RBUTTONDOWN, ID = 0
00230006 Data = 230006
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00030248 hWnd = 00030248, class = CalcFrame
00000021 Msg = WM_MOUSEACTIVATE
00010236 hParent = 00010236, class = CalcFrame, text = Calculator
02040001 Hittest = HTCLIENT, MouseMsg = WM_RBUTTONDOWN
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00010236 hWnd = 00010236, class = CalcFrame, text = Calculator
00000021 Msg = WM_MOUSEACTIVATE
00010236 hParent = 00010236, class = CalcFrame, text = Calculator
02040001 Hittest = HTCLIENT, MouseMsg = WM_RBUTTONDOWN
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00030248 hWnd = 00030248, class = CalcFrame
00000020 Msg = WM_SETCURSOR
00030248 hWnd = 00030248, class = CalcFrame
02040001 Hittest = HTCLIENT, MouseMsg = WM_RBUTTONDOWN
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00010236 hWnd = 00010236, class = CalcFrame, text = Calculator
00000020 Msg = WM_SETCURSOR
00030248 hWnd = 00030248, class = CalcFrame
02040001 Hittest = HTCLIENT, MouseMsg = WM_RBUTTONDOWN
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00030248 hWnd = 00030248, class = CalcFrame
00000204 Msg = WM_RBUTTONDOWN
00000002 Keys = MK_RBUTTON
00230006 X = 6, Y = 35.
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00030248 hWnd = 00030248, class = CalcFrame
00000084 Msg = WM_NCHITTEST
00000000 wParam = 0
01790207 X = 519., Y = 377.
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00030248 hWnd = 00030248, class = CalcFrame
00000020 Msg = WM_SETCURSOR
00030248 hWnd = 00030248, class = CalcFrame
02050001 Hittest = HTCLIENT, MouseMsg = WM_RBUTTONUP
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00010236 hWnd = 00010236, class = CalcFrame, text = Calculator
00000020 Msg = WM_SETCURSOR
00030248 hWnd = 00030248, class = CalcFrame
02050001 Hittest = HTCLIENT, MouseMsg = WM_RBUTTONUP
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00030248 hWnd = 00030248, class = CalcFrame
00000205 Msg = WM_RBUTTONUP
now refine the breakpoint to suit your condition
(change from never to on condition
add condition like when uMsg == WM_LBUTTONDOWN ie
[esp+8] == 0x20x..20y (see the stack layout mention earlier
0x200 t0 0x220 are WM_MOUSE EVENT MESSAGES
here is screenshot that shows a possible configuration and result below screen shot
00551EDE INT3: [esp+8] = WM_MOUSEMOVE
00551EDE INT3: [esp+8] = WM_NCHITTEST
00551EDE INT3: [esp+8] = WM_PARENTNOTIFY
00551EDE INT3: [esp+8] = WM_MOUSEACTIVATE
00551EDE INT3: [esp+8] = WM_MOUSEACTIVATE
00551EDE INT3: [esp+8] = WM_SETCURSOR
00551EDE INT3: [esp+8] = WM_SETCURSOR
00551EDE INT3: [esp+8] = WM_LBUTTONDOWN
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00030248 hWnd = 00030248, class = CalcFrame
00000201 Msg = WM_LBUTTONDOWN
00000001 Keys = MK_LBUTTON
00350004 X = 4, Y = 53.
00551EDE INT3: [esp+8] = WM_NCHITTEST
00551EDE INT3: [esp+8] = WM_SETCURSOR
00551EDE INT3: [esp+8] = WM_SETCURSOR
00551EDE INT3: [esp+8] = WM_LBUTTONUP
00551EDE INT3: [esp+8] = WM_NCHITTEST
00551EDE INT3: [esp+8] = WM_PARENTNOTIFY
00551EDE INT3: [esp+8] = WM_MOUSEACTIVATE
00551EDE INT3: [esp+8] = WM_MOUSEACTIVATE
00551EDE INT3: [esp+8] = WM_SETCURSOR
00551EDE INT3: [esp+8] = WM_SETCURSOR
00551EDE INT3: [esp+8] = WM_RBUTTONDOWN
00551EDE Call to CALC.WndProc from USER32.77B4C4E4
00030248 hWnd = 00030248, class = CalcFrame
00000204 Msg = WM_RBUTTONDOWN
00000002 Keys = MK_RBUTTON
00350004 X = 4, Y = 53.
00551EDE INT3: [esp+8] = WM_NCHITTEST
00551EDE INT3: [esp+8] = WM_SETCURSOR
00551EDE INT3: [esp+8] = WM_SETCURSOR
00551EDE INT3: [esp+8] = WM_RBUTTONUP
Regardless of operating system, a mouse click represents an event and there is a bunch of event handling plumbing that makes this happen. Some of this can hinge upon certain design choices like how processes are separated in the GUI.
A common pattern is to register a context relative to which events can be processed through an implemented handler. Traditionally under Windows, this is a "Window Class" and practically everything is a window. The definition of that window class includes a function/method that handles the events/messages sent to the target window. To target a specific window with a debugger, you would want to break on a condition where the message/event handling function is called with the event you want (like WM_LBUTTONDOWN
on Windows). There are cases where default handling of events can occur as well, a la DefWindowProc()
.
Doing this in a broader context would require hooking that is facilitated by the operating system, perhaps at the kernel level. There may be other options for you available through Hooks.