呵呵,这是本人的第一篇破文,不妥之处在所难免,希望诸位大虾看后笑得声音小一点。

软件名称:zillions
编程语言:vc
运行环境:Win9x/NT/2000/XP 
保护措施:启动时注册号效验  
注册费用:14刀 
软件介绍:老美写的一个游戏集锦,集成了各个国家地区的小游戏,包括中国象棋、韩国版的中国象棋(改得面目全非),国象,奥赛罗,还有其他一些民间益智游戏,共计40多种,还支持自己编写游戏,二人对战,聊天等等。当然,其中的大一点的游戏,象棋类,反应速度还是很慢的,估计算法不是很好,但小游戏还是蛮有趣的。
下载地址:不详,我是从d盘中找的,不知道官方网站还支持否。
未注册限制 :启动时弹出提示窗口,不能编制自己的游戏。
破解工具:olldbg/win32dasm
我的e-mail:whb123628@sohu.com


    记得大概是03年,我从图书馆看到看雪兄写的第一本书,用极大的篇幅介绍sice,但光盘里并没有。便傻愣愣的跑到论坛来问哪儿能弄到sice。当时,雪兄的回答是,没必要非得用sice,可以用olldbg代替。我哪儿明白这个?心想:靠,这不是敷衍俺们初学者吗?加之,乱七八糟的事儿一多,就把破解这回事儿给忘了。今年夏天闲来无事,玩起了这个小游戏,也就想到了破解。参考着论坛的文章,就开始了……
  我先使用sice(win2k下),设了getwindowtexta,点注册时拦倒是拦下了,可往后再按F12时候,跳来跳去的俺就晕了。靠,动态跟不行,就来静态分析,弄开w32dasm,导入,串式参考,找到that is not a valid key,双击来到:

0040E0F8  |.  E8 A8710400   CALL Zillions.004552A5
0040E0FD  |.  8BCE          MOV ECX,ESI
0040E0FF  |.  E8 6CFDFFFF   CALL Zillions.0040DE70    ;;关键call
0040E104  |.  391E          CMP DWORD PTR DS:[ESI],EBX
0040E106  |.  74 11         JE SHORT Zillions.0040E119    ;;关键跳转

0040E108  |.  6A 30         PUSH 30
0040E10A  |.  68 2C734800   PUSH Zillions.0048732C                   ;  ASCII "Sorry!"
0040E10F  |.  68 BC724800   PUSH Zillions.004872BC                   ;  ASCII "That is not a valid unlock key.  Please make               sure your name and key are typed exactly as on the registration."
0040E114  |.  E9 4D010000   JMP Zillions.0040E266

  看到JE SHORT Zillions.0040E119没,为啥说是关键跳转呢?顺藤摸瓜到40e119处一看能知道,只要来到40e119,往下不管再怎么跳,总会是一个比较不错的结果,象是什么“already registered","thanks for registration"之类的;而如果不跳,那就只有死路一条:“当”的一声,然后对你说sorry。那关键的跳转找到了,暴力破解?可是改成jne后呢,是弹出注册成功了,但再次打开后,却告诉你已经在另一台机器注册了。这下俺又晕了(看官:怎么这么容易晕呢?回答:因为俺是菜鸟啊!)
  说到这儿,场外的老鸟可能会不耐烦地:你小子傻吗?它重开之后,还会再次检测序列号的,不对就跳到别处了。呵呵,老鸟息怒,这个道理俺也是后来才明白过来。俺相信,肯定有不少像俺一样初学破解的人,对整个过程充满疑问,为什么这个call是关键的?为什么不用这个方法?这样行不行?……所以,俺尽可能把思路说一下,包括不成功的。因为,俺也是试了好几种办法,才摸到门的。老鸟,不行,您先出去透透气儿?
  又有人要问:说到这儿,你还没跟主题挂钩呢?不错,俺这篇东东是吹olldbg,俺之所以这么写,主要是实事求是。也是想告诉您,其实以上用w32dasm所做的,用olldbg也可以完全代替,包括那些文字都是从olldbg里copy来的,w32dasm有此功能吗?没找到。详细的,你可以参考精华5中bjstan等的文章,俺就是从那儿入门的。对了要注意的就是,在选项--〉调试设置---〉异常中最好是把所有的钩都画上。否则会不断地因为异常中断,俺到这儿时,又晕了半天才发现这个窍门的。
  好的,以下开始olldbg:载入文件,F9运行,弹出对话框,确定,来到程序。来到olldbg,ALT+c,到代码窗口,ctr+g,输入0040E0FF,来到那个靠,看看到底靠什么?双击代码设上断点。回到zillion,help--〉unlock full version,重新输入name或key,(否则不判断的),按ok,拦下,F7跟入call,来到:

0040DE70  /$  81EC 04010000 SUB ESP,104
0040DE76  |.  53            PUSH EBX
0040DE77  |.  8B59 04       MOV EBX,DWORD PTR DS:[ECX+4]

  (此处略去几百字)
0040DE92  |.  BD 99F0F502   MOV EBP,2F5F099           ;;最后结果就在ebp中
  (此处略去几百字)

0040DEAD  |.  8BFB          MOV EDI,EBX                                      
0040DEAF  |.  83C9 FF       OR ECX,FFFFFFFF          
0040DEB2  |.  F2:AE         REPNE SCAS BYTE PTR ES:[EDI]
0040DEB4  |.  F7D1          NOT ECX
0040DEB6  |.  49            DEC ECX                                          ;  ;前四句算name的长度,是0的话跳走
0040DEB7  |.  74 2A         JE SHORT Zillions.0040DEE3
                       ;第一种算法:
0040DEB9  |>  69ED 34BC6A61 /IMUL EBP,EBP,616ABC34        
0040DEBF  |.  0FBE4C14 14   |MOVSX ECX,BYTE PTR SS:[ESP+EDX+14]              ;  每次循环取名字的一位,我的是'whb',下边小窗口
0040DEC4  |.  81C5 FFDEF302 |ADD EBP,2F3DEFF          能看到'w'
0040DECA  |.  8BFB          |MOV EDI,EBX                                     ;  ;'whb'
0040DECC  |.  81F5 7622E21D |XOR EBP,1DE22276
0040DED2  |.  33C0          |XOR EAX,EAX
0040DED4  |.  03E9          |ADD EBP,ECX                                     ;  ecx:the asc2 of 'w'
0040DED6  |.  83C9 FF       |OR ECX,FFFFFFFF
0040DED9  |.  42            |INC EDX                                         ;  ;计数器
0040DEDA  |.  F2:AE         |REPNE SCAS BYTE PTR ES:[EDI]                    
0040DEDC  |.  F7D1          |NOT ECX
0040DEDE  |.  49            |DEC ECX                                         ;上三句经典组合,计算'whb'长度
0040DEDF  |.  3BD1          |CMP EDX,ECX
0040DEE1  |.^ 72 D6         \JB SHORT Zillions.0040DEB9                      ;  ;rep 3 times
0040DEE3  |>  8B5424 10     MOV EDX,DWORD PTR SS:[ESP+10]         ;DWORD PTR SS:[ESP+10]:输入的sn
0040DEE7  |.  33C0          XOR EAX,EAX
0040DEE9  |.  396A 08       CMP DWORD PTR DS:[EDX+8],EBP                     ;  ;compare sn and ebp
0040DEEC  |.  0F94C0        SETE AL                                          
0040DEEF  |.  85C0          TEST EAX,EAX              
0040DEF1  |.  75 5D         JNZ SHORT Zillions.0040DF50           ;前四句,经典组合,判断你的注册码和他的是否同
0040DEF3  |.  8BFB          MOV EDI,EBX                                      
0040DEF5  |.  83C9 FF       OR ECX,FFFFFFFF
0040DEF8  |.  33F6          XOR ESI,ESI
0040DEFA  |.  BD 99F0F502   MOV EBP,2F5F099
0040DEFF  |.  F2:AE         REPNE SCAS BYTE PTR ES:[EDI]
0040DF01  |.  F7D1          NOT ECX
0040DF03  |.  49            DEC ECX
0040DF04  |.  74 3C         JE SHORT Zillions.0040DF42
                       ;第二种算法:
0040DF06  |>  0FBE5434 14   /MOVSX EDX,BYTE PTR SS:[ESP+ESI+14]              ;  'w'=0x77
0040DF0B  |.  52            |PUSH EDX
0040DF0C  |.  E8 1D8B0200   |CALL Zillions.00436A2E           ;把得到的asc码-0x20
0040DF11  |.  69ED 34BC6A61 |IMUL EBP,EBP,616ABC34                           ;  ;eax<--0x57
0040DF17  |.  81C5 FFDEF302 |ADD EBP,2F3DEFF
0040DF1D  |.  83C4 04       |ADD ESP,4
0040DF20  |.  81F5 7622E21D |XOR EBP,1DE22276
0040DF26  |.  83C9 FF       |OR ECX,FFFFFFFF
0040DF29  |.  03E8          |ADD EBP,EAX                                     
0040DF2B  |.  8B4424 10     |MOV EAX,DWORD PTR SS:[ESP+10]
0040DF2F  |.  46            |INC ESI
0040DF30  |.  8B78 04       |MOV EDI,DWORD PTR DS:[EAX+4]               
0040DF33  |.  33C0          |XOR EAX,EAX
0040DF35  |.  F2:AE         |REPNE SCAS BYTE PTR ES:[EDI]
0040DF37  |.  F7D1          |NOT ECX
0040DF39  |.  49            |DEC ECX
0040DF3A  |.  3BF1          |CMP ESI,ECX
0040DF3C  |.^ 72 C8         \JB SHORT Zillions.0040DF06                      
0040DF3E  |.  8B5424 10     MOV EDX,DWORD PTR SS:[ESP+10]
0040DF42  |>  8B72 08       MOV ESI,DWORD PTR DS:[EDX+8]                    
0040DF45  |.  33C0          XOR EAX,EAX
0040DF47  |.  3BF5          CMP ESI,EBP
0040DF49  |.  0F94C0        SETE AL
0040DF4C  |.  85C0          TEST EAX,EAX
0040DF4E  |.  74 07         JE SHORT Zillions.0040DF57
0040DF50  |>  8BCA          MOV ECX,EDX
0040DF52  |.  E8 F9FEFFFF   CALL Zillions.0040DE50
0040DF57  |>  5F            POP EDI
0040DF58  |.  5E            POP ESI
0040DF59  |.  5D            POP EBP
0040DF5A  |.  5B            POP EBX
0040DF5B  |.  81C4 04010000 ADD ESP,104
0040DF61  \.  C3            RETN

  注意到代码前那两个大括号没?代表了两个循环体那!当俺看到这里时,心里顿时凉了起来(夏天嘛,天热),舒服!稍微看一下代码,感觉结构差不多,再联想到,注册框中说的两种注册方式,这不就是代表了两种不同的算法吗?什么?汇编不好,没关系!结合olldbg的窗口,可以在其中做注释,猜也猜个差不多,不象sice,还得不停的d。右上角是寄存器,右下角是堆栈。左下角是内存,左上是代码,二者之间部分,能看到正在处理的数据。根据ebp中数据的变化得到第一种注册码是这么算出来的:regcode=(regcode)*0x616ABC34+0x2F3DEFF)^(0x1DE22276)+名字的各位asc码
第二种和第一种类似,只不过:regcode=(regcode)*0x616ABC34+0x2F3DEFF)^(0x1DE22276)+名字的各位asc码-0x20
  
  说到这儿,我又忍不住要吹一下olldbg:根据帮助文档(我的是1.04版),这款好用的东东是共享软件,所谓共享,其实就是向作者邮箱发一封e-mail提提意见,也就是不要钱,这与小可”有饭大家吃“的思想不谋而合。作者的这种敬业的精神也令人钦佩。都说trw与sice比肩,是国人的骄傲。不知道何时我们能有象olldbg这样的好东东,集静态分析,动态跟踪,编辑修改于一身,令众多的共享工具几于无用武之地。

附上注册机:(在vc6.0带的c编译器下通过)
#include "stdio.h" 
#include "string.h" 
main() 

char name[80]; 
int i; 
unsigned long regcode=0; 
printf("\n\n\n**********keygen of zillions, made by whb603**********\n"); 
printf("\n\nPlease input your name:"); 
gets(name); 
regcode=0x2F5F099;
for(i=0;name[i]!='\0';i++) 
{
  regcode=((regcode*0x616ABC34)+0x2F3DEFF)^(0x1DE22276);
  regcode+=name[i];
}
printf("\nThe regcode is:%u\n",regcode);  //注意:不是%d
regcode=0x2F5F099;
for(i=0;name[i]!='\0';i++) 
{
  regcode=((regcode*0x616ABC34)+0x2F3DEFF)^(0x1DE22276);
  regcode+=name[i]-32;
}
printf("\nAnother regcode is:%u\n\n\n",regcode);  //注意:不是%d
}
  最后,俺又要照应题目,吹一下olldbg,等一下……场外有人嘀咕:罗罗嗦嗦,真他妈唐僧!鸡蛋,矿泉水瓶,香蕉皮等铺天盖地而至……还是闪吧:-)。

10:44 2005-8-13