【破文标题】:PCTimerExpert v1.4.7.8 注册算法分析

【破文作者】:KuNgBiM[DFCG]

【作者邮箱】:gb_1227@163.com

【软件名称】:PCTimerExpert 1.4.7.8

【编译语言】:Microsoft Visual C++ 6.0

【作者声明】:初学Crack,只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!

—————————————————————————————————
【破解过程】:

侦测:用PEiD查壳,无壳,Microsoft Visual C++ 6.0 编译。

试探:运行主程序注册,输入注册码(试炼码),确认!程序提示"注册失败,请检查注册码是否正确!"

初步下药:使出法宝,用W32Dasm进行静态反汇编,失望的是,改程序为MFC42的程序,并且带有Anti-Loder功能,看来W32Dasm是没戏咯~

对症下药:Ollydbg载入主程序,加载完毕后,下命令:bp GetWindowTextA,然后F9运行:

77DF768E >  55              push ebp                        //第1次断下,F9继续
77DF768F    8BEC            mov ebp,esp
77DF7691    6A FF           push -1
77DF7693    68 8034DF77     push USER32.77DF3480
77DF7698    68 4CC7E377     push USER32.77E3C74C
........

77DF768E >  55              push ebp                        //第2次断下,同样F9继续
77DF768F    8BEC            mov ebp,esp
77DF7691    6A FF           push -1
77DF7693    68 8034DF77     push USER32.77DF3480
77DF7698    68 4CC7E377     push USER32.77E3C74C
........

77DF768E >  55              push ebp                        //第3次断下,同样F9继续,USER32.SendMessageA 
77DF768F    8BEC            mov ebp,esp
77DF7691    6A FF           push -1
77DF7693    68 8034DF77     push USER32.77DF3480
77DF7698    68 4CC7E377     push USER32.77E3C74C
........

77DF768E >  55              push ebp                        //第4次断下,同样F9继续
77DF768F    8BEC            mov ebp,esp
77DF7691    6A FF           push -1
77DF7693    68 8034DF77     push USER32.77DF3480
77DF7698    68 4CC7E377     push USER32.77E3C74C
........

经过5次的F9后,程序终于来到了注册界面,输入试炼信息:

***** 试炼信息 *****

机器码:1757386560
注册码:9876543210

********************

点击“注册”后OD中断在:

77DF768E >  55              push ebp                        //中断在此!
77DF768F    8BEC            mov ebp,esp
77DF7691    6A FF           push -1
77DF7693    68 8034DF77     push USER32.77DF3480
77DF7698    68 4CC7E377     push USER32.77E3C74C
77DF769D    64:A1 00000000  mov eax,dword ptr fs:[0]
77DF76A3    50              push eax
77DF76A4    64:8925 0000000>mov dword ptr fs:[0],esp
77DF76AB    51              push ecx
77DF76AC    51              push ecx
77DF76AD    51              push ecx
77DF76AE    53              push ebx
77DF76AF    56              push esi
77DF76B0    57              push edi
77DF76B1    8965 E8         mov dword ptr ss:[ebp-18],esp
77DF76B4    8B7D 0C         mov edi,dword ptr ss:[ebp+C]
77DF76B7    85FF            test edi,edi
77DF76B9    74 58           je short USER32.77DF7713
77DF76BB    837D 10 00      cmp dword ptr ss:[ebp+10],0
77DF76BF    74 52           je short USER32.77DF7713
77DF76C1    8365 FC 00      and dword ptr ss:[ebp-4],0
77DF76C5    8027 00         and byte ptr ds:[edi],0
77DF76C8    8B4D 08         mov ecx,dword ptr ss:[ebp+8]
77DF76CB    E8 31CCFFFF     call USER32.77DF4301
77DF76D0    8BF0            mov esi,eax
77DF76D2    8975 E4         mov dword ptr ss:[ebp-1C],esi
77DF76D5    85F6            test esi,esi
77DF76D7    74 36           je short USER32.77DF770F
77DF76D9    56              push esi
77DF76DA    E8 59FFFFFF     call USER32.77DF7638
77DF76DF    85C0            test eax,eax
77DF76E1    6A 01           push 1
77DF76E3    57              push edi
77DF76E4    FF75 10         push dword ptr ss:[ebp+10]
77DF76E7    6A 0D           push 0D
77DF76E9    56              push esi
77DF76EA    74 07           je short USER32.77DF76F3
77DF76EC    E8 72E9FFFF     call USER32.77DF6063
77DF76F1    EB 05           jmp short USER32.77DF76F8
77DF76F3    E8 CCD1FFFF     call USER32.77DF48C4
77DF76F8    834D FC FF      or dword ptr ss:[ebp-4],FFFFFFFF
77DF76FC    EB 17           jmp short USER32.77DF7715
77DF76FE    6A 01           push 1
77DF7700    58              pop eax
77DF7701    C3              retn
77DF7702    8B65 E8         mov esp,dword ptr ss:[ebp-18]
77DF7705    68 78050000     push 578
77DF770A    E8 935E0100     call USER32.77E0D5A2
77DF770F    834D FC FF      or dword ptr ss:[ebp-4],FFFFFFFF
77DF7713    33C0            xor eax,eax
77DF7715    8B4D F0         mov ecx,dword ptr ss:[ebp-10]
77DF7718    64:890D 0000000>mov dword ptr fs:[0],ecx
77DF771F    5F              pop edi                                     //edi=00898730, (ASCII "9876543210")
77DF7720    5E              pop esi                                     //esi=00591F38
77DF7721    5B              pop ebx
77DF7722    C9              leave
77DF7723    C2 0C00         retn 0C                                     //返回到下面
........

6BC894AA    6A FF           push -1
6BC894AC    8BCF            mov ecx,edi
6BC894AE    E8 22EEFFFF     call MFC42.#5572                            //取注册码
6BC894B3    EB 13           jmp short MFC42.6BC894C8
6BC894B5    8BCE            mov ecx,esi
6BC894B7    E8 5D3D0000     call MFC42.#3092
6BC894BC    85C0            test eax,eax
6BC894BE    74 08           je short MFC42.6BC894C8
6BC894C0    57              push edi
6BC894C1    8BC8            mov ecx,eax
6BC894C3    E8 52FFFFFF     call MFC42.#3874                            //取注册码长度
6BC894C8    8B07            mov eax,dword ptr ds:[edi]                  //ASCII "9876543210",eax=0A
6BC894CA    5F              pop edi
6BC894CB    5E              pop esi
6BC894CC    8B40 F8         mov eax,dword ptr ds:[eax-8]                //ds:[00898728]=0000000A
6BC894CF    C2 0800         retn 8                                      //返回到下面关键计算部分!★
........

00404B9E    8B4424 08       mov eax,dword ptr ss:[esp+8]                //取试炼码长度,ASCII "9876543210",eax=0A
00404BA2    8B48 F8         mov ecx,dword ptr ds:[eax-8]                //把试炼码长度赋值给ECX
00404BA5    85C9            test ecx,ecx                                //判断注册码是否为空
00404BA7    75 0B           jnz short PCTimerE.00404BB4                 //不跳则死!
00404BA9    6A FF           push -1
00404BAB    6A 40           push 40
00404BAD    6A 78           push 78
00404BAF    E9 C5000000     jmp PCTimerE.00404C79                       //跳到注册失败
00404BB4    50              push eax                                    //eax=00898730, (ASCII "9876543210")
00404BB5    FF15 C8C54000   call dword ptr ds:[<&MSVCRT.atol>]          ; MSVCRT.atol
00404BBB    8BF0            mov esi,eax                                 //eax=4CB016EA,esi=6BCE2078
00404BBD    83C4 04         add esp,4
00404BC0    85F6            test esi,esi                                //esi=4CB016EA(转换值)
00404BC2    0F84 AB000000   je PCTimerE.00404C73                        //转换失败则跳死!
00404BC8    6A 00           push 0                                      //pFileSystemNameSize = NULL
00404BCA    6A 00           push 0                                      //pFileSystemNameBuffer = NULL
00404BCC    6A 00           push 0                                      //pFileSystemFlags = NULL
00404BCE    8D4C24 18       lea ecx,dword ptr ss:[esp+18]
00404BD2    6A 00           push 0                                      //pMaxFilenameLength = NULL
00404BD4    51              push ecx                                    //pVolumeSerialNumber
00404BD5    6A 00           push 0                                      //MaxVolumeNameSize = 0
00404BD7    6A 00           push 0                                      //VolumeNameBuffer = NULL
00404BD9    68 D4034100     push PCTimerE.004103D4                      //RootPathName = "c:\"
00404BDE    C74424 2C 00000>mov dword ptr ss:[esp+2C],0
00404BE6    FF15 6CC04000   call dword ptr ds:[<&KERNEL32.GetVolumeInfo>//KERNEL32.GetVolumeInformationA(取C盘序列号)
00404BEC    85C0            test eax,eax                                //取值成功记为1,eax=1
00404BEE    75 11           jnz short PCTimerE.00404C01                 //成功则跳向计算部分!
00404BF0    50              push eax
00404BF1    6A 30           push 30
00404BF3    68 B0034100     push PCTimerE.004103B0
00404BF8    E8 AD4E0000     call <jmp.&MFC42.#1200>
00404BFD    33C0            xor eax,eax
00404BFF    EB 15           jmp short PCTimerE.00404C16
00404C01    8B4C24 0C       mov ecx,dword ptr ss:[esp+C]                //成功后就跳到这里,并把序列号赋值给ECX
00404C05    8BD1            mov edx,ecx                                 //ecx=68C0884D,edx=00130608(取高16位)
00404C07    8BC1            mov eax,ecx                                 //ecx=68C0884D,eax=00000001(取低16位)
00404C09    C1EA 10         shr edx,10                                  //取高16位
00404C0C    2BC2            sub eax,edx                                 //减去高16位的值
00404C0E    81E1 FFFF0000   and ecx,0FFFF                               //取低16位
00404C14    2BC1            sub eax,ecx                                 //减去低16位的值
00404C16    8B15 C4D94000   mov edx,dword ptr ds:[40D9C4]               //再取一个常数值34D944EA,ds:[0040D9C4]=34D944EA
00404C1C    8BC8            mov ecx,eax                                 //上面的结果也保存到ECX中,eax=68BF9740,ecx=0000884D
00404C1E    C1E9 10         shr ecx,10                                  //取结果的高16位,ecx=68BF9740
00404C21    33D0            xor edx,eax                                 //将34D944EA与上面的结果作异或运算,eax Xor edx
00404C23    25 FFFF0000     and eax,0FFFF                               //取结果的低16位,eax=68BF9740
00404C28    2BD1            sub edx,ecx                                 //再减去高16位,ecx=000068BF,edx=5C66D3AA
00404C2A    2BD0            sub edx,eax                             //再减去低16位,EDX就是注册码,eax=00009740,edx=5C666AEB
00404C2C    33C0            xor eax,eax
00404C2E    3BD6            cmp edx,esi                                 //关键比较!
00404C30    0F94C0          sete al
00404C33    85C0            test eax,eax
00404C35    74 3C           je short PCTimerE.00404C73                  //不相等的话,就跳向注册失败!★爆破点★
00404C37    E8 3A4C0000     call <jmp.&MFC42.#1168>                     // AfxGetModuleState(void)
00404C3C    8B40 04         mov eax,dword ptr ds:[eax+4]
00404C3F    56              push esi
00404C40    68 8C034100     push PCTimerE.0041038C                      //ASCII "REGCODE"
00404C45    68 7C034100     push PCTimerE.0041037C                      //ASCII "Registration"
00404C4A    8BC8            mov ecx,eax
00404C4C    E8 5F4E0000     call <jmp.&MFC42.#6402>                     // WriteProfileInt(char const *,char const *,int)
00404C51    85C0            test eax,eax
00404C53    74 15           je short PCTimerE.00404C6A
00404C55    6A FF           push -1
00404C57    6A 40           push 40
00404C59    6A 79           push 79
00404C5B    E8 CE4B0000     call <jmp.&MFC42.#1199>                     // AfxMessageBox(“注册成功”)
00404C60    C705 780C4100 0>mov dword ptr ds:[410C78],1
00404C6A    8BCB            mov ecx,ebx
00404C6C    E8 274E0000     call <jmp.&MFC42.#4853>                     // CDialog::OnOK(void)
00404C71    EB 0B           jmp short PCTimerE.00404C7E
00404C73    6A FF           push -1
00404C75    6A 40           push 40
00404C77    6A 7A           push 7A
00404C79    E8 B04B0000     call <jmp.&MFC42.#1199>                     // AfxMessageBox(“注册失败”)
00404C7E    8D4C24 08       lea ecx,dword ptr ss:[esp+8]
00404C82    C74424 18 FFFFF>mov dword ptr ss:[esp+18],-1
00404C8A    E8 A54B0000     call <jmp.&MFC42.#800>
00404C8F    8B4C24 10       mov ecx,dword ptr ss:[esp+10]
00404C93    5E              pop esi
00404C94    5B              pop ebx
00404C95    64:890D 0000000>mov dword ptr fs:[0],ecx
00404C9C    83C4 14         add esp,14
00404C9F    C3              retn                                        //返回程序

-------------------------------------------------------------------------------------------------------------------------
【算法总结】

注册验证非常简单:

1.先把十进制的机器码转换为16进制代码,记作ZHM1。(例:1757386560 = 68BF9740)

2.接着用ZHM1与一个常数(34D944EA)异或,再减去ZHM1的高16位和低16位,记作ZHM2。
(例:即68BF9740 Xor 34D944EA - 68BF - 9740 = 5C65D3AB)

3.最后把ZHM2再转换成十进制数,作为注册码SN。

=================================

注册信息:

机器码:1757386560
注册码:1550177195

=================================

〓本文完〓

--------------------------------------------------------------------------

版权所有(C)2005 KuNgBiM[DFCG]         Copyright (C) 2005 KuNgBiM[DFCG]

--------------------------------------------------------------------------
          Cracked BY KuNgBiM[DFCG]

                2005-06-12

                4:07:27 AM