如何找到MFC程序中的消息处理函数?
1 如果想断下特定的消息的处理函数,则首先在函数CWnd::WindowProc函数中下条件断点,因为消息经过内核到相应的处理函数的过程中必须经过这个函数,此函数的定义如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
LRESULT CWnd::WindowProc(UINT message,WPARAM wParam,LPARAM lParam)
{
LRESULT lResult=0;
if(!OnWndMsg(message,wParam,lParam,&lResult))
lResult=DefWindowProc(message,wParam,lParam);
return lResult;
}
message即为消息,在这个函数中首先调用了函数OnWndMsg对消息进行处理,这个处理过程是找到消息对应的处理函数的过程,如果未能找到相应的处理函数则调用DefWindowProc,即默认的消息处理函数对消息进行处理,因此,如果我们需要对特定的消息下断点,只要在函数OnWndMsg处设置条件断点即可,WindowProc函数的反汇编代码如下
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
73D31B77 8BFF mov edi, edi ; CWnd::WindowProc
73D31B79 55 push ebp
73D31B7A 8BEC mov ebp, esp
73D31B7C 51 push ecx
73D31B7D 8365 FC 00 and dword ptr [ebp-4], 0
73D31B81 56 push esi
73D31B82 8BF1 mov esi, ecx
73D31B84 8B06 mov eax, dword ptr [esi]
73D31B86 8D4D FC lea ecx, dword ptr [ebp-4]
73D31B89 51 push ecx
73D31B8A FF75 10 push dword ptr [ebp+10]
73D31B8D 8BCE mov ecx, esi
73D31B8F FF75 0C push dword ptr [ebp+C]
73D31B92 FF75 08 push dword ptr [ebp+8]
73D31B95 FF90 A4000000 call dword ptr [eax+A4] ; OnWndMsg
73D31B9B 85C0 test eax, eax
73D31B9D 75 16 jnz short 73D31BB5
73D31B9F FF75 10 push dword ptr [ebp+10]
73D31BA2 8B06 mov eax, dword ptr [esi]
73D31BA4 FF75 0C push dword ptr [ebp+C]
73D31BA7 8BCE mov ecx, esi
73D31BA9 FF75 08 push dword ptr [ebp+8]
73D31BAC FF90 A8000000 call dword ptr [eax+A8] ; DefWindowProc
73D31BB2 8945 FC mov dword ptr [ebp-4], eax
73D31BB5 8B45 FC mov eax, dword ptr [ebp-4]
73D31BB8 5E pop esi
73D31BB9 C9 leave
73D31BBA C2 0C00 retn 0C
call dword ptr [eax+A4]即为OnWndMsg函数的调用,函数的参数有四个,message,wParam,lParam,&lResult,分别对应73D31B92 73D31B8F 73D31B8A 73D31B89四行,因此,条件断点下在73D31B92处,例如下条件断点[ebp+8]==WM_TIMER即对定时器消息进行中断。
2 追踪用户自定义的消息处理函数
条件断点下好以后,此时已经断下了定时器消息,这个消息的处理过程是用户自定义的,如何找到它呢?
其实很简单,一路F8下去吧,如果遇到进入程序领空的call,就F7跟进,很快的。。示例如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
73D31BC2 > B8 F1EFDC73 mov eax, 73DCEFF1 ; OnWndMsg
73D31BC7 E8 AC100900 call 73DC2C78
73D31BCC 83EC 58 sub esp, 58
73D31BCF 8365 F0 00 and dword ptr [ebp-10], 0
73D31BD3 53 push ebx
73D31BD4 8B5D 08 mov ebx, dword ptr [ebp+8]
73D31BD7 81FB 11010000 cmp ebx, 111 ; WM_COMMAND
73D31BDD 56 push esi
73D31BDE 57 push edi
73D31BDF 8BF9 mov edi, ecx
73D31BE1 75 1B jnz short 73D31BFE
在第73D31BD7行,函数OnWndMsg比较当前消息是否为WM_COMMAND消息,如果是则执行73D31BE1以下的命令,如果不是则跳转到73D31BFE行,本例中拦截的是WM_TIMER,不是WM_COMMAND,所以会跳转。73D31BFE行代码如下:
73D31BFE 83FB 4E cmp ebx, 4E ; WM_NOTIFY
73D31C01 75 23 jnz short <WM_ACTIVATE>
同样是一个比较,此处比较的是当前消息是否为WM_NOTIFY消息,此处会跳,跳的位置是73D31C26,此行代码如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
73D31C26 > 83FB 06 cmp ebx, 6 ; WM_ACTIVATE
73D31C29 8B75 10 mov esi, dword ptr [ebp+10]
73D31C2C 75 10 jnz short 73D31C3E
此处也是一个比较,比较当前消息是否喂WM_ACTIVATE消息,此处跳,跳到73D31C3E处,代码如下:
73D31C3E 83FB 20 cmp ebx, 20 ; WM_SETCURSOR
73D31C41 75 18 jnz short 73D31C5B
此处比较消息是否为WM_SETCURSOR,此处跳到73D31C5B处,代码如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
73D31C5B 8B07 mov eax, dword ptr [edi]
73D31C5D 8BCF mov ecx, edi
73D31C5F FF50 30 call dword ptr [eax+30]
73D31C62 8BD8 mov ebx, eax
73D31C64 895D EC mov dword ptr [ebp-14], ebx
73D31C67 335D 08 xor ebx, dword ptr [ebp+8]
73D31C6A 6A 07 push 7
73D31C6C 81E3 FF010000 and ebx, 1FF
73D31C72 E8 07670900 call #1196_AfxLockGlobals
73D31C77 8B4D 08 mov ecx, dword ptr [ebp+8]
73D31C7A 8B45 EC mov eax, dword ptr [ebp-14]
73D31C7D 8D1C5B lea ebx, dword ptr [ebx+ebx*2]
73D31C80 8D1C9D 58E6E073 lea ebx, dword ptr [ebx*4+73E0E658]
73D31C87 3B0B cmp ecx, dword ptr [ebx]
73D31C89 75 24 jnz short 73D31CAF
值得注意的是第73D31C5F处的call进入了程序领空,F7跟进以后代码如下:
00401240 . B8 E8224000 mov eax, 004022E8
00401245 . C3 retn
这显然不是消息相应函数,继续跟踪,直到遇到进入程序领空的call,在第73D31FD1行找到了一个进入程序领空的call,F7跟进,代码如下:
![](https://www.cnblogs.com/Images/OutliningIndicators/ContractedBlock.gif)
Code
00401480 . 56 push esi
00401481 . 6A 00 push 0
00401483 . 68 28304000 push 00403028 ; ASCII "ok"
00401488 . 8BF1 mov esi, ecx
0040148A . 68 20304000 push 00403020 ; ASCII "okok"
0040148F . E8 44020000 call <jmp.&MFC42.#4224_CWnd::MessageBoxA>
00401494 . 8BCE mov ecx, esi
00401496 . E8 2B020000 call <jmp.&MFC42.#2379_CWnd::Default>
0040149B . 5E pop esi
0040149C . C2 0400 retn 4
这就是WM_TIMER消息的相应函数,可以看到,调用了MessageBoxA函数,输出一个简单的对话框,消息的追踪流程到此结束,其他类型的消息可以同样追踪完成
博客很久没更新,汗颜。。。