MFC程序消息映射与破解

Eddy 发布于2010-8-26 4:16:10 分类: 加密解密 已浏览loading 网友评论2条 我要评论

00401633    .  8B7424 18          MOV ESI,DWORD PTR SS:[ESP+18]
00401637    >  6A 00              PUSH 0
00401639    .  68 34304000        PUSH Rith_Cra.00403034                                     ;  congratulations!
0040163E    .  68 20304000        PUSH Rith_Cra.00403020                                     ;  well done cracker!
00401643    .  8BCE               MOV ECX,ESI
00401645    .  E8 54020000        CALL <JMP.&MFC42.#4224_MessageBoxA@CWnd@@QAEHPBD0I@Z>

用提示字符串找到这个按钮的算法部分 也就是 MFC程序的消息映射函数处;

一个按钮点击事件的过程如下:
CWinThread::PumpMessage -> CWnd::PretranslateMessage -> CWnd::WWalkPreTranslateMessate -> CD1Dlg::PreTranslateMessage -> CDialog::PreTranslateMessage -> CWnd::PreTranslateInput  -> CWnd::IsDialogMessageA -> USER32内核 -> AfxWndProcBase -> AfxWndProc -> AfxCallWndProc -> CWnd::WindowProc -> CWnd::OnWndMsg -> CWnd::OnCommand -> CDialog::OnCmdMsg -> CCmdTarget::OnCmdMsg -> _AfxDispatchCmdMsg -> CD1Dlg::OnButton1()

由于我主要跟踪的是MFC的消息映射,所以该流程中USER32内核前的部分可以不用关心.
在刚才打开算法部分的的开头下断,点击按钮,断下来,ALT+K打开调用堆栈,在use32后面第一个MFC函数体上点显示过程,下断.

F9运行断下来,看
73DC8468     FF75 14              PUSH DWORD PTR SS:[EBP+14]
73DC846B     8365 FC 00           AND DWORD PTR SS:[EBP-4],0
73DC846F     FF75 10              PUSH DWORD PTR SS:[EBP+10]
73DC8472     FF75 0C              PUSH DWORD PTR SS:[EBP+C]
73DC8475     FF75 08              PUSH DWORD PTR SS:[EBP+8]
73DC8478     E8 A595F6FF          CALL MFC42.#1578_?AfxWndProc@@YGJPAUHWND__@@IIJ@Z
73DC847D     8B4D F0              MOV ECX,DWORD PTR SS:[EBP-10]
73DC8480     8B55 EC              MOV EDX,DWORD PTR SS:[EBP-14]
73DC8483     8951 04              MOV DWORD PTR DS:[ECX+4],EDX
73DC8486     8B4D F4              MOV ECX,DWORD PTR SS:[EBP-C]
73DC8489     64:890D 00000000     MOV DWORD PTR FS:[0],ECX
73DC8490     C9                   LEAVE
73DC8491     C2 1000              RETN 10

看到CALL MFC42.#1578_?AfxWndProc了吧,这个函数是 MFC提供的通用消息处理函数,MFC的消息是通过这个函数分发到每个窗口的cWnd对象,然后在cWnd对象定义的消息处理函数中处理各种消息.

然后在73DC8478     E8 A595F6FF          CALL MFC42.#1578_?AfxWndProc@@YGJPAUHWND__@@IIJ@Z上下断,F7单步进入,


73D31A36     8B75 08              MOV ESI,DWORD PTR SS:[EBP+8]
73D31A39     56                   PUSH ESI
73D31A3A     E8 C3F7FFFF          CALL MFC42.#2867_?FromHandlePermanent@CWnd@@SGPAV1@PAUHWND>
73D31A3F     85C0                 TEST EAX,EAX
73D31A41     74 17                JE SHORT MFC42.73D31A5A
73D31A43     3970 20              CMP DWORD PTR DS:[EAX+20],ESI
73D31A46     75 12                JNZ SHORT MFC42.73D31A5A
73D31A48     FF75 14              PUSH DWORD PTR SS:[EBP+14]
73D31A4B     FF75 10              PUSH DWORD PTR SS:[EBP+10]
73D31A4E     FF75 0C              PUSH DWORD PTR SS:[EBP+C]
73D31A51     56                   PUSH ESI
73D31A52     50                   PUSH EAX
73D31A53     E8 1C000000          CALL MFC42.#1109_?AfxCallWndProc@@YGJPAVCWnd@@PAUHWND__@@I>

这里面有两个函数,FromHandlePermanent@CWnd这个函数根据传入窗口的hWND找到起对应的CWnd对象,然后把(*pCwnd,hWnd,uMsg,wPram,lParam)传入到下个AfxCallWndProc函数中.

单步进入AfxCallWndProc函数中,

73D31A83     57                   PUSH EDI
73D31A84     8965 F0              MOV DWORD PTR SS:[EBP-10],ESP
73D31A87     68 DB88DC73          PUSH MFC42.#2202_?CreateObject@?$CThreadLocal@V_AFX_THREAD>
73D31A8C     B9 0CE6E073          MOV ECX,MFC42.73E0E60C
73D31A91     E8 DF670900          CALL MFC42.#3030_?GetData@CThreadLocalObject@@QAEPAVCNoTra>
73D31A96     8BD8                 MOV EBX,EAX
73D31A98     8D43 34              LEA EAX,DWORD PTR DS:[EBX+34]
73D31A9B     8BF0                 MOV ESI,EAX
73D31A9D     6A 07                PUSH 7
73D31A9F     59                   POP ECX
73D31AA0     8D7D C0              LEA EDI,DWORD PTR SS:[EBP-40]
73D31AA3     F3:A5                REP MOVS DWORD PTR ES:[EDI],DWORD PTR DS:[ESI]
73D31AA5     8B4D 0C              MOV ECX,DWORD PTR SS:[EBP+C]
73D31AA8     8B75 10              MOV ESI,DWORD PTR SS:[EBP+10]
73D31AAB     8B7D 08              MOV EDI,DWORD PTR SS:[EBP+8]
73D31AAE     8908                 MOV DWORD PTR DS:[EAX],ECX
73D31AB0     8B45 14              MOV EAX,DWORD PTR SS:[EBP+14]
73D31AB3     8943 3C              MOV DWORD PTR DS:[EBX+3C],EAX
73D31AB6     8B45 18              MOV EAX,DWORD PTR SS:[EBP+18]
73D31AB9     8943 40              MOV DWORD PTR DS:[EBX+40],EAX
73D31ABC     33C0                 XOR EAX,EAX
73D31ABE     83FE 02              CMP ESI,2
73D31AC1     895D EC              MOV DWORD PTR SS:[EBP-14],EBX
73D31AC4     8973 38              MOV DWORD PTR DS:[EBX+38],ESI
73D31AC7     8945 FC              MOV DWORD PTR SS:[EBP-4],EAX
73D31ACA     75 0E                JNZ SHORT MFC42.73D31ADA
73D31ACC     3947 38              CMP DWORD PTR DS:[EDI+38],EAX
73D31ACF     74 09                JE SHORT MFC42.73D31ADA
73D31AD1     8B4F 38              MOV ECX,DWORD PTR DS:[EDI+38]
73D31AD4     8B11                 MOV EDX,DWORD PTR DS:[ECX]
73D31AD6     50                   PUSH EAX
73D31AD7     FF52 64              CALL DWORD PTR DS:[EDX+64]
73D31ADA     8365 0C 00           AND DWORD PTR SS:[EBP+C],0
73D31ADE     81FE 10010000        CMP ESI,110                                            // ; 判断程序是否初始化
73D31AE4     75 0E                JNZ SHORT MFC42.73D31AF4
73D31AE6     8D45 0C              LEA EAX,DWORD PTR SS:[EBP+C]
73D31AE9     50                   PUSH EAX
73D31AEA     8D45 DC              LEA EAX,DWORD PTR SS:[EBP-24]
73D31AED     50                   PUSH EAX
73D31AEE     57                   PUSH EDI
73D31AEF     E8 51880100          CALL MFC42.73D4A345
73D31AF4     FF75 18              PUSH DWORD PTR SS:[EBP+18]
73D31AF7     8B07                 MOV EAX,DWORD PTR DS:[EDI]
73D31AF9     FF75 14              PUSH DWORD PTR SS:[EBP+14]
73D31AFC     8BCF                 MOV ECX,EDI
73D31AFE     56                   PUSH ESI
73D31AFF     FF90 A0000000        CALL DWORD PTR DS:[EAX+A0]

这里的

     GetData@CThreadLocalObject@@QAEPAVCNoTrackObject@@P6GPAV2@XZ@Z是为了得到一个
AFX_MODULE_STATE结构,并且把当前的消息填充到AFX_MODULE_STATE结构中.

单步到73D31AFF     FF90 A0000000        CALL DWORD PTR DS:[EAX+A0]                                 ; <JMP.&MFC42.#6374_?WindowProc@CWnd@@MAEJIIJ@Z>

这里,F7进入:


             73D31B8D     8BCE                 MOV ECX,ESI
73D31B8F     FF75 0C              PUSH DWORD PTR SS:[EBP+C]
73D31B92     FF75 08              PUSH DWORD PTR SS:[EBP+8]
73D31B95     FF90 A4000000        CALL DWORD PTR DS:[EAX+A4]                                 ; <JMP.&MFC42.#5163_?OnWndMsg@CWnd@@MAEHIIJPAJ@Z>
73D31B9B     85C0                 TEST EAX,EAX
73D31B9D     75 16                JNZ SHORT MFC42.73D31BB5
73D31B9F     FF75 10              PUSH DWORD PTR SS:[EBP+10]
73D31BA2     8B06                 MOV EAX,DWORD PTR DS:[ESI]
73D31BA4     FF75 0C              PUSH DWORD PTR SS:[EBP+C]
73D31BA7     8BCE                 MOV ECX,ESI
73D31BA9     FF75 08              PUSH DWORD PTR SS:[EBP+8]
73D31BAC     FF90 A8000000        CALL DWORD PTR DS:[EAX+A8]
73D31BB2     8945 FC              MOV DWORD PTR SS:[EBP-4],EAX
73D31BB5     8B45 FC              MOV EAX,DWORD PTR SS:[EBP-4]


这里面同样有两个函数调用:
                        
                <JMP.&MFC42.#5163_?OnWndMsg@CWnd@@MAEHIIJPAJ@Z>
                这个函数是  MFC处理消息的核心函数,在这个函数里面MFC确定是否对传入的消息进行处理:
            如果OnWndMsg@CWnd没有处理这个消息,将由下面这个函数处理CALL DWORD PTR DS:[EAX+A8](这里的[EAX+A8]实际上是 DefWindowProcA@CWnd,windows的默认消息函数);

进入OnWndMsg@CWnd@@MAEHIIJPAJ@Z,

73D31BD7     81FB 11010000        CMP EBX,111
73D31BDD     56                   PUSH ESI
73D31BDE     57                   PUSH EDI
73D31BDF     8BF9                 MOV EDI,ECX
73D31BE1     75 1B                JNZ SHORT MFC42.73D31BFE

看到这里的EBX值没,程序在比较ebx中所放的消息是否是WM_COMMAND,如果不是剩下的就交给其他的消息函数处理,我们的探索之旅就结束了,我们当然不能让这种事情发生.
73D31BD7     81FB 11010000        CMP EBX,111

在这上面下条件断点   ebx==111,取消其他断点.F9运行,单击check it 按钮.断下来:

73D31BD7  >  81FB 11010000        CMP EBX,111
73D31BDD     56                   PUSH ESI
73D31BDE     57                   PUSH EDI
73D31BDF     8BF9                 MOV EDI,ECX
73D31BE1     75 1B                JNZ SHORT MFC42.73D31BFE
73D31BE3     FF75 10              PUSH DWORD PTR SS:[EBP+10]
73D31BE6     8B07                 MOV EAX,DWORD PTR DS:[EDI]
73D31BE8     FF75 0C              PUSH DWORD PTR SS:[EBP+C]
73D31BEB     FF90 80000000        CALL DWORD PTR DS:[EAX+80]                                 ; <JMP.&MFC42.#4441_?OnCommand@CWnd@@MAEHIJ@Z>
73D31BF1     85C0                 TEST EAX,EAX
73D31BF3     0F84 CA000000        JE MFC42.73D31CC3
                          
  这里   <JMP.&MFC42.#4441_?OnCommand@CWnd@@MAEHIJ@Z>就是对按钮事件进行响应的位置,F7步入:
73D3323B     FF75 08              PUSH DWORD PTR SS:[EBP+8]
73D3323E     8BCE                 MOV ECX,ESI
73D33240     57                   PUSH EDI
73D33241     FF50 14              CALL DWORD PTR DS:[EAX+14]                                 ; <JMP.&MFC42.#4425_?OnCmdMsg@CDialog@@UAEHIHPAXPAUAFX_CMDHANDLERINFO@@@Z>
73D33244     5F                   POP EDI
73D33245     5E                   POP ESI
73D33246     5B                   POP EBX
73D33247     C9                   LEAVE


单步到:
       73D33241     FF50 14              CALL DWORD PTR DS:[EAX+14]                            ; <JMP.&MFC42.#4425_?OnCmdMsg@CDialog@@UAEHIHPAXPAUAFX_CMDHANDLERINFO@@@Z>
上继续步入:
       73D9DEA4     8BF1                 MOV ESI,ECX
73D9DEA6     57                   PUSH EDI
73D9DEA7     53                   PUSH EBX
73D9DEA8     E8 0844F9FF          CALL MFC42.#4424_?OnCmdMsg@CCmdTarget@@UAEHIHPAXPAUAFX_CMDHANDLERINFO@>



      继续步入73D9DEA8     E8 0844F9FF          CALL MFC42.#4424_?OnCmdMsg@CCmdTarget@@UAEHIHPAXPAUAFX_CMDHANDLERINFO@>
     

73D32385     FF75 08              PUSH DWORD PTR SS:[EBP+8]
73D32388     FF75 0C              PUSH DWORD PTR SS:[EBP+C]
73D3238B     53                   PUSH EBX
73D3238C     FF76 04              PUSH DWORD PTR DS:[ESI+4]
73D3238F     E8 DAFEFFFF          CALL MFC42.#1145_?AfxFindMessageEntry@@YGPBUAFX_MSGMAP_ENTRY@@PBU1@III>
73D32394     85C0                 TEST EAX,EAX
73D32396     75 0F                JNZ SHORT MFC42.73D323A7
73D32398     FF16                 CALL DWORD PTR DS:[ESI]
73D3239A     8BF0                 MOV ESI,EAX
73D3239C     85F6                 TEST ESI,ESI
73D3239E   ^ 75 E5                JNZ SHORT MFC42.73D32385
73D323A0     5E                   POP ESI
73D323A1     5B                   POP EBX
73D323A2     5F                   POP EDI
73D323A3     5D                   POP EBP
73D323A4     C2 1000              RETN 10



这里面AfxFindMessageEntry就是MFC中实现消息映射的位置,MFC的CWnd类中存放有

BEGIN_MESSAGE_MAP(CMsgDlg, CDialog)
  //{{AFX_MSG_MAP(CMsgDlg)
  ON_WM_SYSCOMMAND()
  ON_WM_PAINT()
  ON_WM_QUERYDRAGICON()
  ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
  ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
  //}}AFX_MSG_MAP
END_MESSAGE_MAP()

STRUCT AFX_MSG_ENTRY
{
   UNIT nMessage;     //窗口消息
   UNIT nCode;        //控制代码
   UNIT nID;          //控件ID
   UNIT nLastID       
   UNIT nSig          //消息处理函数的类型
   AFX_PMSG pfn          //消息处理函数的地址
}
如上所示的静态数组,称为消息映射表.MFC用一个STRUCT AFX_MSG_ENTRY结构来描述映射表中的每个表项.

    在这里通过一个GetMessageMap函数获得消息映射表的基地址,然后在AfxFindMessageEntry函数中,调用一个循环,比较传入的消息和映射表中表项的是否匹配来找到消息对应的处理函数,然后把这个数组中的pfn(消息处理函数地址)记录下来.

继续单步:

   73D323BA     E8 7F000000          CALL MFC42.73D3243E
73D323BF   ^ EB DF                JMP SHORT MFC42.73D323A0

CALL MFC42.73D3243E步入:
       73D3243E     8BFF                 MOV EDI,EDI
73D32440     55                   PUSH EBP
73D32441     8BEC                 MOV EBP,ESP
73D32443     8B45 20              MOV EAX,DWORD PTR SS:[EBP+20]
73D32446     53                   PUSH EBX
73D32447     33DB                 XOR EBX,EBX
73D32449     43                   INC EBX
73D3244A     85C0                 TEST EAX,EAX
73D3244C     74 12                JE SHORT MFC42.73D32460
73D3244E     8B4D 08              MOV ECX,DWORD PTR SS:[EBP+8]
73D32451     8908                 MOV DWORD PTR DS:[EAX],ECX
73D32453     8B4D 14              MOV ECX,DWORD PTR SS:[EBP+14]
73D32456     8948 04              MOV DWORD PTR DS:[EAX+4],ECX
73D32459     8BC3                 MOV EAX,EBX
73D3245B     E9 E4000000          JMP MFC42.73D32544
73D32460     8B45 1C              MOV EAX,DWORD PTR SS:[EBP+1C]
73D32463     83F8 28              CMP EAX,28
73D32466     56                   PUSH ESI
73D32467     77 71                JA SHORT MFC42.73D324DA
73D32469     74 5C                JE SHORT MFC42.73D324C7
73D3246B     48                   DEC EAX
73D3246C     48                   DEC EAX
73D3246D     74 53                JE SHORT MFC42.73D324C2
73D3246F     83E8 0A              SUB EAX,0A
73D32472     74 46                JE SHORT MFC42.73D324BA
73D32474     48                   DEC EAX
73D32475     74 3E                JE SHORT MFC42.73D324B5
73D32477     83E8 16              SUB EAX,16
73D3247A     74 2E                JE SHORT MFC42.73D324AA
73D3247C     83E8 03              SUB EAX,3
73D3247F     74 16                JE SHORT MFC42.73D32497
73D32481     48                   DEC EAX
73D32482     75 69                JNZ SHORT MFC42.73D324ED
73D32484     8B45 18              MOV EAX,DWORD PTR SS:[EBP+18]
73D32487     FF30                 PUSH DWORD PTR DS:[EAX]
73D32489     8B4D 08              MOV ECX,DWORD PTR SS:[EBP+8]
73D3248C     FF70 04              PUSH DWORD PTR DS:[EAX+4]
73D3248F     FF55 14              CALL DWORD PTR SS:[EBP+14]
73D32492     E9 A8000000          JMP MFC42.73D3253F

单步到第1个[ebp+14],经常破解的应该知道[ebp+14]这是个参数,你要是跟踪下来就会知道ebp+14的值就是AfxFindMessageEntry函数中,保存的消息处理函数的地址.

哦,原来call [EBP+14]是调用我们的消息处理函数,继续进入你就发现这就是程序的算法部分.

在这里我们先,停下来总结下.MFC通过一连串的函数走到了AfxFindMessageEntry,然后记录下
消息处理函数的地址,在通过call [EBP+14]来调用消息处理函数.

那我们是否可以通过call [EBP+14]来定位程序的算法部分.删除所有断点,,直接F9,然后ALT+E,双击MFC42.DLL,CTRL+F,输入CALL [EBP+14],在第一个找到的地址处F2下断点。

步入,果然就到了算法部分.(这里是 看 书呆彭 的贴才知道,大牛就是厉害,可惜他没讲原理).

那这中方法是否适用于其他的MFC版本呢?

在MFC42d中,也可以通过这种方式秒破.不过特征值变成了 call [ebp-4].

最后我总结下MFC的消息路由:
                     

                        AfxWindProc
                             |
                        afxCallWndProc
                             |
                        WindowProc
                             |
                          OnWndMsg(这里面判断消息类型,然后进行分发)
                          
                       如果OnWndMsg没有处理DefWindowProcA@CWnd进行默认处理


这次的分析到这里就结束了,算法很简单,我就不详细说明了.

转自pediy,作者errom。

已经有(2)位网友发表了评论,你也评一评吧!
原创文章如转载,请注明:转载自Eddy Blog
原文地址:http://www.rrgod.com/decryption/541.html     欢迎订阅Eddy Blog

  1. 发表于2010-8-26 11:20:58

    哇,好厉害~~~

  2. 发表于2010-8-26 11:21:28

    加油啊,呵呵~~~~

记住我的信息,下次不用再输入 欢迎给Eddy Blog留言