首页
社区
课程
招聘
如何在IDA中找到MFC程序的消息处理函数
2005-12-8 23:39 13949

如何在IDA中找到MFC程序的消息处理函数

bpx 活跃值
3
2005-12-8 23:39
13949
比起用Win32SDK写的程序,要分析MFC应用程序要麻烦不少。在前者,只要找到注册窗口类的地方就知道其WinProc的位置。那里是程序的控制中心,只要顺藤摸瓜就可以找到你感兴趣的地方。对于用MFC写的程序,这一切都变得复杂起来了。这时,所有的消息都是通过一套复杂的机制来完成分发的。他们是通过分发数据表来找到最终函数地址的. 详细请参阅MFC的源代码。

常见的消息分发数据是由以下的宏来生成的:
        ON_WM_SIZE()
        ON_NOTIFY(TCN_SELCHANGE, ID_TABBOARD, OnBoardSelchange)
        ON_WM_LBUTTONDBLCLK()
        ON_WM_LBUTTONDOWN()
        ON_WM_RBUTTONDOWN()
        ON_WM_TIMER()
        ON_COMMAND(ID_REDRAW_ALL, OnRedrawAll)

这里简单说一下如何找到二类消息的处理函数。一类是WM_XXX型消息,如WM_LBUTTONDOWN,另一类是WM_COMMAND型消息.

对于第一类,它的调用栈是:
CMyView::OnLButtonDown        <--最终目标
CWnd::OnWndMsg                <--找到这个函数就接近最终目标了
CWnd::WindowProc
AxfCallWndProc
AxfWndProc
AxfWndProcBase

以WM_LBUTTONDOWN为例

#define ON_WM_LBUTTONDOWN() \
        { WM_LBUTTONDOWN, 0, 0, 0, AfxSig_vwp, \
                (AFX_PMSG)(AFX_PMSGW)(void (AFX_MSG_CALL CWnd::*)(UINT, CPoint))&OnLButtonDown },
AfxSig_vwp = 0x31

对于VC6.0 Release 版本,可搜索 C0 24 F0 83 C0 2F 48  83 F8 30 0F 87 C6 02 找到CWnd::OnWndMsg。
进入CWnd::OnWndMsg后,找到 case 0x30(IDA 中的case 0x30其实是 case 0x31)处的
call    ebx
将进入你真正感兴趣的地方!

这里必须用条件断点Dword(ESP+0x0c) == 0x201, (注WM_LBUTTONDOWN == 0x201) 否则这个断点总会遇到.

找WM_COMMAND消息处理的地方

对于第二类,它的调用栈是:
CMyDoc::OnCmdXXX        <--最终目标
_AxfDispatchCmdMsg        <--找到这个函数就接近最终目标了
CCmdTarget::OnCmdMsg
CDocument::OnCmdMsg
CView::OnCmdMsg
CFrameWnd::OnCmdMsg
CWnd::OnCommand
CFrameWnd::OnCommand
CWnd::OnWndMsg
CWnd::WindowProc
AxfCallWndProc
AxfWndProc
AxfWndProcBase

ON_COMMAND定义如下
#define ON_COMMAND(id, memberFxn) \
        { WM_COMMAND, CN_COMMAND, (WORD)id, (WORD)id, AfxSig_vv, (AFX_PMSG)&memberFxn },
其中的AfxSig_vv = 12

搜索 71 74 5C 48  48 74 53 83 E8 0A 74 46,将找到_AfxDispatchCmdMsg函数,在case 12 的地方设断点并运行,当程序需要处理OnCmdXXX的时候,控制就会跑到这里,单步进入就可以了。

[培训]《安卓高级研修班(网课)》月薪三万计划

收藏
点赞7
打赏
分享
最新回复 (19)
雪    币: 233
活跃值: (85)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
dssz 2005-12-9 00:12
2
0
好文章,果然是高人,支持!!!!!!!

建议版主加精华!!!!!!!!
雪    币: 229
活跃值: (70)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
skyege 2 2005-12-9 00:22
3
0
收下了。楼主不防写个小工具。
雪    币: 208
活跃值: (40)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
justlovemm 2005-12-11 13:13
4
0
顶啊
我以前也考虑过这个问题,但就是没有想到好的办法。
雪    币: 207
活跃值: (40)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
+dEMON 1 2005-12-11 14:28
5
0
学习。。。
雪    币: 26435
活跃值: (18467)
能力值: (RANK:350 )
在线值:
发帖
回帖
粉丝
kanxue 8 2005-12-11 20:22
6
0
最初由 dssz 发布
好文章,果然是高人,支持!!!!!!!

建议版主加精华!!!!!!!!


才看到。;(
如果还有漏掉的好文章,还麻烦各位顶一下。
雪    币: 136
活跃值: (398)
能力值: ( LV9,RANK:170 )
在线值:
发帖
回帖
粉丝
yzslly 4 2005-12-11 21:04
7
0
不错,想当时也被困扰。。。
雪    币: 214
活跃值: (15)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
ljy3282393 1 2005-12-11 21:57
8
0
楼主要是给合一个具体的例子来讲解就更好了
雪    币: 298
活跃值: (445)
能力值: ( LV12,RANK:450 )
在线值:
发帖
回帖
粉丝
Immlep 11 2005-12-11 23:01
9
0
好文章啊,第200个帖就留在这里啊.!!呵呵..
雪    币: 254
活跃值: (126)
能力值: ( LV8,RANK:130 )
在线值:
发帖
回帖
粉丝
heXer 3 2005-12-11 23:44
10
0
最初由 kanxue 发布


才看到。;(
如果还有漏掉的好文章,还麻烦各位顶一下。


以后看到没加精的都去顶一下
雪    币: 244
活跃值: (81)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
萝卜 1 2005-12-12 01:40
11
0
最初由 heXer 发布


以后看到没加精的都去顶一下

雪    币: 598
活跃值: (617)
能力值: ( LV12,RANK:660 )
在线值:
发帖
回帖
粉丝
prince 16 2005-12-12 10:26
12
0
确是好文章,差点漏掉~
雪    币: 227
活跃值: (370)
能力值: ( LV9,RANK:530 )
在线值:
发帖
回帖
粉丝
lnn1123 13 2005-12-12 16:23
13
0
最初由 heXer 发布


以后看到没加精的都去顶一下

雪    币: 449
活跃值: (552)
能力值: ( LV9,RANK:690 )
在线值:
发帖
回帖
粉丝
winndy 17 2005-12-12 16:32
14
0
正写出了我所需要的..

有没有更通用的办法?
找出delphi的,vb的,etc...
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
jjwangjun 2005-12-12 17:20
15
0
非常好
雪    币: 162
活跃值: (112)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
小楼 1 2005-12-12 17:49
16
0
不必用ida,用ultraedit就行。方法如下
注意到mfc的消息列表有
  PAFX_MSGMAP_ENTRY = ^AFX_MSGMAP_ENTRY;
  AFX_MSGMAP_ENTRY = packed record
    nMessage: dword; // windows中消息代号,定义在WinUser.h中
    nCode: dword;    // 如果nMessage是0x0111(WM_Command),nCode代表扩展消息,例如WM_Exchange等.亦定义在WinUser.h中
    nID: dword;      // 控件ID, 与资源部分中控件的ID一致
    nLastID: dword;  //  = nID
    nSig: dword;     //  含义不清楚
    AFX_PMSG: dword; // 指向消息处理的具体代码的开始位置
  end;  

所以我们只要知道消息的类型,和发出消息的控件ID,就可以搜索找到这个数组,那么AFX_PMSG就是你需要下断的地址

基于类似的方法,vb,delphi都可以这样来找到事件的处理代码的起始位置。
我想,大部分现代编译器编译的程序也应该适用这种方法。

扩展开去,这种方法应该属于伟大的dead listing技术之一。如果有兴趣,我们能进一步解析mfc,delphi,vb等程序的结构,从而了解更多。《黑客反汇编揭密》那本书讲的基本就是dead listing技术(虽然有人认为那本书很不怎么的)。
雪    币: 272
活跃值: (40)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
听听雨吧 2005-12-12 20:58
17
0
小楼GG在啊,顶一下!
雪    币: 1866
活跃值: (95)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
dalao 1 2005-12-14 16:22
18
0
好文章呀!支持!
雪    币: 61
活跃值: (12)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
sdtw 2005-12-14 20:25
19
0
看过...就顶...............
雪    币: 191
活跃值: (997)
能力值: ( LV6,RANK:90 )
在线值:
发帖
回帖
粉丝
poppig 2 2005-12-19 15:22
20
0
谢谢小楼的方法,呵呵!
  比较好用!

  用bpx的方法,怎么用UE找不到
C0 24 F0 83 C0 2F 48  83 F8 30 0F 87 C6 02
  有人试验了吗?我用的是Release方式编译的啊!
游客
登录 | 注册 方可回帖
返回