【逆向】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

posted @ 2020-02-15 00:21  SunsetR  阅读(755)  评论(0编辑  收藏  举报