【破解作者】 农夫
【软件名称】 五子棋 3.2
【破解工具】 Olldbg1.10 、Peid0.92
【破解平台】 win2000 sp4
【破解声明】 仅供学习和交流,没有其他目的。失误之处敬请诸位大侠赐教!
【破解日期】 2005.2.3
【破解内容】
《加密与解密》(第二版)买了已经一年多了, 当时看了没到一半,就知难而退,放一边去了。如今书本还崭新如故。
近日,心血来潮,突然对破解有了兴趣,感觉老是用别人破解好的软件心里总有一种别扭,不如自己也来破它一破,以图痛快。
于是就到看雪论坛来逛了逛,了解了破解的一点皮毛,手就有点痒痒的了。总想找一点什么软件来解解才行,翻了一通电脑,
总算找到了一个比较小的软件--五子棋,正好是没有注册的,就拿它开第一刀吧!
五子棋3.2已经是很旧版本了,我想早就有人破过了,但我切实没有看过这个软件的破文,在此就现一下丑了。
用PEiD进行查壳,显示Borland Delphi 4.0 - 5.0,没有壳。用Olldbg加载主程序,看着反汇编的代码有点不知所措,
怎么办?找字符串!在反汇编窗口点右键-->搜索-->字符参考,出来了一大堆,从后面往前找,看到了"Name""Register"
"RegNo""Register",还有"Five99.ini",难道程序要读ini文件?不理它,先双击第一个"Name",进入了下面的程序段,
在地址00466AA4处设个断点,运行,进入注册画面,输入注册名abcdef,注册码123456,注册,断下了。先用F8粗略调试
一遍,发现问题就在这里了。重来,这回用F7+F8进行细调,发现程序把输入的注册名和注册码都写入了Five99.ini文件里,
并且还从几个不同的地方读Five99.ini对注册码进行校验,用爆破不太合适,解码--把它的注册码揪出来!具体分析如下:
00466AA4 /. 55 push ebp
00466AA5 |. 8BEC mov ebp,esp
00466AA7 |. 6A 00 push 0
00466AA9 |. 6A 00 push 0
00466AAB |. 53 push ebx
00466AAC |. 33C0 xor eax,eax
00466AAE |. 55 push ebp
00466AAF |. 68 596B4600 push Five.00466B59
00466AB4 |. 64:FF30 push dword ptr fs:[eax]
00466AB7 |. 64:8920 mov dword ptr fs:[eax],esp
00466ABA |. 8D55 FC lea edx,dword ptr ss:[ebp-4]
00466ABD |. A1 789A4700 mov eax,dword ptr ds:[479A78]
00466AC2 |. 8B80 E4020000 mov eax,dword ptr ds:[eax+2E4]
00466AC8 |. E8 2356FCFF call Five.0042C0F0 ;读“注册名”对话框的字符
00466ACD |. 8B45 FC mov eax,dword ptr ss:[ebp-4] ;EAX为存放字符串的首地址
00466AD0 |. 50 push eax ;将其保存
00466AD1 |. B9 706B4600 mov ecx,Five.00466B70 ; ASCII "Name"
00466AD6 |. BA 806B4600 mov edx,Five.00466B80 ; ASCII "Register"
00466ADB |. A1 809A4700 mov eax,dword ptr ds:[479A80]
00466AE0 |. 8B18 mov ebx,dword ptr ds:[eax]
00466AE2 |. FF53 04 call dword ptr ds:[ebx+4] ;创建Five99.ini文件,并将输入的注册名写到"Name"项上
00466AE5 |. 8D55 F8 lea edx,dword ptr ss:[ebp-8]
00466AE8 |. A1 789A4700 mov eax,dword ptr ds:[479A78]
00466AED |. 8B80 EC020000 mov eax,dword ptr ds:[eax+2EC]
00466AF3 |. E8 F855FCFF call Five.0042C0F0 ;读“注册码”对话框的字符
00466AF8 |. 8B45 F8 mov eax,dword ptr ss:[ebp-8] ;EAX为存放字符串的首地址
00466AFB |. 50 push eax ;将其保存
00466AFC |. B9 946B4600 mov ecx,Five.00466B94 ; ASCII "RegNo"
00466B01 |. BA 806B4600 mov edx,Five.00466B80 ; ASCII "Register"
00466B06 |. A1 809A4700 mov eax,dword ptr ds:[479A80]
00466B0B |. 8B18 mov ebx,dword ptr ds:[eax]
00466B0D |. FF53 04 call dword ptr ds:[ebx+4] ;将输入的注册码写到Five99.ini文件的"RegNo"项上
00466B10 |. E8 CBFCFFFF call Five.004667E0 ;问题就在这个CALL里啦!跟进去!
00466B15 |. 803D 7C9A4700 00 cmp byte ptr ds:[479A7C],0 ;[479A7C]是注册成败的标志,非0为成功。
00466B1C |. 75 0C jnz short Five.00466B2A ;这是注册成功后的跳转
00466B1E |. B8 A46B4600 mov eax,Five.00466BA4
00466B23 |. E8 A898FEFF call Five.004503D0 ;这是注册失败的提示
00466B28 |. EB 14 jmp short Five.00466B3E
00466B2A |> B8 D06B4600 mov eax,Five.00466BD0
00466B2F |. E8 9C98FEFF call Five.004503D0
00466B34 |. A1 789A4700 mov eax,dword ptr ds:[479A78]
00466B39 |. E8 3AFFFDFF call Five.00446A78
00466B3E |> 33C0 xor eax,eax
00466B40 |. 5A pop edx
00466B41 |. 59 pop ecx
00466B42 |. 59 pop ecx
00466B43 |. 64:8910 mov dword ptr fs:[eax],edx
00466B46 |. 68 606B4600 push Five.00466B60
00466B4B |> 8D45 F8 lea eax,dword ptr ss:[ebp-8]
00466B4E |. BA 02000000 mov edx,2
00466B53 |. E8 08D0F9FF call Five.00403B60
00466B58 \. C3 retn
从地址00466B10的CALL来到这里:
004667E0 /$ 55 push ebp
004667E1 |. 8BEC mov ebp,esp
004667E3 |. 81C4 C8FDFFFF add esp,-238
004667E9 |. 53 push ebx
004667EA |. 56 push esi
004667EB |. 57 push edi
004667EC |. 33C0 xor eax,eax
004667EE |. 8985 C8FDFFFF mov dword ptr ss:[ebp-238],eax ;用于存放从ini文件里读取的注册号字符串的地址清0
004667F4 |. 8985 CCFDFFFF mov dword ptr ss:[ebp-234],eax ;用于存放从ini文件里读取的注册码字符串的地址清0
004667FA |. 33C0 xor eax,eax
004667FC |. 55 push ebp
004667FD |. 68 BD694600 push Five.004669BD
00466802 |. 64:FF30 push dword ptr fs:[eax]
00466805 |. 64:8920 mov dword ptr fs:[eax],esp
00466808 |. 6A 00 push 0
0046680A |. 8D85 CCFDFFFF lea eax,dword ptr ss:[ebp-234]
00466810 |. 50 push eax
00466811 |. B9 D4694600 mov ecx,Five.004669D4 ; ASCII "Name"
00466816 |. BA E4694600 mov edx,Five.004669E4 ; ASCII "register"
0046681B |. A1 809A4700 mov eax,dword ptr ds:[479A80]
00466820 |. 8B18 mov ebx,dword ptr ds:[eax]
00466822 |. FF13 call dword ptr ds:[ebx] ;从ini文件里读取注册名字符串
00466824 |. 8B95 CCFDFFFF mov edx,dword ptr ss:[ebp-234] ;EDX为存放注册名字符串的地址
0046682A |. 8D85 D0FDFFFF lea eax,dword ptr ss:[ebp-230]
00466830 |. B9 FF000000 mov ecx,0FF
00466835 |. E8 5ED5F9FF call Five.00403D98 ;取注册名字符串的长度
0046683A |. 8D95 D0FDFFFF lea edx,dword ptr ss:[ebp-230] ;EDX为存放注册名字符串的长度的地址,长度之后为注册名字符串
00466840 |. 8D45 9B lea eax,dword ptr ss:[ebp-65] ;EAX为注册名字符串长度
00466843 |. B1 64 mov cl,64
00466845 |. E8 C2C1F9FF call Five.00402A0C ;注册名字符串长度处理
0046684A |. 6A 00 push 0
0046684C |. 8D85 C8FDFFFF lea eax,dword ptr ss:[ebp-238]
00466852 |. 50 push eax
00466853 |. B9 F8694600 mov ecx,Five.004669F8 ; ASCII "RegNo"
00466858 |. BA E4694600 mov edx,Five.004669E4 ; ASCII "register"
0046685D |. A1 809A4700 mov eax,dword ptr ds:[479A80]
00466862 |. 8B18 mov ebx,dword ptr ds:[eax]
00466864 |. FF13 call dword ptr ds:[ebx] ;从ini文件里读取注册码字符串
00466866 |. 8B95 C8FDFFFF mov edx,dword ptr ss:[ebp-238] ;EDX为存放注册码字符串的地址
0046686C |. 8D85 D0FDFFFF lea eax,dword ptr ss:[ebp-230]
00466872 |. B9 FF000000 mov ecx,0FF
00466877 |. E8 1CD5F9FF call Five.00403D98 ;取注册码字符串的长度
0046687C |. 8D95 D0FDFFFF lea edx,dword ptr ss:[ebp-230] ;EDX为存放注册码字符串的长度的地址,长度之后为注册码字符串
00466882 |. 8D85 36FFFFFF lea eax,dword ptr ss:[ebp-CA] ;EAX为注册码字符串长度
00466888 |. B1 64 mov cl,64
0046688A |. E8 7DC1F9FF call Five.00402A0C ;注册码字符串长度处理
0046688F |. 8A45 9B mov al,byte ptr ss:[ebp-65] ;取注册名字符串长度
00466892 |. 84C0 test al,al ;检测注册名字符串长度
00466894 |. 74 09 je short Five.0046689F ;如果没有字符串,则退出
00466896 |. 80BD 36FFFFFF 06 cmp byte ptr ss:[ebp-CA],6 ;检测注册名字符串长度是否有效,必须长度为6
0046689D |. 74 0C je short Five.004668AB ;有效,则去解码
0046689F |> C605 7C9A4700 00 mov byte ptr ds:[479A7C],0 ;否则,清解码标志
004668A6 |. E9 F4000000 jmp Five.0046699F
004668AB |> 8BF0 mov esi,eax
004668AD |. 81E6 FF000000 and esi,0FF
004668B3 |. 85F6 test esi,esi
004668B5 |. 7C 22 jl short Five.004668D9
004668B7 |. 46 inc esi ;长度加1,连长度一起做变换处理
004668B8 |. 8D4D 9B lea ecx,dword ptr ss:[ebp-65] ;ECX为注册名字符串长度及注册名字符串首地址
004668BB |. 8D9D D1FEFFFF lea ebx,dword ptr ss:[ebp-12F] ;EBX为存放解码后的数据存放首地址
004668C1 |> 33C0 /xor eax,eax
004668C3 |. 8A01 |mov al,byte ptr ds:[ecx] ;取一个字符,第一次为取长度
004668C5 |. BF 0A000000 |mov edi,0A ;EDI=10
004668CA |. 33D2 |xor edx,edx
004668CC |. F7F7 |div edi ;EAX/EDI(10),取余
004668CE |. 80C2 30 |add dl,30 ;余数DL=DL+30,即将余数转为ASCII码
004668D1 |. 42 |inc edx ;EDX+1
004668D2 |. 8813 |mov byte ptr ds:[ebx],dl ;保存计算所得的数据
004668D4 |. 43 |inc ebx ;保存数据的地址加1
004668D5 |. 41 |inc ecx ;注册名字符串地址加1,取下一个字符
004668D6 |. 4E |dec esi ;长度减1
004668D7 |.^75 E8 \jnz short Five.004668C1
004668D9 |> 33C9 xor ecx,ecx
004668DB |. 8A4D 9B mov cl,byte ptr ss:[ebp-65] ;取注册名字符串长度
004668DE |. 83F9 01 cmp ecx,1 ;做字符串长度检测
004668E1 |. 7C 1A jl short Five.004668FD
004668E3 |. 8D840D D1FEFFFF lea eax,dword ptr ss:[ebp+ecx-12F] ;取刚处理好的数据,即对注册名字符进行二次变换处理,EAX为数据的高地址
004668EA |> 8A55 9B /mov dl,byte ptr ss:[ebp-65] ;取长度
004668ED |. 2AD1 |sub dl,cl ;以固定长度减计数长度 DL-CL,CL=6,5,4,3,2,1
004668EF |. 03D2 |add edx,edx ;EDX+EDX 即(EDX-ECX)*2
004668F1 |. 8A18 |mov bl,byte ptr ds:[eax] ;取一个字符到BL
004668F3 |. 02D3 |add dl,bl ;DL+BL
004668F5 |. 8810 |mov byte ptr ds:[eax],dl ;保存计算所得的数据
004668F7 |. 49 |dec ecx ;计数长度减1
004668F8 |. 48 |dec eax ;数据地址减1
004668F9 |. 85C9 |test ecx,ecx
004668FB |.^75 ED \jnz short Five.004668EA
004668FD |> 8A45 9B mov al,byte ptr ss:[ebp-65] ;取注册名字符串长度
00466900 |. 3C 06 cmp al,6 ;再做字符串长度检测
00466902 |. 73 30 jnb short Five.00466934 ;长度不小于6,转
00466904 |. 33C9 xor ecx,ecx
00466906 |. 8AC8 mov cl,al
00466908 |. 41 inc ecx
00466909 |. 83F9 06 cmp ecx,6
0046690C |. 7F 26 jg short Five.00466934
0046690E |. 8D9C0D D0FEFFFF lea ebx,dword ptr ss:[ebp+ecx-130] ;这是字符串长度小于6的计算
00466915 |> 33C0 /xor eax,eax
00466917 |. 8A03 |mov al,byte ptr ds:[ebx]
00466919 |. 83C0 02 |add eax,2
0046691C |. 83E8 30 |sub eax,30
0046691F |. BE 0A000000 |mov esi,0A
00466924 |. 99 |cdq
00466925 |. F7FE |idiv esi
00466927 |. 80C2 30 |add dl,30
0046692A |. 8853 01 |mov byte ptr ds:[ebx+1],dl
0046692D |. 41 |inc ecx
0046692E |. 43 |inc ebx
0046692F |. 83F9 07 |cmp ecx,7
00466932 |.^75 E1 \jnz short Five.00466915
00466934 |> B9 06000000 mov ecx,6 ;置计数长度为6
00466939 |. 8D85 D7FEFFFF lea eax,dword ptr ss:[ebp-129] ;取刚处理好的数据,即对注册名字符进行三次变换处理,EAX为数据的高地址
0046693F |> B2 06 /mov dl,6 ;固定长度
00466941 |. 2AD1 |sub dl,cl ;固定长度减计数长度DL-CL,CL=6,5,4,3,2,1
00466943 |. 03D2 |add edx,edx ;EDX+EDX 即(EDX-ECX)*2
00466945 |. 8D1452 |lea edx,dword ptr ds:[edx+edx*2] ;EDX=EDX+EDX*2
00466948 |. 8A18 |mov bl,byte ptr ds:[eax] ;取一个字符到BL
0046694A |. 02D3 |add dl,bl ;DL+BL
0046694C |. 8810 |mov byte ptr ds:[eax],dl ;存回原处
0046694E |. 8A10 |mov dl,byte ptr ds:[eax]
00466950 |. 80FA 7E |cmp dl,7E ;将DL+BL和7E(126)比较
00466953 |. 76 05 |jbe short Five.0046695A ;小于等于则转
00466955 |. 80EA 78 |sub dl,78 ;大于则减78(120)
00466958 |. 8810 |mov byte ptr ds:[eax],dl ;存回原处
0046695A |> 8A10 |mov dl,byte ptr ds:[eax]
0046695C |. 80FA 21 |cmp dl,21 ;再和21(33)比较
0046695F |. 73 05 |jnb short Five.00466966 ;不小于则转
00466961 |. 80C2 21 |add dl,21 ;小于则加上21(33)
00466964 |. 8810 |mov byte ptr ds:[eax],dl ;存回原处
00466966 |> 49 |dec ecx ;长度减1
00466967 |. 48 |dec eax ;存放地址减1
00466968 |. 85C9 |test ecx,ecx
0046696A |.^75 D3 \jnz short Five.0046693F
0046696C |. C685 D8FEFFFF 00 mov byte ptr ss:[ebp-128],0
00466973 |. C605 7C9A4700 01 mov byte ptr ds:[479A7C],1 ;注册标志预先置1,为1注册成功
0046697A |. B9 06000000 mov ecx,6 ;置比较计数
0046697F |. 8D85 D2FEFFFF lea eax,dword ptr ss:[ebp-12E] ;取处理好的数据,从低地址开始取,EAX为数据的低地址首址
00466985 |. 8D95 37FFFFFF lea edx,dword ptr ss:[ebp-C9] ;EDX为输入的注册码字符串首址,它要将注册名处理后的数据和注册码进行比较!
0046698B |> 8A18 /mov bl,byte ptr ds:[eax] ;取一个处理好的数据
0046698D |. 3A1A |cmp bl,byte ptr ds:[edx] ;和一个注册码相比较
0046698F |. 74 09 |je short Five.0046699A ;相等则继续比较,看得出来,最后变换处理出来的数据就是注册码啦!
00466991 |. C605 7C9A4700 00 |mov byte ptr ds:[479A7C],0 ;不相等则清注册标志
00466998 |. EB 05 |jmp short Five.0046699F
0046699A |> 42 |inc edx
0046699B |. 40 |inc eax
0046699C |. 49 |dec ecx
0046699D |.^75 EC \jnz short Five.0046698B
0046699F |> 33C0 xor eax,eax
004669A1 |. 5A pop edx
004669A2 |. 59 pop ecx
004669A3 |. 59 pop ecx
004669A4 |. 64:8910 mov dword ptr fs:[eax],edx
004669A7 |. 68 C4694600 push Five.004669C4
004669AC |> 8D85 C8FDFFFF lea eax,dword ptr ss:[ebp-238]
004669B2 |. BA 02000000 mov edx,2
004669B7 |. E8 A4D1F9FF call Five.00403B60 ;这里应该是对输入的注册码进行校验,以防爆破破解
004669BC \. C3 retn
到此,记下“abcdef”的处理数据“`YRA:3”,退出调试程序。
打开Five.exe,在“注册名”框内输入abcdef,在“注册码”框内输入`YRA:3,
点“注册”,“恭喜你已经成功注册!”。
破解成功,心里甚喜,虽然算法很简单,但毕竟这是我的第一个实例破解啊!
我要从这里开始飞向光明之巅!
【破解总结】
这个软件算法很简单,就是将输入的注册名经过三次变换,而变换的结果就是注册码。
第一步变换,是将输入的注册名的ASCII码除以10取余,再将余数转换成ASCII码,再加1:
d=a%10+30+1。
第二步变换,是以注册名字符串的长度为一固定值减去以注册名字符串的长度作计数后的值,
所得值再乘以2,然后加到第一步变换得的数值上,得到第二次值:
d=d+(c-(c-n))*2 即d=d+(c-n)*2(n=6,5,4,3,2,1)
第三步变换,是以注册名字符串的长度为一固定值减去以注册名字符串的长度作计数后的值,
所得值乘以2,再将所得值乘以2加上其本身,然后再加上第二步变换得的数值,和第二步差不多:
d=d+(c-n)*2+((c-n)*2)*2(n=6,5,4,3,2,1)
第三步变换所得的结果就是程序的注册码了。附件:Five.rar
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!