逆向MFC程序不同于标准的windows程序,标准windows程序我们很容易找到窗口过程,并且窗口过程基本上都是用户自定义代码,通过跟踪对WM_COMMAND消息的处理我们很容易就能找到按钮对应的处理逻辑。(wParam保存了对应按钮的控件ID或者通过lParam保存对应按钮的句柄,以下所有理论来自《深入浅出MFC》一书)
MFC对WM_COMMAND的处理进行的封装,这边我引用侯捷的《深入浅出MFC》一书中的图来像大家展示封装后的窗口过程函数的样子
通过上图我们可以看到,我们原先窗口过程标准的消息处理变成了找消息映射表MessageMap中的消息条目,消息条目是一个数组,用来表示什么按钮(nID)用什么函数(pfn)来处理什么消息(nMessage),消息映射表对应的数据结构如下:
struct AFX_MSGMAP
{
const AFX_MSGMAP* (PASCAL* pfnGetBaseMap)();
const AFX_MSGMAP_ENTRY* lpEntries;
};
struct AFX_MSGMAP_ENTRY
{
UINT nMessage;
UINT nCode;
UINT nID;
UINT nLastID;
UINT_PTR nSig;
AFX_PMSG pfn;
};
AFX_MSGMAP就是我们的消息映射表,它包含一个指向父类消息映射表的指针,以及一个指向消息映射条目数组的指针。如果我们知道了按钮的控件ID,而按钮触发的消息都是WM_COMMAND(0x111h),我们就能很容易找到对应的消息条目,这样我们就知道按钮被按下后会触发什么逻辑了。那么如何定位消息映射表呢?
- 因为MFC还实现了运行时动态识别RTTI,而这个结构正好在我们的消息映射表结构前面,并且RTTI结构中保存了类名的常量字符串,所以我们可以通过找类名找到RTTI结构,然后往下找到我们的消息映射表
- 如果控件ID比较特殊,我们可以直接使用IDA搜索立即数直接定位到对应的消息映射条目
- 由于GetMessageMap函数是个虚函数,所以我们的消息映射表结构是在虚表中的,我们只要定位到了虚表那么我们就能很容易找到对应的消息映射函数
具体怎么做呢?欢迎观看实践篇