转自:http://bbs.pediy.com/showthread.php?t=180556&highlight=windbg
以鼠标左键按下消息为例, 用WinDbg来捕获.
对于Win7X64下的计算器程序, 用Spy++监视单独一个按钮的消息(e.g. 清除按钮C), 当排除无关消息后.
可以看到按钮按下的消息是 WM_LBUTTONDOWN
代码:
<00001> 00020314 P WM_LBUTTONDOWN fwKeys:MK_LBUTTON xPos:14 yPos:10 <00002> 00020314 S WM_SETFOCUS hwndLoseFocus:0009047E <00003> 00020314 R WM_SETFOCUS <00004> 00020314 S BM_SETSTATE fState:True <00005> 00020314 R BM_SETSTATE <00006> 00020314 P WM_LBUTTONUP fwKeys:0000 xPos:14 yPos:10 <00007> 00020314 S BM_SETSTATE fState:False <00008> 00020314 R BM_SETSTATE <00009> 00020314 S WM_CAPTURECHANGED hwndNewCapture:00000000 <00010> 00020314 R WM_CAPTURECHANGED <00011> 00020314 S WM_KILLFOCUS hwndGetFocus:000B048E <00012> 00020314 R WM_KILLFOCUS
代码:
bp USER32!TranslateMessage "$$>< d:\\windbg-script.txt"
x64程序的区别: 进入目标API后, MSG * 入参在rcx中
代码:
$$ /// @file d:\\windbg-script.txt $$ Windbg脚本 $$ 试验目的: 用WinDbg设置一个断点, 在断点条件发生时, 执行一个WinDbg脚本 $$ e.g. bp USER32!TranslateMessage "$$>< d:\\windbg-script.txt" $$ 试验环境: win7X64Sp1 + WinDbg 6.12.0002.633 $$ 试验步骤: $$ * bc * $$ * bp USER32!TranslateMessage "$$>< d:\\windbg-script.txt" $$ * 当断点触发后, 自动调用 d:\windbg-script.txt $$ 只有符合脚本中约定的条件时,才会停下. 否则自动继续执行 $$ e.g. 例如只有 WM_LBUTTONDOWN 发生时, WinDbg才会停下来 $$ @note $$ 当断点触发后, 进入USER32!TranslateMessage, $$ 参考此API的反汇编, 可以看到 MSG * 入参在rcx中 $$ 0:000> uf USER32!TranslateMessage $$ USER32!TranslateMessage: $$ 00000000`775996f0 fff3 push rbx $$ 00000000`775996f2 4883ec20 sub rsp,20h $$ 00000000`775996f6 b8e5000000 mov eax,0E5h $$ 00000000`775996fb 488bd9 mov rbx,rcx $$ 00000000`775996fe 66394110 cmp word ptr [rcx+10h],ax $$ 00000000`77599702 0f84ede20100 je USER32!TranslateMessage+0x14 (00000000`775b79f5) $$ USER32!TranslateMessage+0x2c: $$ 00000000`77599708 33d2 xor edx,edx $$ 00000000`7759970a 488bcb mov rcx,rbx $$ 00000000`7759970d e81e020000 call USER32!TranslateMessageEx (00000000`77599930) $$ ... $$ 通过观察MSG结构内容, 可以看到 MSG + 8 = message $$ dt MSG @rcx -r3 -v $$ ole32!MSG $$ struct tagMSG, 6 elements, 0x30 bytes $$ +0x000 hwnd : 0x00000000`0031040c struct HWND__, 1 elements, 0x4 bytes $$ +0x000 unused : ?? $$ +0x008 message : 0xf $$ +0x010 wParam : 0 $$ +0x018 lParam : 0n0 $$ +0x020 time : 0xdfd2cd $$ +0x024 pt : struct tagPOINT, 2 elements, 0x8 bytes $$ +0x000 x : 0n792 $$ +0x004 y : 0n1042 $$ 经过试验, 注释要放脚本上面. 如果放在脚本体外面, 会有函数执行失败的提示. $$ /// run results $$ MSG.message = 0000000000000201 $$ hold WM_LBUTTONDOWN $$ MK_LBUTTON pressdown $$ USER32!TranslateMessage: $$ 00000000`775996f0 fff3 push rbx $$ 00000000`775996f2 4883ec20 sub rsp,20h $$ 00000000`775996f6 b8e5000000 mov eax,0E5h $$ 00000000`775996fb 488bd9 mov rbx,rcx $$ 00000000`775996fe 66394110 cmp word ptr [rcx+10h],ax $$ 00000000`77599702 0f84ede20100 je USER32!TranslateMessage+0x14 (00000000`775b79f5) $$ USER32!TranslateMessage+0x2c: $$ 00000000`77599708 33d2 xor edx,edx $$ 00000000`7759970a 488bcb mov rcx,rbx $$ 00000000`7759970d e81e020000 call USER32!TranslateMessageEx (00000000`77599930) $$ USER32!TranslateMessage+0x36: $$ 00000000`77599712 4883c420 add rsp,20h $$ 00000000`77599716 5b pop rbx $$ 00000000`77599717 c3 ret $$ USER32!TranslateMessage+0x14: $$ 00000000`775b79f5 4c8b4918 mov r9,qword ptr [rcx+18h] $$ 00000000`775b79f9 4c8b4110 mov r8,qword ptr [rcx+10h] $$ 00000000`775b79fd 8b5108 mov edx,dword ptr [rcx+8] $$ 00000000`775b7a00 488b09 mov rcx,qword ptr [rcx] $$ 00000000`775b7a03 ff1587ab0500 call qword ptr [USER32!gImmApiEntries+0x160 (00000000`77612590)] $$ 00000000`775b7a09 85c0 test eax,eax $$ 00000000`775b7a0b 0f84f71cfeff je USER32!TranslateMessage+0x2c (00000000`77599708) $$ USER32!TranslateMessage+0x30: $$ 00000000`775b7a11 e9fc1cfeff jmp USER32!TranslateMessage+0x36 (00000000`77599712) $$ rax=0000000000000000 rbx=0000000000000000 rcx=000000000028d300 $$ rdx=000000003a94041d rsi=000000000cd60503 rdi=00000000ffe33460 $$ rip=00000000775996f0 rsp=000000000028d1f8 rbp=00000000ffe33460 $$ r8=000000000028d300 r9=00000000ffe33460 r10=0000000000000000 $$ r11=0000000000000246 r12=0000000000000000 r13=0000000000000000 $$ r14=0000000000000001 r15=0000000000000002 $$ iopl=0 nv up ei pl zr na po nc $$ cs=0033 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 $$ USER32!TranslateMessage: $$ 00000000`775996f0 fff3 push rbx $$ ole32!MSG $$ struct tagMSG, 6 elements, 0x30 bytes $$ +0x000 hwnd : 0x00000000`000602e4 struct HWND__, 1 elements, 0x4 bytes $$ +0x000 unused : 0n67108868 $$ +0x008 message : 0x201 $$ +0x010 wParam : 1 $$ +0x018 lParam : 0n720923 $$ +0x020 time : 0x1fdfc81 $$ +0x024 pt : struct tagPOINT, 2 elements, 0x8 bytes $$ +0x000 x : 0n1032 $$ +0x004 y : 0n412 $$ USER32!TranslateMessage: $$ 00000000`775996f0 fff3 push rbx $$ get message on $t0 r $t0 = poi(@rcx + 0x08) .echo ">> windbg-script.txt" $$ get wParam on $t1 r $t1 = poi(@rcx + 0x10) $$ /// #define WM_LBUTTONDOWN 0x0201 .if ($t0 == 0x0201) { .printf "MSG.message = %N\r\n", @$t0 .echo "hold WM_LBUTTONDOWN" $$ /// #define MK_LBUTTON 0x0001 $$ get MK_LBUTTON on $t2 r $t2 = ($t1 & 0x0001) .if ($t2 == 1) { $$ 鼠标左右键没有交换的情况下, 鼠标左键按下 .printf "MK_LBUTTON pressdown\r\n" .echo "" $$ 反汇编API uf USER32!TranslateMessage .echo "" $$ 显示寄存器组 r .echo "" $$ 显示MSG * 入参细节 dt MSG @rcx -r3 -v $$ WinDbg 停住了, 单步调试 $$ 用WinDbg下消息断点,运行的非常慢, 如果找到了需要的消息断点, 应该bc x, 清除消息断点. } } .else { $$ 如果不是要捕获的消息, 从条件断点开始执行 gc }
x86程序的区别: 进入目标API后, MSG * 入参在esi中
代码:
$$ /// @file d:\\windbg-script.txt $$ Windbg脚本 $$ 试验目的: 用WinDbg设置一个断点, 在断点条件发生时, 执行一个WinDbg脚本 $$ e.g. bp USER32!TranslateMessage "$$>< d:\\windbg-script.txt" $$ 试验环境: win7X64Sp1 + WinDbg 6.12.0002.633 + x86目标程序 $$ 试验步骤: $$ * bc * $$ * bp USER32!TranslateMessage "$$>< d:\\windbg-script.txt" $$ * 当断点触发后, 自动调用 d:\windbg-script.txt $$ 只有符合脚本中约定的条件时,才会停下. 否则自动继续执行 $$ e.g. 例如只有 WM_LBUTTONDOWN 发生时, WinDbg才会停下来 $$ X86程序的MSG * 在esi中 $$ MSG.message = 0000000000000201 $$ hold WM_LBUTTONUP $$ MK_LBUTTON pressdown $$ USER32!TranslateMessage: $$ 763e7809 8bff mov edi,edi $$ 763e780b 55 push ebp $$ 763e780c 8bec mov ebp,esp $$ 763e780e 56 push esi $$ 763e780f 8b7508 mov esi,dword ptr [ebp+8] $$ 763e7812 b8e5000000 mov eax,0E5h $$ 763e7817 66394608 cmp word ptr [esi+8],ax $$ 763e781b 0f84dd7d0300 je USER32!TranslateMessage+0x14 (7641f5fe) $$ USER32!TranslateMessage+0x29: $$ 763e7821 6a00 push 0 $$ 763e7823 56 push esi $$ 763e7824 e810000000 call USER32!TranslateMessageEx (763e7839) $$ USER32!TranslateMessage+0x31: $$ 763e7829 5e pop esi $$ 763e782a 5d pop ebp $$ 763e782b c20400 ret 4 $$ USER32!TranslateMessage+0x25: $$ 763e782e 85c0 test eax,eax $$ 763e7830 74ef je USER32!TranslateMessage+0x29 (763e7821) $$ USER32!TranslateMessage+0x29: $$ 763e7832 ebf5 jmp USER32!TranslateMessage+0x31 (763e7829) $$ USER32!TranslateMessage+0x14: $$ 7641f5fe ff760c push dword ptr [esi+0Ch] $$ 7641f601 ff7608 push dword ptr [esi+8] $$ 7641f604 ff7604 push dword ptr [esi+4] $$ 7641f607 ff36 push dword ptr [esi] $$ 7641f609 ff15f0014576 call dword ptr [USER32!gImmApiEntries+0xb0 (764501f0)] $$ 7641f60f e91a82fcff jmp USER32!TranslateMessage+0x25 (763e782e) $$ eax=00000000 ebx=00000002 ecx=00000000 edx=00000000 esi=0018fed0 edi=00a9be70 $$ eip=763e7809 esp=0018fe8c ebp=0018feb4 iopl=0 nv up ei pl nz na po nc $$ cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202 $$ USER32!TranslateMessage: $$ 763e7809 8bff mov edi,edi $$ ole32!MSG $$ struct tagMSG, 6 elements, 0x1c bytes $$ +0x000 hwnd : 0x000d0458 struct HWND__, 1 elements, 0x4 bytes $$ +0x000 unused : ?? $$ +0x004 message : 0x201 $$ +0x008 wParam : 1 $$ +0x00c lParam : 0n786468 $$ +0x010 time : 0xe21883 $$ +0x014 pt : struct tagPOINT, 2 elements, 0x8 bytes $$ +0x000 x : 0n812 $$ +0x004 y : 0n547 $$ USER32!TranslateMessage: $$ 763e7809 8bff mov edi,edi $$ get message on $t0 r $t0 = poi(@esi + 0x04) .echo ">> windbg-script.txt" $$ get wParam on $t1 r $t1 = poi(@esi + 0x08) $$ /// #define WM_LBUTTONDOWN 0x0201 .if ($t0 == 0x0201) { .printf "MSG.message = %N\r\n", @$t0 .echo "hold WM_LBUTTONUP" $$ /// #define MK_LBUTTON 0x0001 $$ get MK_LBUTTON on $t2 r $t2 = ($t1 & 0x0001) .if ($t2 == 1) { $$ 鼠标左右键没有交换的情况下, 鼠标左键按下 .printf "MK_LBUTTON pressdown\r\n" .echo "" $$ 反汇编API uf USER32!TranslateMessage .echo "" $$ 显示寄存器组 r .echo "" $$ 显示MSG * 入参细节 dt MSG @esi -r3 -v $$ WinDbg 停住了, 单步调试 $$ 用WinDbg下消息断点,运行的非常慢, 如果找到了需要的消息断点, 应该bc x, 清除消息断点. } } .else { $$ 如果不是要捕获的消息, 从条件断点开始执行 gc }