前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >MFC原理第五讲.消息映射.以及如何添加消息

MFC原理第五讲.消息映射.以及如何添加消息

作者头像
IBinary
发布2019-05-25 16:47:04
1.8K0
发布2019-05-25 16:47:04
举报
文章被收录于专栏:逆向技术逆向技术逆向技术

        MFC原理第五讲.消息映射.以及如何添加消息

一丶消息映射是什么

  我们知道.Win32程序.都是通过消息去驱动的. 不断的在处理消息. 只要我们使用固定的宏.就可以让我们的框架知道一旦消息发生.该往哪一个类传递. 每一个类可以拥有一个映射表格.

也可以没有.  

  关键宏   1. DECLARE_MESSAGE_MAP 声明宏.放在类中

  2. BEGIN_MESSAGE_MAP 实现宏放在类实现外

  3. END_MESSAGE_MAP 实现宏放在类外面

如何添加消息.

  如果我们添加了 BEGIN 跟 END 两个宏之后. 我们在中间添加他们的消息就可以.

  例如:

BEGIN_MESSAGE_MAP(CMainWnd,CFrameWnd)   //两个参数.第一个是自己的类.第二个是父类.
    ON_WM_LBUTTONDOWN()                 我们的消息. 需要添加声明以及实现.
END_MESSAGE_MAP()

我们的消息.MFC都给我们封装好了.如果实现消息. 则一律 ON_WM开头. 消息 是WM_XXX.

我们可以在 afxmsg.h 中查看.

我们在类中声明消息.并且添加消息处理函数即可.

例如以下代码:

上面是声明.下面是实现.

应用程序截图

二丶消息映射原理分析

  不管学习任何东西. 先学会用.再去学习原理.这样是最快的.

现在对我们的宏进行拆分来看.

  1.DECLARE_MESSAGE_MAP 宏查看.

#define DECLARE_MESSAGE_MAP() \
protected: \
    static const AFX_MSGMAP* PASCAL GetThisMessageMap(); \
    virtual const AFX_MSGMAP* GetMessageMap() const; \

这个宏一幕了然. 添加了两个方法.一个是虚方法.

那么这个是声明宏.那么另外两个应该就有实现宏了.看下实现宏的拆解.

  2.BEGIN_MESSAGE_MAP(字节类名.父类名)

#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[] =  \
        {

可以看得出.拆解开是一个一半的东西. 这里需要添加我们的消息了.所以下面是END_MESSAGE_MAP

所以两个一起解析.

const AFX_MSGMAP* CMainWnd::GetMessageMap() const
{
    return GetThisMessageMap();
}

const AFX_MSGMAP* PASCAL CMainWnd::GetThisMessageMap()
{
    typedef CMainWnd ThisClass;
    typedef CFrameWnd TheCFrameWnd;
    static const AFX_MSGMAP_ENTRY _messageEntries[] =
    {
        //这里添加我们的消息

    {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }      //END_MESSAGE_MAP 宏.下面都是.
    };
    static const AFX_MSGMAP messageMap = 
    { 
        &TheCFrameWnd::GetThisMessageMap, &_messageEntries[0] 
    }; 
        return &messageMap; 
}

可以看出.这两个宏就是对声明的两个宏的实现. 而上面我们添加的ON_WM_LBUTTONDOWN 就是放在 END_MESSAGE_MAP 上面的. 我们看一下格式.

const AFX_MSGMAP* CMainWnd::GetMessageMap() const
{
    return GetThisMessageMap();
}

const AFX_MSGMAP* PASCAL CMainWnd::GetThisMessageMap()
{
    typedef CMainWnd ThisClass;
    typedef CFrameWnd TheCFrameWnd;
    static const AFX_MSGMAP_ENTRY _messageEntries[] =
    {
        //这里添加我们的消息
        ON_WM_LBUTTONDOWN()                                //我们要解析这个消息
    {0, 0, 0, 0, AfxSig_end, (AFX_PMSG)0 }
    };
    static const AFX_MSGMAP messageMap = 
    { 
        &TheCFrameWnd::GetThisMessageMap, &_messageEntries[0] 
    }; 
        return &messageMap; 
}
#define ON_WM_LBUTTONDOWN() \
    { WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwp, \
        (AFX_PMSG)(AFX_PMSGW) \
        (static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > ( &ThisClass :: OnLButtonDown)) },

其实上面可以看出.其实是一个 _messageEntries数组.保存着我们的消息. 我们替换这个宏看一下.

    { 
        WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwp, 
        (AFX_PMSG)(AFX_PMSGW)(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > ( &ThisClass :: OnLButtonDown)) 
    },

解析完成可以看到.第一个是 WM_LBUTTONDOWN 对应着他的处理函数 OnLButtonDown 也就是最后一个参数.

所以现在明白了我们添加消息的时候.为什么要按照规定的格式. 因为这个宏已经使消息一一对应了.

因为上面是一个结构体数组用来保存.所以我们可以看一下这个数组是什么格式的.

struct AFX_MSGMAP_ENTRY
{
    UINT nMessage;   // windows message
    UINT nCode;      // control code or WM_NOTIFY code
    UINT nID;        // control ID (or 0 for windows messages)
    UINT nLastID;    // used for entries specifying a range of control id's
    UINT_PTR nSig;       // signature type (action) or pointer to message #  
    AFX_PMSG pfn;    // routine to call (or special value)
};

注释也给我们写的很清楚了. 消息. 消息控制代码.什么消息类型 控制ID pfn函数的返回值类型 pfn 消息处理对应函数.

但是我们要具体解释一下. 第5个跟第6个参数.

第五个参数指明了我们函数的返回值

比如上图:

  AfxSig_vwp 类型. 我们可以点击F12取头文件中查看.例如下图:

所以我们知道了我们的函数定义的返回以及参数类型了.

我是按照VS2015下的MFC讲解. 如果是VC6.0下. 那么 需要添加三个成员方法. 不过实现是类似了. 具体可以查看VC60的MFC源码.

根据VS2015给我们添加了两个成员方法. 可以看到返回值也是一个结构体.那么看下这个结构体内容吧.

struct AFX_MSGMAP
{
    const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();  父类的MAP
    const AFX_MSGMAP_ENTRY* lpEntries;            存放自己当前的消息结构.
};

上面总结一下.

  1.首先声明宏会为我们添加两个方法. 获取消息映射表

  2.实现宏则实现这两个方法. 而且还有两个结构. 一个是存放消息信息的结构. 另一个结构则是存放父类的MessageMap .以及自己当前存放信息的结构

那么知道了消息映射表.我们可以在按钮点击的时候. 按一下打印出我们消息的时候对应的地址了. 这个对于逆向很有帮助. 学到最后我们可以写一个工具. 可以有很好的切入点了.

具体代码如下:

void CMainWnd::OnMyLButtonDown(UINT flag, CPoint point) //知道了结构我们自己改也可以.
{
	//获取消息映射表.看看消息传递.
	const AFX_MSGMAP * pMsg = GetMessageMap();
	//打印出自己当前按钮点击的时候的地址.
	CString str;
	str.Format(TEXT("地址 = %p\r\n"), pMsg->lpEntries->pfn);  从消息映射表中获取我们的函数地址. 其实应该遍历.并且判断是否是消息.这里直接就偷懒了.因为只有一个消息.
	OutputDebugString(str);
	AfxMessageBox(TEXT("OnLButtonDown"));
}

应用程序截图:

很方便的看到了地址. 我们可以使用逆向工具 到这个地址查看.看看是否是我们点击的时候的消息.

因为是Dbg版本.所以有Jmp跳转的一层.我们直接跳转进去查看.

可以很简单的看到.就是我们编写的代码的位置.

下一讲讲解消息传递.

链接:https://pan.baidu.com/s/1HQo3muBivkRcM0koKjICeQ 密码:p5dj

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2018-09-12 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  •         MFC原理第五讲.消息映射.以及如何添加消息
    • 一丶消息映射是什么
    • 二丶消息映射原理分析
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档