本文的知识点完全出自一本名叫《深入浅出MFC》的书。当然同样的知识点,网上也有很多其他版本
不过这些并非以找按钮事件为目的,他们都是以知识点介绍为主
那你要说我这是炒冷饭,那我就不高兴了,这应该叫做“换一个角度看问题”
关于文章的定位问题:
本来这篇文章是写得比较复杂的,涉及MFC的知识,但我觉得这样不好,就改啊改,把文章改成定位为初级的
不过读者还是必须掌握C++与对C++逆向的基础知识,这两点必须有,不一定要懂MFC
对于文章,原本我只讲思路,可思路往往又只有学过、理解的人才看得懂,既然理解了何必再看我
这便一个矛盾的地方,也与我觉得不好的地方
基于这点考虑,我把文章分为了两部分:
<1> 方法
所谓方法就是指具体操作做法,就是具体到点鼠标、运算加减乘除上,当然还有不可避免的极少分析
<2> 原理
所谓原理就是用来支持方法的,为什么这样做总得有个说法对吧。作为一个提高存在,实在理解不了算了
------------------------------------废话可能有点多,大家不要嫌,那么让我们切入正题-----------------------------------------
方法:
我必须先把操作步骤提出来:
1,我们要定位按钮事件,是从一个关键的数据结构中获得事件函数的指针,这个结构名叫 AFX_MSGMAP_ENTRY
2,定位 AFX_MSGMAP_ENTRY 又需要定位一条虚函数,名叫 GetMessageMap ,这是条包装函数,他包装的函数取 AFX_MSGMAP_ENTRY 结构指针
3,虚函数的定位,自然是通过虚函数表,至于定位虚函数表那自然就是定位MFC类对象的 this 指针
步骤的含义将在原理中说的,不理解没关系,但是结构懂不懂?虚函数是什么知不知道?这每本C++的书都会讲,这是我前面提到的第一个要求,掌握C++基础
总结下来,我们唯一不确定的就是 this 指针,只要能找到MFC类对象的 this 指针,那就大功告成了
找 this 指针的方法多种多样,可以通过成员函数找到,但我认为最好的还是找构造函数(一般构造更容易找)
这也是我前面提的第二个要求,掌握C++逆向的基础, this 指针你总得能找到对吧
接下来看代码了,我带大家走一次,OD载入例子程序1,停在OEP处:
例子程序是我随手找来的一个计算器,上面有太多按钮,打个比方我们现在要定位其中某个按钮,比如说Enter按钮
一路F8走到这里
进入call以后,来到以下,继续F8一路走
F7进入call dword ptr [eax+50]这句以后,让我数一下,我一共贴出了33句代码,多得真是用上了全部手指脚趾都数不完
我们接着看进入以后的代码
好了, this 指针,也找到了,我再多说几句, this 指针的格式是这样的:
这里有两个问题:
1,按照这个格式找到的call不一定是构造函数,不过ecx装的是 this 指针基本没跑的
2,虽然是 this 指针,但又不一定是窗口类的,这个就不好说了,一般来讲我以上步骤找到的都正确
我建议换上 IDA 来识别,因为IDA能认出是否是窗口类的 this 指针( 注 )
找到 this 指针以后,看上面的三步骤,这里是逆向,也就是说要倒着看那三条
第三条找 this 指针,这就是刚刚做过的事
第二条通过虚函数表找虚函数 GetMessageMap ,看图中说明
(图一)
(图二)
图2中都是虚函数指针,哪一条才是我们要的 GetMessageMap 呢
这里我已经勾出来了,要想找出这条虚函数,必须了解它的“规律”
我这里说一下规律:
(图三)
既然我已经勾出来,那就看一下 GetMessageMap 的代码,如图3
在步骤2的说明中我已经提到过, GetMessageMap 是条包装函数,意味着他不做任何实际有意义的事,除了调用
那么第一条规律就是: 包装
从图3中可以看到,一共有8句代码,其中头两句和末三句是进出函数的惯例了,没什么好看的,第三第四句实际上是废操作
只剩第五句,调用了一条有意义的函数,这就是一个彻头彻尾的包装
接着必须要看一下被调用的关键函数
(图四)
依旧是十分简单的,同时也引出了第二条规律: 至关重要的函数实际上有意义只有一条mov eax, 全局指针
这个全局指针就是 AFX_MSGMAP_ENTRY 的结构指针
步骤二也已完成,剩下的就是最后一条,步骤一,也就是找按钮事件的指针了
跟随00456AA8到数据窗口
(图五)
完成图5的操作后就是大功告成的前夕,先别急,我们还得给按钮事件下个断点呢,不然这按钮事件找来有何意义
(图六)
图6中,我用蓝色框框标出来的所有指针,给他们下断,这些都是按钮事件(消息映射)
看出规律了吗,他这是一个结构数组,每隔6个dword,就是一个按钮事件(消息映射),最后以0结尾
我们要找的Enter按钮事件,就在其中
原理:
保持帖子整洁,原理放入文档中供下载观看了
----------------------------------------------------------------------------------------------------
附注:
关于IDA识别窗口类的操作如下:
首先改一个选项
(图七)
(图八)
然后就看函数名,函数名中出现了CDialog、CWnd、CFrameWnd的这些就是窗口类
(图九)
结语:
看完本文,我要说的是,我们现在把找按钮事件的难点转换成了找窗口的 this 指针
这么难度就大大降低,因为这点可以通过IDA来协助查找
我不敢保证各位一定能找到窗口的 this 指针,但至少如果你能看懂本文,那以后就不要再发帖问“请问MFC按钮事件怎么找?”,而是这样问“请问这个程序的窗口this指针怎么找?”
实际情况下,找窗口的 this 指针可能还是有点复杂
打个比方,现在有个程序,他有好几个窗口,上面都是不同的按钮,我现在只想断其中一个窗口的其中一个按钮
那每个窗口都有个this指针,定位起来难度就会加大
还是请多多使用IDA,因为他能认出很多MFC类成员函数,从中找到窗口类的 this 指针
补充:
不过这些并非以找按钮事件为目的,他们都是以知识点介绍为主
那你要说我这是炒冷饭,那我就不高兴了,这应该叫做“换一个角度看问题”
关于文章的定位问题:
本来这篇文章是写得比较复杂的,涉及MFC的知识,但我觉得这样不好,就改啊改,把文章改成定位为初级的
不过读者还是必须掌握C++与对C++逆向的基础知识,这两点必须有,不一定要懂MFC
对于文章,原本我只讲思路,可思路往往又只有学过、理解的人才看得懂,既然理解了何必再看我
这便一个矛盾的地方,也与我觉得不好的地方
基于这点考虑,我把文章分为了两部分:
<1> 方法
所谓方法就是指具体操作做法,就是具体到点鼠标、运算加减乘除上,当然还有不可避免的极少分析
<2> 原理
所谓原理就是用来支持方法的,为什么这样做总得有个说法对吧。作为一个提高存在,实在理解不了算了
------------------------------------废话可能有点多,大家不要嫌,那么让我们切入正题-----------------------------------------
方法:
我必须先把操作步骤提出来:
1,我们要定位按钮事件,是从一个关键的数据结构中获得事件函数的指针,这个结构名叫 AFX_MSGMAP_ENTRY
2,定位 AFX_MSGMAP_ENTRY 又需要定位一条虚函数,名叫 GetMessageMap ,这是条包装函数,他包装的函数取 AFX_MSGMAP_ENTRY 结构指针
3,虚函数的定位,自然是通过虚函数表,至于定位虚函数表那自然就是定位MFC类对象的 this 指针
步骤的含义将在原理中说的,不理解没关系,但是结构懂不懂?虚函数是什么知不知道?这每本C++的书都会讲,这是我前面提到的第一个要求,掌握C++基础
总结下来,我们唯一不确定的就是 this 指针,只要能找到MFC类对象的 this 指针,那就大功告成了
找 this 指针的方法多种多样,可以通过成员函数找到,但我认为最好的还是找构造函数(一般构造更容易找)
这也是我前面提的第二个要求,掌握C++逆向的基础, this 指针你总得能找到对吧
接下来看代码了,我带大家走一次,OD载入例子程序1,停在OEP处:
例子程序是我随手找来的一个计算器,上面有太多按钮,打个比方我们现在要定位其中某个按钮,比如说Enter按钮
一路F8走到这里
进入call以后,来到以下,继续F8一路走
F7进入call dword ptr [eax+50]这句以后,让我数一下,我一共贴出了33句代码,多得真是用上了全部手指脚趾都数不完
我们接着看进入以后的代码
好了, this 指针,也找到了,我再多说几句, this 指针的格式是这样的:
这里有两个问题:
1,按照这个格式找到的call不一定是构造函数,不过ecx装的是 this 指针基本没跑的
2,虽然是 this 指针,但又不一定是窗口类的,这个就不好说了,一般来讲我以上步骤找到的都正确
我建议换上 IDA 来识别,因为IDA能认出是否是窗口类的 this 指针( 注 )
找到 this 指针以后,看上面的三步骤,这里是逆向,也就是说要倒着看那三条
第三条找 this 指针,这就是刚刚做过的事
第二条通过虚函数表找虚函数 GetMessageMap ,看图中说明
(图一)
(图二)
图2中都是虚函数指针,哪一条才是我们要的 GetMessageMap 呢
这里我已经勾出来了,要想找出这条虚函数,必须了解它的“规律”
我这里说一下规律:
(图三)
既然我已经勾出来,那就看一下 GetMessageMap 的代码,如图3
在步骤2的说明中我已经提到过, GetMessageMap 是条包装函数,意味着他不做任何实际有意义的事,除了调用
那么第一条规律就是: 包装
从图3中可以看到,一共有8句代码,其中头两句和末三句是进出函数的惯例了,没什么好看的,第三第四句实际上是废操作
只剩第五句,调用了一条有意义的函数,这就是一个彻头彻尾的包装
接着必须要看一下被调用的关键函数
(图四)
依旧是十分简单的,同时也引出了第二条规律: 至关重要的函数实际上有意义只有一条mov eax, 全局指针
这个全局指针就是 AFX_MSGMAP_ENTRY 的结构指针
步骤二也已完成,剩下的就是最后一条,步骤一,也就是找按钮事件的指针了
跟随00456AA8到数据窗口
(图五)
完成图5的操作后就是大功告成的前夕,先别急,我们还得给按钮事件下个断点呢,不然这按钮事件找来有何意义
(图六)
图6中,我用蓝色框框标出来的所有指针,给他们下断,这些都是按钮事件(消息映射)
看出规律了吗,他这是一个结构数组,每隔6个dword,就是一个按钮事件(消息映射),最后以0结尾
我们要找的Enter按钮事件,就在其中
原理:
保持帖子整洁,原理放入文档中供下载观看了
----------------------------------------------------------------------------------------------------
附注:
关于IDA识别窗口类的操作如下:
首先改一个选项
(图七)
(图八)
然后就看函数名,函数名中出现了CDialog、CWnd、CFrameWnd的这些就是窗口类
(图九)
结语:
看完本文,我要说的是,我们现在把找按钮事件的难点转换成了找窗口的 this 指针
这么难度就大大降低,因为这点可以通过IDA来协助查找
我不敢保证各位一定能找到窗口的 this 指针,但至少如果你能看懂本文,那以后就不要再发帖问“请问MFC按钮事件怎么找?”,而是这样问“请问这个程序的窗口this指针怎么找?”
实际情况下,找窗口的 this 指针可能还是有点复杂
打个比方,现在有个程序,他有好几个窗口,上面都是不同的按钮,我现在只想断其中一个窗口的其中一个按钮
那每个窗口都有个this指针,定位起来难度就会加大
还是请多多使用IDA,因为他能认出很多MFC类成员函数,从中找到窗口类的 this 指针
补充: