MFC寻找按钮事件

[软件名称]: CRECKME 0  CRECKME 0 程序和分析源码.zip.
[应用平台]:Win9X/NT/2000/XP
[软件大小]:8K
[破解声明]:为了检验自己的逆向破解能力,请求斑竹给个邀请码,鼓励我继续写下去。顺便感谢一下党,感谢国家,感谢我们家的曾曾。
[破解工具]:PEiD,IDA 5.5,PE Explore
[备注] 破解软件来源于看雪论坛中的帖子 (本人原创CRACKME系列 难度由0--9,看你属于哪一级)
[作者]:INightElf
[破解日期]:2012-08-06
前言:
   之前一段时间都在破解MASM32 / TASM32之类的软件,由于比较简单,很快就无法引起我的兴趣,在看雪论坛闲逛,发现有网友发(原创CRACKME系列 难度由0--9,看你属于哪一级)帖子,该破解软件由MFC 编译的,刚好用来检验本人掌握的MFC原理是否扎实,也来检验自己的破解水平。
言归正传!下面开始我们的破解之旅

1.查壳,用PEid 检测,编译器为编译器Microsoft Visual C++ 7.0 Method2 [调试],无壳。
名稱:  1.jpg查看次數: 259文件大小:  67.0 KB

2.用PE Explore 查看软件的资源,如图。可见该软件有三个对话框,其中编号为129的对话框为主要窗口, 验证输入的Name 和Serial是否正确。请记下Name控件的ID 为1000,Serial 控件的ID 为1001,确定按钮控件ID为1,取消按钮ID 为2。当输入的Name和Serial 正确,则弹出编号为102的对话框。编号为100则是关于对话框.请记下上面描述的ID号。
这是为了后面的反汇编代码中处理按钮消息做准备,请注意这里的ID 号是10进制

按圖片以查看大圖名稱:	2.jpg查看次數:	17文件大小:	131.4 KBID:	69458

3.用IDA 反汇编CrackMe0,得到CrackMe0反汇编清单,熟悉MFC编程的人都知道,一般程序都会把初始化放到CXXXApp::InitInstance和CXXXApp::IInitApplication 这两个函数,而CXXXApp则继承了CWinApp,并在CXXXApp::InitInstance 中调用父类的CWinApp::InitInstance,在CXXXApp:: IInitApplication 中调用父类的CWinApp:: IInitApplication。所以逆向的一步,则是找到CWinApp::InitInstance和CWinApp:: IInitApplication这两个函数,然后通过交叉引用注释,查找到CXXXApp::InitInstance和CWinApp:: IInitApplication函数所在地址。

按圖片以查看大圖名稱:	3.jpg查看次數:	8文件大小:	609.4 KBID:	69459

由于IDA强大的反汇编库函数,只要对Function Name 列表进行排序,很容易就找到了,在CrackMe0函数中,程序的初始化放到CXXXApp::InitInstance中。导航到交叉引用函数sub_401090,该函数就是CXXXApp::InitInstance。并对该函数进行重命名为CXXXWinApp::InitInstance。
按圖片以查看大圖名稱:	4.jpg查看次數:	4文件大小:	163.4 KBID:	69460

4.在CXXXWinApp::InitInstance函数中仔细观察,看到了地址0x004010EE 调用了CDialog::DoModal(void),表明在该地址前面创建了对话框。在text:004010DA行有一个Call 函数指令,表明了该函数创建了对话框 
.text:004010EE call?DoModal@CDialog@@UAEHXZ ; CDialog::DoModal(void)
导航进去该函数查看。果然验证了之前的推测. .text:004014CE 地址的ID为129,根据步骤2的ID比较,可以断定创建的窗口为即将破解的主窗口, 其中CrackMeMainDialogVirtualFunctionTable为主窗口的虚函数表
.text:004014EC   mov     dword ptr [esi], offset CrackMeMainDialogVirtualFunctionTable ; 虚函数表格
CrackMeMainDialogVirtualFunctionTable 函数名为本人重新命名的,请注意。为什么在这里要特别强调主窗口的虚函数表呢?这是非常关键的一步。猜猜!嘻嘻。
当当当……….谜底是(为了获取确定按钮的消息处理函数) 。是不是觉得我很无聊呢。

按圖片以查看大圖名稱:	4-1.jpg查看次數:	5文件大小:	178.1 KBID:	69464


.text:004014B0 CreateCrackMeMainDialog proc near       ; CODE XREF: CXXXWinApp::InitInstance(void)+4A p
.text:004014B0
.text:004014B0 var_10          = dword ptr -10h
.text:004014B0 var_C           = dword ptr -0Ch
.text:004014B0 var_4           = dword ptr -4
.text:004014B0 arg_0           = dword ptr  4
.text:004014B0
.text:004014B0                 push    0FFFFFFFFh
.text:004014B2                 push    offset SEH_4014B0
.text:004014B7                 mov     eax, large fs:0
.text:004014BD                 push    eax
.text:004014BE                 mov     large fs:0, esp
.text:004014C5                 push    ecx
.text:004014C6                 mov     eax, [esp+10h+arg_0]
.text:004014CA                 push    esi
.text:004014CB                 push    eax
.text:004014CC                 mov     esi, ecx
.text:004014CE                 push    129             ; hDlgTemplateId 对话框模板ID,在这里也是破解的主窗口
.text:004014D3                 mov     [esp+1Ch+var_10], esi
.text:004014D7                 call    ??0CDialog@@QAE@IPAVCWnd@@@Z ; CDialog::CDialog(uint,CWnd *)
.text:004014DC                 push    offset unk_403940
.text:004014E1                 lea     ecx, [esi+74h]
.text:004014E4                 mov     [esp+18h+var_4], 0
.text:004014EC                 mov     dword ptr [esi], offset CrackMeMainDialogVirtualFunctionTable ; 虚函数表格
.text:004014F2                 call    ds:??0?$CStringT@DV?$StrTraitMFC_DLL@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@QAE@PBD@Z ; ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>(char const *)
.text:004014F8                 mov     ecx, [esp+14h+var_C]
.text:004014FC                 mov     dword ptr [esi+78h], 0
.text:00401503                 mov     eax, esi
.text:00401505                 pop     esi
.text:00401506                 mov     large fs:0, ecx
.text:0040150D                 add     esp, 10h
.text:00401510                 retn    4
.text:00401510 CreateCrackMeMainDialog endp


5.导航到CrackMeMainDialogVirtualFunctionTable 虚函数表格。
在地址
.rdata:0040380C dd offset ?GetTypeLib@CCmdTarget@@UAEJKPAPAUITypeLib@@@Z ; CCmdTarget::GetTypeLib(ulong,ITypeLib * *)
和地址 
.rdata:00403814 dd offset ?GetCommandMap@CCmdTarget@@MBEPBUAFX_OLECMDMAP@@XZ ; CCmdTarget::GetCommandMap(void)
之间的函数就是主窗口消息栈区函数。请注意该函数已经被本人重新命名过。
.rdata:00403810                 dd offset j_?GetMessageMap@CrackMeMainDialog@@MBEPBUAFX_MSGMAP@@XZ ; CrackMeMainDialog::GetMessageMap(void)
按圖片以查看大圖名稱:	5.jpg查看次數:	6文件大小:	410.7 KBID:	69465

6.导航到CrackMeMainDialog::GetMessageMap(void) 函数,在该函数里面的地址.text:00401545 设置断点,并执行程序。
text:00401540 ; protected: virtual struct AFX_MSGMAP const * __thiscall CrackMeMainDialog::GetMessageMap(void)const
.text:00401540 j_?GetMessageMap@CrackMeMainDialog@@MBEPBUAFX_MSGMAP@@XZ proc near
.text:00401540                 mov     eax, offset off_403780
.text:00401545                 retn
.text:00401545 j_?GetMessageMap@CrackMeMainDialog@@MBEPBUAFX_MSGMAP@@XZ endp
则程序中断在地址text:00401545,查看此时的EAX寄存器值,[EAX+4] == 0x00403784 的值就是MFC 对话框的消息处理函数列表。

按圖片以查看大圖名稱:	6.jpg查看次數:	1文件大小:	274.9 KBID:	69461

在栈区Jump到地址0x00403784

名稱:  6-1.jpg查看次數: 258文件大小:  67.8 KB

在栈区Jump到地址0x00403788
名稱:  6-2.jpg查看次數: 256文件大小:  88.7 KB

在这里必须说明以下MFC消息处理函数的结构,定义如下
#define ON_CONTROL(wNotifyCode, id, memberFxn) \
  { WM_COMMAND, (WORD)wNotifyCode, (WORD)id, (WORD)id, AfxSigCmd_v, \
    (static_cast< AFX_PMSG > (memberFxn)) },

#define WM_COMMAND     0x0111  发送命令消息,一般控件按钮消息都是通过这个命令发送的。
Id 就是按钮的ID号, memberFxn 就是按钮的消息处理函数。
从上图和步骤二可以知道,确定按钮的ID号为1,所以地址0x004015A0 为确定按钮的消息处理函数。本人把该函数重新命名为BtnOK

7.  十万长征终于完成了一半,导航到函数地址,剩下的工作就是分析算法了。
.text:004015A0 ; 确定按钮事件
.text:004015A0
.text:004015A0 BtnOK           proc near
.text:004015A0
.text:004015A0 ; FUNCTION CHUNK AT .text:004015D5 SIZE 00000034 BYTES
.text:004015A0
.text:004015A0                 push    esi
.text:004015A1                 push    edi
.text:004015A2                 push    1
.text:004015A4                 mov     esi, ecx
.text:004015A6                 call    ?UpdateData@CWnd@@QAEHH@Z ; CWnd::UpdateData(int)
.text:004015AB                 lea     edi, [esi+74h]  ; 获取Name 字段的内容
.text:004015AE                 mov     ecx, edi
.text:004015B0                 call    ds:?GetLength@?$CSimpleStringT@D$00@ATL@@QBEHXZ ; ATL::CSimpleStringT<char,1>::GetLength(void)
.text:004015B6                 cmp     eax, 6          ; name 字段的字符串的长度必须大于等于6
.text:004015B9                 jge     short loc_4015D5
.text:004015BB                 cmp     dword ptr [esi+78h], 186A0h
.text:004015C2                 jge     short loc_4015D5
.text:004015C4                 push    0               ; unsigned int
.text:004015C6                 push    0               ; unsigned int
.text:004015C8                 push    offset aNameOrSerialIs ; "Name or Serial is too short!"
.text:004015CD                 call    ?AfxMessageBox@@YGHPBDII@Z ; AfxMessageBox(char const *,uint,uint)
.text:004015D2
.text:004015D2 loc_4015D2:
.text:004015D2                 pop     edi
.text:004015D3                 pop     esi
.text:004015D4                 retn
.text:004015D4 BtnOK           endp
.text:004015D4
.text:004015D5 ; ---------------------------------------------------------------------------
.text:004015D5 ; START OF FUNCTION CHUNK FOR BtnOK
.text:004015D5
.text:004015D5 loc_4015D5:                             ; Name 字段的内容与"IndolentAfternoon" 字符串比较,
.text:004015D5                 push    offset aIndolentaftern ; 一致则继续比较Serial,从这里就说明了Name 必须=='IndolentAfternoon'
.text:004015DA                 mov     ecx, edi
.text:004015DC                 call    ds:?Compare@?$CStringT@DV?$StrTraitMFC_DLL@DV?$ChTraitsCRT@D@ATL@@@@@ATL@@QBEHPBD@Z ; ATL::CStringT<char,StrTraitMFC_DLL<char,ATL::ChTraitsCRT<char>>>::Compare(char const *)
.text:004015E2                 test    eax, eax
.text:004015E4                 jnz     short loc_4015D2
.text:004015E6                 cmp     dword ptr [esi+78h], 5687255 ; 获取Serial 字符串与5687255 常量比较,一致则说明了输入的Serial
.text:004015E6                                         ; 是正确的,并给出成功的提示符,证明了 Serial  ==5687255
.text:004015ED                 jnz     short loc_4015D2
.text:004015EF                 push    0               ; unsigned int
.text:004015F1                 push    0               ; unsigned int
.text:004015F3                 push    offset aCongratulation ; "Congratulation! Correct Serial Num,do n"...
.text:004015F8                 call    ?AfxMessageBox@@YGHPBDII@Z ; AfxMessageBox(char const *,uint,uint)
.text:004015FD                 mov     eax, [esi]
.text:004015FF                 pop     edi
.text:00401600                 mov     ecx, esi
.text:00401602                 pop     esi
.text:00401603                 jmp     dword ptr [eax+154h]
.text:00401603 ; END OF FUNCTION CHUNK FOR BtnOK

8.前面分析了那么多步骤只是为了获取按钮消息事件而已,感觉有点学院派的作风,其实可以用很多简单的方法来获取。但是就无法理解MFC消息处理机制了。总结前面的步骤
第1步获取: CWinApp::InitInstance函数地址
第2步获取: CXXXWinApp::InitInstance函数地址
第3步获取: 主对话框的虚函数表CrackMeMainDialogVirtualFunctionTable
第4步获取: 主对话框的CrackMeMainDialog::GetMessageMap(void)const 函数
第5步获取: 获取确定按钮事件.text:004015A0  BtnOK 
很多MFC程序都可以用前面的5个步骤来获取按钮的消息,这个是本人总结出来的宝贵经验,现在无偿奉献给大家。明天把算法的步骤补上,其实该算法特别简单。但是写到现在我已经没有精力写下去了。累!

9.算法太简单了,在BtnOK函数中直接给出明文比较,通过分析可以得出 Name ==” IndolentAfternoon” ,Serial == 5687255   不需要注册机。 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值