【逆向】MFC消息映射定位与识别
前言
消息映射是MFC内建的一个消息分发机制,只要利用数个宏以及固定形式的写法,就可以让Framework知道,一旦消息发生,该如何调用对应的消息处理函数。通俗来讲就是通过宏等技术手段,建立一个消息映射表,将每个窗口下的消息与消息处理函数用类似Map容器的方式进行一一对应。
数据结构
AFX_MSGMAP:
struct AFX_MSGMAP { const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)(); //父类消息映射表 const AFX_MSGMAP_ENTRY* lpEntries; //自身消息映射表 };
AFX_MSGMAP_ENTRY:
struct AFX_MSGMAP_ENTRY { UINT nMessage; //窗口消息 UINT nCode //控制代码 或 WM_NOTIFY代码 UINT nID; //控件ID(或0,用于窗口信息) UINT nLastID; //用于指定控件 ID 的范围 UINT nSig; //签名类型(动作)或指向消息的指针 AFX_PMSG pfn; //要调用的处理函数(或特殊值) }
映射原理
1、使用宏(“DECLARE_MESSAGE_MAP”)在“.h”头文件中声明消息映射表
//以下是宏展开后的内容,其实就是声明2个用于获取 AFX_MSGMAP 结构体的函数: #define DECLARE_MESSAGE_MAP() \ protected: \ static const AFX_MSGMAP* PASCAL GetThisMessageMap(); \ //用于获取:AFX_MSGMAP(包含父类和自身的消息映射表) virtual const AFX_MSGMAP* GetMessageMap() const; \ //虚函数:内部会直接调用上面的 GetThisMessageMap()
2、使用宏(“BEGIN_MESSAGE_MAP”,“END_MESSAGE_MAP”)在“.cpp”文件中实现消息映射表
//BEGIN_MESSAGE_MAP(实现消息映射表) BEGIN_MESSAGE_MAP(CHelloDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDC_BUTTON1, &CHelloDlg::OnBnClickedButton1) //按钮事件:将按钮1与处理函数绑定 END_MESSAGE_MAP() //将宏展开以后可以发现,内部其实就是依次调用上面说的2个函数,然后返回 AFX_MSGMAP 结构体 #define BEGIN_MESSAGE_MAP(theClass, baseClass) \ PTM_WARNING_DISABLE \ const AFX_MSGMAP* theClass::GetMessageMap() const \ { return GetThisMessageMap(); } \ const AFX_MSGMAP* PASCAL theClass::GetThisMessageMap() \ { \ typedef theClass ThisClass; \ typedef baseClass TheBaseClass; \ static const AFX_MSGMAP_ENTRY _messageEntries[] = \ { #define END_MESSAGE_MAP() \ {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 } \ }; \ static const AFX_MSGMAP messageMap = \ { &TheBaseClass::GetThisMessageMap, &_messageEntries[0] }; \ return &messageMap; \ } \ PTM_WARNING_RESTORE
3、当MFC程序的某个窗口产生消息时,窗口类对象通过调用虚函数“GetMessageMap()”获取消息映射表。然后执行对应的消息处理函数。
分析识别
根据消息映射原理我们可以知道,其实分析就是查找和定位 AFX_MSGMAP 结构体的过程:
方法一:获取指定窗口对象,遍历虚函数表,获取虚函数(“GetMessageMap”),通过该函数获取自身消息映射表
方法二:内存搜索“AFX_MSGMAP_ENTRY”结构体,通过“nMessage”,“nID”字段定位按钮事件处理函数
编写Demo程序,逆向分析其消息映射表,手动定位“Button1”按钮事件,获取事件处理函数地址。
1 //Button1按钮,事件处理函数 2 void CHelloDlg::OnBnClickedButton1() 3 { 4 MessageBox(NULL, NULL); 5 }
“WM_PAINT”消息是窗口绘画消息,几乎每一个窗口都有它,所以我们在内存(“.rdata”)搜索消息映射结构体(“AFX_MSGMAP_ENTRY”)的时候,可以通过“nMessage”字段的“WM_PAINT”消息来定位消息映射表。
按“长型”->“地址”的方式显示数据,查找控件ID为“00 00 03 E8”的消息映射表。
反汇编地址跟随“00821A3C”
参考
《深入浅出MFC》
https://bbs.pediy.com/thread-248816.htm
https://www.52pojie.cn/thread-151725-1-1.html