子宫肌瘤与艾灸:MFC程序中的消息逆向

来源:百度文库 编辑:偶看新闻 时间:2024/04/30 22:26:08
MFC程序中的消息逆向 

     MFC中CWnd基类中包含了一个GetThisMessageMap虚函数,用于获得指向messageMap的指针。因此任何从CWnd派生的窗口类,都含有这个函数(在虚拟函数表中的位置好像是0x30附近)。它的代码通常形如:

CWnd::GetThisMessageMap

00511390 >/>>push    ebp
00511391 |.>mov     ebp, esp
00511393 |.>mov     eax, offset messageMap
00511398 |.>pop     ebp
00511399 \.>retn

MFC的消息处理过程基本是这样的:

AfxWndProc
调用
AfxCallWndProc和<&USER32.DefWindowProcA>

AfxCallWndProc
调用
CWnd::WindowProc

CWnd::WindowProc
调用
CWnd::OnWndMsg和CWnd::DefWindowProcA/CWnd::DefWindowProcW

CWnd::OnWndMsg调用CWnd::GetThisMessageMapAfxFindMessageEntry来找到

具体的消息处理例程,并交与其处理。

因此只要能定位到CWnd::OnWndMsg就能找到CWnd::GetThisMessageMap,进而得到messageMap。

messageMap是一个很重要的结构:

它的第一个字段是指向其基类的messageMap指针,第二个字段就是_messageEntries结构数组,以一个

全零的结构结束。_messageEntries结构数组中就包含了当前窗口的消息映射情况,其对应着源码中的

消息映射宏:

BEGIN_MESSAGE_MAP(CSundyButton, CButton)
ON_WM_MEASUREITEM()
ON_WM_DRAWITEM()
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSEMOVE()
ON_MESSAGE(WM_MOUSELEAVE,&CSundyButton::OnMouseLeave)
ON_MESSAGE(WM_MOUSEHOVER,&CSundyButton::OnMouseHover)
END_MESSAGE_MAP()

因此得到_messageEntries的地址,也就得到了用户代码中处理消息的地址了。

对一个基于MFC的程序,首先参考模块中的CWnd::OnWndMsg,如果这个参考不容易找到,可以
下断点:bp AfxCallWndProc。进而追踪CWnd::WindowProc->CWnd::OnWndMsg->CWnd::GetThisMessageMap->_messageEntries。

实战训练:
目标:特色按钮.exe
主程序有4个消息处理程序,包含一个自定义的控件,它含有7个消息处理程序,尝试找出它们。

OD载入,直接找到了:
地址=004F9A80
区段=.text
类型=库
名称=CWnd::OnWndMsg

切换断点,F9运行,中断后很快跟随到GetThisMessgeMap的调用:
004F9C8C   . FFD0          call    eax   ;GetThisMessgeMap
数据跟随GetMessgeMap的返回值:
00697C00 >004DC2C9 陕M.   入口地址
00697C04 00697B88 坽i.   offset 特色按钮._messageEntries

006977C0 >004D7D00 .}M. 入口地址
006977C4 00697700 .wi. offset 特色按钮._messageEntries


数据跟随00697B88
00697B88 >0000000F ...
00697B8C 00000000 ....
00697B90 00000000 ....
00697B94 00000000 ....
00697B98 00000013 ...
00697B9C 004D7FF8 ?M.   特色按钮.004D7FF8
00697BA0 00000037 7...
00697BA4 00000000 ....
00697BA8 00000000 ....
00697BAC 00000000 ....
00697BB0 00000028 (...
00697BB4 004D666C lfM. 特色按钮.004D666C
00697BB8 00000111 ..
00697BBC 00000000 ....
00697BC0 000003EB ?..
00697BC4 000003EB ?..
00697BC8 00000038 8...
00697BCC 004D560E VM. 特色按钮.004D560E
00697BD0 00000111 ..
00697BD4 00000000 ....
00697BD8 000003E9 ?..
00697BDC 000003E9 ?..
00697BE0 00000038 8...
00697BE4 004DD8D6 重M.   特色按钮.004DD8D6
00697BE8 00000000 ....
00697BEC 00000000 ....
00697BF0 00000000 ....
00697BF4 00000000 ....
00697BF8 00000000 ....
00697BFC 00000000 ....


刚好是四个消息处理例程,消息ID和例程地址都很明显了。

接下来是自定义控件的几个消息处理例程。

跟随006977C0
006977C0 >004D7D00 .}M. 入口地址
006977C4 00697700 .wi. offset 特色按钮._messageEntries
00697700 >0000002C ,...
00697704 00000000 ....
00697708 00000000 ....
0069770C 00000000 ....
00697710 0000002E ....
00697714 004DB419 碝.   特色按钮.004DB419
00697718 0000002B +...
0069771C 00000000 ....
00697720 00000000 ....
00697724 00000000 ....
00697728 0000002E ....
0069772C 004DAEA6 ΞM.   特色按钮.004DAEA6
00697730 00000201 ..
00697734 00000000 ....
00697738 00000000 ....
0069773C 00000000 ....
00697740 00000035 5...
00697744 004E05C7 ?N.   特色按钮.004E05C7
00697748 00000202 ..
0069774C 00000000 ....
00697750 00000000 ....
00697754 00000000 ....
00697758 00000035 5...
0069775C 004DA2EE 睥M.   特色按钮.004DA2EE
00697760 00000200 . ..
00697764 00000000 ....
00697768 00000000 ....
0069776C 00000000 ....
00697770 00000035 5...
00697774 004DB45A Z碝.   特色按钮.004DB45A
00697778 000002A3 ?..
0069777C 00000000 ....
00697780 00000000 ....
00697784 00000000 ....
00697788 0000000E ...
0069778C 004DA8BB 花M.   特色按钮.004DA8BB
00697790 000002A1 ?..
00697794 00000000 ....
00697798 00000000 ....
0069779C 00000000 ....
006977A0 0000000E ...
006977A4 004DD368 h覯.   特色按钮.004DD368
006977A8 00000000 ....
006977AC 00000000 ....
006977B0 00000000 ....
006977B4 00000000 ....
006977B8 00000000 ....
006977BC 00000000 ....

注:像这种自定义控件的消息处理例程和主窗口的消息处理例程都在“特色按钮.exe”的领空,用这种方法比较容易找到。如果控件定制成DLL,OCX等以组件的形式注册,然后在主窗口中使用,按以上方法只能得到主窗口的消息处理例程地址,而封装好的组件的消息处理却在DLL,OCX中处理的。

我的做法是对AfxWndProc下断,然后返回到调用:
77D18731 call    dword ptr [ebp+8]
这一句指令是在user32领空的。

77D18731 call    dword ptr [ebp+8] 会调用

AfxWndProc和MFC42.#AfxWndProc

那么下次就对77D18731 call    dword ptr [ebp+8] 下断。
直到中断到对封装的控件消息的处理处,跟随一下发现是调用:
00C808D2   >jmp     dword ptr [<&MFC42.#AfxWndProc_1578>]
这条jmp指令就是在封装的控件领空中,而跳转的地址是MFC42领空。

相似地,mfc42.#AfxWndProc_1578会调用#AfxCallWndProc_1109
73D31A53   >call    #AfxCallWndProc_1109

#AfxCallWndProc_1109又会调用#CWnd::WindowProc_6374:
73D31AFF   >call    dword ptr [eax+A0] ;
00C7F7D0   >jmp     dword ptr [<&MFC42.#CWnd::WindowProc_>; mfc42.#CWnd::WindowProc_6374

#CWnd::WindowProc_6374又会调用#CWnd::OnWndMsg_5163
73D31B95   >call    dword ptr [eax+A4]                    ;
00C7F7CA   >jmp     dword ptr [<&MFC42.#CWnd::OnWndMsg_51>; mfc42.#CWnd::OnWndMsg_5163

在mfc42.#CWnd::OnWndMsg_5163中就可以找到控件的GetThisMessgeMap了:
73D31C5B   >mov     eax, dword ptr [edi]
73D31C5D   >mov     ecx, edi
73D31C5F   >call    dword ptr [eax+30]
73D31C62   >mov     ebx, eax                              ; CUQG.00C880F8

这两次的CWnd::OnWndMsg调用不同是因为MFC库版本不同造成的,实际上都是通过CWnd::OnWndMsg来找GetThisMessgeMap的。

最好的方法是先用OD载入这个DLL或者OCX文件,找到CWnd::OnWndMsg下好断点,

再用OD载入主程序分析。