• 标 题:Kalua Cocktails 1.1完全破解,内附汇编注册机(用注册机编写器,并有它的使用教程) (22千字)
  • 作 者:Sam.com
  • 时 间:2002-2-27 23:54:55
  • 链 接:http://bbs.pediy.com

Kalua Cocktails 1.1完全破解,内附汇编注册机(用注册机编写器,并有它的使用教程)

软件名称: Kalua Cocktails 1.1
下载地址:ftp://ftp.gekkosoft.com/pub/kalua11.exe

软件简介:
        是一套教你如何调配鸡尾酒的食谱软件。这套软件收录超过1100种鸡尾酒调法,并且都附有图片说明每种鸡尾酒所含的酒精浓度和调配鸡尾酒所要购买的配料,且支持打印功能,可让你将调配鸡尾酒所需的配料打印出来,方便采购这些配料。此外,也提供输入配料来调配鸡尾酒的功能,可以自行输入配料,程序便会自动帮配料调配出哪些种类的鸡尾酒供你参考。

软件限制:未注册只可查阅100种鸡尾酒,每次退出会提示注册.注册后可查阅1000多种酒
破解原因:我是做饮食服务业的,它对我有用,可惜是E文的

  程序是用Delphi编的,Shrinker v3.4加的壳,因为这几天都在想写注册机的事,我记不起如何找到下面代码了,反正程序可以用Procdump脱壳,用Dede载入,找到注册窗口的OK按键反汇编,然后用Trw200拦截,用S命令查找输入的假信息,再用bpm设断点,细心一点就能找到了.学破解以来我一直在用Trw,但是此程序最后查表时用到了浮点运算,我用了Trw的FPU插件,可是到运算指令前一用就死机了,不知有人成功过吗,逼得我在ME里装了Ice.

    这个程序的加密方法还不算很难,起码可以逆运算来获得注册码,但这个已经是我破解生涯中最难的一个了,因为它是将注册名和注册码变形来比较的,看到的都是乱七八糟的16进制数在内存中转来转去,一不留意就搞错了.破了它以后想到写个注册机,可以提高自己的水平嘛,为此我可充电了好几天啊,在此也要谢谢"注册机编写器"的作者,他在他的论坛上回答了我的不少问题,教会了我不少东西,另外还要谢谢看雪论坛!!

    提醒一句,纸和笔也是破解时的重要工具!

==SN Start==================================
这里是我输入的假注册码的变形,并不复杂,而且是可逆的,就是看到如此简单我才想到要写注册机,但当我搞清楚了注册名的变形后,发现这里根本就不重要.最后得到的结果不管它,生点在下面.
公式如下:

设假注册码前12位Xor C后的数据如下
S1 S2 S3 S4 S5 S6 S7 S8 S9 S10 S11 S12

S1 xor S12 = Y1
S2 xor Y1  = Y2
.
.
S12 xor Y11=Y12

0187:004743F3  MOV      EDX,0C
0187:004743F8  LEA      EAX,[ESP+01]
0187:004743FC  MOV      CL,[EAX]    <----注册码的第一位
0187:004743FE  XOR      CL,0C        <----将它Xor C
0187:00474401  MOV      [EAX],CL    <----放回原位
0187:00474403  INC      EAX
0187:00474404  DEC      EDX
0187:00474405  JNZ      004743FC    <----这里取12位,再长的注册码也是如此

0187:00474407  MOV      AL,[ESP+01]  <----变形后的第一位
0187:0047440B  XOR      AL,[ESP+0C]  <----与最后一位相Xor
0187:0047440F  MOV      [ESP+01],AL  <----放到第一位
0187:00474413  MOV      EDX,0B
0187:00474418  LEA      EAX,[ESP+02]
0187:0047441C  MOV      CL,[EAX]    <----变形后的第二位
0187:0047441E  XOR      CL,[EAX-01]  <----与再次变形后的第一位相Xor
0187:00474421  MOV      [EAX],CL    <----保存在第二位
0187:00474423  INC      EAX
0187:00474424  DEC      EDX
0187:00474425  JNZ      0047441C
==SN End=====================================

==Step 1=====================================
以下是注册名的变形,很长,要有耐性.除了我特别声明,下面的数都是16进制的.
我输入的是注册名是www.Sam.com

0167:0047449D  LEA      EAX,[ESP+12]  <-----eax指向注册名的首地址
0167:004744A1  XOR      ECX,ECX
0167:004744A3  MOV      CL,[EAX]      <-----注册名首位"w"放入ecx
0167:004744A5  ADD      EDI,ECX      <-----edi为0
0167:004744A7  INC      EAX
0167:004744A8  DEC      EDX          <-----edx是注册名的位数
0167:004744A9  JNZ      004744A1      <-----往上跳,这里其实是将注册名的每一位依次相加,结果放入edi
0167:004744AB  MOV      EAX,EDI
0167:004744AD  MOV      ECX,FF
0167:004744B2  CDQ   
0167:004744B3  IDIV    ECX          <-----上面相加的结果除以FF
0167:004744B5  MOV      EDI,EDX      <-----余数放到edi,这个数很重要,记住它,我这里是25,设为Z1
0167:004744B7  LEA      EAX,[ESP+84]
0167:004744BE  PUSH    EAX
0167:004744BF  LEA      EDX,[ESP+15]
0167:004744C3  LEA      EAX,[ESP+FC]

==Step 2======================================
下面的是一个Call内的内容,留意一下之前程序在内存里产生了一个字符串"Kalua2000Kal",下面就是将注册名加上此后缀,变为"www.Sam.comKalua2000Kal",然后取12位进行运算,即为"www.Sam.comK",这里我没把代码贴齐,只要留意一下就能看到的.

0167:00402CC0  PUSH    ESI
0167:00402CC1  PUSH    EDI
0167:00402CC2  MOV      EDI,EAX
0167:00402CC4  XOR      EAX,EAX
0167:00402CC6  MOV      AL,[EDI]
0167:00402CC8  MOV      ESI,EDX
0167:00402CCA  XOR      EDX,EDX
0167:00402CCC  MOV      DL,[ESI]
0167:00402CCE  INC      ESI
0167:00402CCF  ADD      AL,DL
0167:00402CD1  JC      00402CE5
0167:00402CD3  CMP      AL,CL
0167:00402CD5  JA      00402CE5
0167:00402CD7  MOV      ECX,EDX
0167:00402CD9  MOV      DL,[EDI]
0167:00402CDB  MOV      [EDI],AL
0167:00402CDD  INC      EDI
0167:00402CDE  ADD      EDI,EDX
0167:00402CE0  REP MOVSB
0167:00402CE2  POP      EDI
0167:00402CE3  POP      ESI
0167:00402CE4  RET

==Step 3====================================   
这里才是重要的,注册名在这里开始要变化了,怎样变我很难表达,反正结果如下(注意此时注册名为12位的"www.Sam.comK"):

w  w  w  .  S  a  m  .  c  o  m  K          K  w  m  w  o  w  c  .  .  S  m  a
|  |  |  |  |  |  |  |  |  |  |  |    ===>  |  |  |  |  |  |  |  |  |  |  |  |
1  2  3  4  5  6  7  8  9  10 11 12        12 1  11 2  10 3  9  4  8  5  7  6

我们得到字符串"Kwmwowc..Sma"

0167:00474518  MOV      EBX,01
0167:0047451D  LEA      EAX,[ESP+12]
0167:00474521  MOV      ECX,EBX
0167:00474523  ADD      ECX,ECX
0167:00474525  DEC      ECX
0167:00474526  MOV      EDX,0D
0167:0047452B  SUB      EDX,EBX
0167:0047452D  MOV      DL,[ESP+EDX+11]
0167:00474531  MOV      [ESP+ECX+76],DL
0167:00474535  MOV      DL,[EAX]
0167:00474537  MOV      [ESP+ECX+77],DL
0167:0047453B  INC      EBX
0167:0047453C  INC      EAX
0167:0047453D  CMP      EBX,BYTE +07
0167:00474540  JNZ      00474521

==Step 4=====================================
这步也比较复杂,用"Kalua2000Kal"和"Kwmwowc..Sma"两个字符串进行运算,运算完后在内存里就看不到明码的东西了.运算的公式如下:
K  w  m  w  o  w  c  .  .  S  m  a
|  |  |  |  |  |  |  |  |  |  |  |
A1  A2  A3  A4  A5  A6  A7  A8  A9  A10 A11 A12

K  a  l  u  a  2  0  0  0  K  a  l
|  |  |  |  |  |  |  |  |  |  |  |
B1  B2  B3  B4  B5  B6  B7  B8  B9  B10 B11 B12

A1+B1=T1
A2+Z1=T2
T1+T2=T3
T3÷FF==>edx==C1

A2+B2=T1
A3+Z2=T2
T1+T2=T3
T3÷FF==>edx==C2
.
.
.
A12+B12=T1
T1+Z2=T3
T3÷FF==>edx==C12

最后得到一组数据:
33 E2 5B DD 39 75 8D 86 D9 87 19 18

0167:00474551  MOV      EBX,01        <----计数器
0167:00474556  LEA      ESI,[ESP+12]  <----指向"Kwmwowc..Sma"
0167:0047455A  LEA      EBP,[ESP+05]  <----指向"Kalua2000Kal"
0167:0047455E  XOR      ECX,ECX
0167:00474560  MOV      CL,[ESI]      <----ecx="K"
0167:00474562  XOR      EAX,EAX
0167:00474564  MOV      AL,[EBP+00]    <----eax="K"
0167:00474567  ADD      ECX,EAX        <----"K"+"K"结果设为T1
0167:00474569  CMP      EBX,BYTE +0C  <----如果到了第12位就跳
0167:0047456C  JNL      00474575
0167:0047456E  XOR      EAX,EAX
0167:00474570  MOV      AL,[ESI+01]    <----eax="w"
0167:00474573  ADD      EDI,EAX        <----edi=25,结果设为T2,25是Step 1里的结果,edi是累加的结果,设为Z2
0167:00474575  ADD      ECX,EDI        <----两个结果相加T1+T2=T3,如果是第12位就免了上面一步
0167:00474577  MOV      EAX,ECX
0167:00474579  MOV      ECX,FF
0167:0047457E  CDQ   
0167:0047457F  IDIV    ECX            <----T3除以FF,余数=edx=C1
0167:00474581  MOV      ECX,EDX
0167:00474583  CMP      ECX,BYTE +01
0167:00474586  JNL      0047458E
0167:00474588  ADD      ECX,FF        <----如果余数小于1就加上FF
0167:0047458E  MOV      [ESI],CL      <----将余数保存
0167:00474590  INC      EBX
0167:00474591  INC      EBP
0167:00474592  INC      ESI
0167:00474593  CMP      EBX,BYTE +0D
0167:00474596  JNZ      0047455E      <----这里循环完后指向"Kwmwowc..Sma"的地址就保存了变形后的数据


下面的代码是否很眼熟,其实它和Step 3是一样的,得到的数据再次移位,得到另一组数据:
18 33 19 E2 87 5B D9 DD 86 39 8D 75

0167:00474598  MOV      EBX,01
0167:0047459D  LEA      EAX,[ESP+12]
0167:004745A1  MOV      ECX,EBX
0167:004745A3  ADD      ECX,ECX
0167:004745A5  DEC      ECX
0167:004745A6  MOV      EDX,0D
0167:004745AB  SUB      EDX,EBX
0167:004745AD  MOV      DL,[ESP+EDX+11]
0167:004745B1  MOV      [ESP+ECX+76],DL
0167:004745B5  MOV      DL,[EAX]
0167:004745B7  MOV      [ESP+ECX+77],DL
0167:004745BB  INC      EBX
0167:004745BC  INC      EAX
0167:004745BD  CMP      EBX,BYTE +07
0167:004745C0  JNZ      004745A1

==Step 5=========================================
这里是核心部分了,下面其实是一个查表的过程,用上面得到的数据逐位查表,得到的字符就和真正的注册码差不多了.不过程序用了浮点运算,为了搞清楚它我还查了不少资料.

0167:004745D1  MOV      EBX,09
0167:004745D6  LEA      EDI,[ESP+12]    <----指向上面的数据18 33 19 E2 87 5B D9 DD 86 39 8D 75
0167:004745DA  LEA      ESI,[ESP+77]
0167:004745DE  XOR      ECX,ECX
0167:004745E0  MOV      CL,[EDI]        <----ecx=18,这里查第1位
0167:004745E2  MOV      EDX,1A          <----这个1A也是个重要的东西,记住它
0167:004745E7  MOV      EAX,ECX
0167:004745E9  CALL    0047432C        <----这个Call里很多浮点运算,核心部分,下有解释(Main Call)
0167:004745EE  MOV      ECX,EAX        <----ecx<==eax=17,这个数就是我们想要的了
0167:004745F0  MOV      EAX,00474724    <----eax指向字符串"abcdefghijklmnopqrstuvwxyz"
0167:004745F5  MOV      AL,[EAX+ECX-01] <----查表得eax="w",注意这里的17是16进制的,十进制是23,其实就是指26个英文字母的第23位

0167:004745F9  MOV      [ESI],AL        <----保存结果
0167:004745FB  CMP      BYTE [005A424C],00  <---光标运行到此句时下d esi就可看到查到的字符,逐位把它记下来,我得到的是"wsxrkpoqj"

0167:00474602  JZ      0047460A
0167:00474604  MOV      AL,[ESI]
0167:00474606  XOR      AL,0C          <----这里是不是也很眼熟,查到的字符马上被Xor了
0167:00474608  MOV      [ESI],AL
0167:0047460A  INC      ESI
0167:0047460B  INC      EDI
0167:0047460C  DEC      EBX            <----ebx是计数器,这里只查了前9位
0167:0047460D  JNZ      004745DE

0167:0047460F  MOV      EBX,03          <----下面是查后3位的
0167:00474614  LEA      EDI,[ESP+1B]
0167:00474618  LEA      ESI,[ESP+80]
0167:0047461F  XOR      ECX,ECX
0167:00474621  MOV      CL,[EDI]
0167:00474623  MOV      EDX,0A          <----这个换成A了
0167:00474628  MOV      EAX,ECX
0167:0047462A  CALL    0047432C
0167:0047462F  MOV      ECX,EAX
0167:00474631  MOV      EAX,00474748
0167:00474636  MOV      AL,[EAX+ECX-01]
0167:0047463A  MOV      [ESI],AL
0167:0047463C  CMP      BYTE [005A424C],00  <----这里再下d esi,得到"951"
0167:00474643  JZ      0047464B
0167:00474645  MOV      AL,[ESI]
0167:00474647  XOR      AL,0C
0167:00474649  MOV      [ESI],AL
0167:0047464B  INC      ESI
0167:0047464C  INC      EDI
0167:0047464D  DEC      EBX
0167:0047464E  JNZ      0047461F
呵!好累,这一大段其实我们得到了一个字符串"wsxrkpoqj951",不过马上被Xor C了,所以得到了:
7B 7F 74 7E 67 7C 63 7D 66 35 39 3D
~~~~~~~~                  ````````

0167:00474650  LEA      EAX,[ESP+016C]
0167:00474657  PUSH    EAX
0167:00474658  MOV      ECX,03
0167:0047465D  MOV      EDX,01
0167:00474662  LEA      EAX,[ESP+7A]
0167:00474666  CALL    0040291C
0167:0047466B  LEA      EDX,[ESP+016C]
0167:00474672  LEA      EAX,[ESP+017C]
0167:00474679  CALL    00402CF0
0167:0047467E  LEA      EAX,[ESP+0198]
0167:00474685  PUSH    EAX
0167:00474686  MOV      ECX,03
0167:0047468B  MOV      EDX,0A
0167:00474690  LEA      EAX,[ESP+7A]
0167:00474694  CALL    0040291C
0167:00474699  LEA      EDX,[ESP+0198]
0167:004746A0  LEA      EAX,[ESP+017C]
0167:004746A7  MOV      CL,18
0167:004746A9  CALL    00402CC0
0167:004746AE  LEA      EDX,[ESP+017C]
0167:004746B5  LEA      EAX,[ESP+01A8]
0167:004746BC  CALL    00402CF0
0167:004746C1  LEA      EAX,[ESP+0198]
0167:004746C8  PUSH    EAX
0167:004746C9  MOV      ECX,06
0167:004746CE  MOV      EDX,04
0167:004746D3  LEA      EAX,[ESP+7A]
0167:004746D7  CALL    0040291C
0167:004746DC  LEA      EDX,[ESP+0198]
0167:004746E3  LEA      EAX,[ESP+01A8]
0167:004746EA  MOV      CL,24
0167:004746EC  CALL    00402CC0
0167:004746F1  LEA      EDX,[ESP+01A8]
上面这段将刚才那组数据移来移去,过了这一条,d edx看看,它将上面数据的位置换了换,变成:
7B 7F 74 35 39 3D 7E 67 7C 63 7D 66
~~~~~~~~ ````````
也就是说我们查表最后得到的一个字符串是"wsx951rkpoqj",

==Step 6========================================
这里已经算是最后一步了,是不是发现下面的运算和最上面注册码的变形是一样的,其实对于我们来说这里已经不重要了,因为真正的注册码已经出现了只不过如果第一次调试时找不到这一步就根本找不到重点.因为程序在Step 5里得到的字符串"wsxrkpoqj951"每一位一出现就被Xor C,所以看不到明码,而且程序还将它的中间6位移到字串的最后,再经过下面运算的结果和我假注册码的变形相比较,所以马上可以断定"wsx951rkpoqj"就是我的真正注册码.

0167:00474407  MOV      AL,[ESP+01]
0167:0047440B  XOR      AL,[ESP+0C]
0167:0047440F  MOV      [ESP+01],AL
0167:00474413  MOV      EDX,0B
0167:00474418  LEA      EAX,[ESP+02]
0167:0047441C  MOV      CL,[EAX]
0167:0047441E  XOR      CL,[EAX-01]
0167:00474421  MOV      [EAX],CL
0167:00474423  INC      EAX
0167:00474424  DEC      EDX
==Step Over=====================================





下面是查表时核心Call的部分,关于浮点运算,可以查阅看雪的Crack Tutorial,因为我也不是很懂.
==Main Call=====================================
它的过程大概是这样的:
18  33  19  E2  87  5B  D9  DD  86  39  8D  75
|  |  |  |  |  |  |  |  |  |  |  |
D1  D2  D3  D4  D5  D6  D7  D8  D9  D10 D11 D12

D1除以40E00000  ==>ST(0)
求ST(0)的平方根  ==>ST(0)
ST(0)==>ST(1)
ST(0)取整
ST(0)-ST(1)      ==>ST(0)
ST(0)乘以1A(or A)==>ST(0)
ST(0)+3F800000  ==>ST(0)
ST(0)取整
如果看不懂,可以看看我写的注册机,我省略了很多无用的步骤,最好用ICE调试一下就能搞懂了


0167:0047432C  PUSH    EBX
0167:0047432D  PUSH    ESI
0167:0047432E  ADD      ESP,BYTE -14
0167:00474331  MOV      ESI,EDX
0167:00474333  MOV      EBX,EAX
0167:00474335  CALL    0040BBC8          <----这个Call不用理它,下面还有一个
写注册机时写到此我就被卡住了,因为此Call里调用了GetLocalTime的函数,还进行了一大堆的运算,可能是为了生成下面内存中的一些数据的,刚开始我还以为注册码会和时间相关,但搞清楚后基本确定生成注册码不用调用这个Call.


0167:0047433A  FSTP    QWORD [ESP+08]
0167:0047433E  WAIT   
0167:0047433F  MOV      [ESP+10],EBX      <----这里开始了,ebx=18,查第一位
0167:00474343  FILD    DWORD [ESP+10]    <----注意在ICE中看到的ST(i)中的数是10进制的,如此时ST(0)=24
0167:00474347  FSTP    QWORD [ESP]
0167:0047434A  WAIT   
0167:0047434B  FLD      QWORD [ESP]
0167:0047434E  FDIV    DWORD [004743B8]  <----[004743B8]里的值是40E00000,这个数是固定的,下面的[004743BC]都一样,程序还没进入这个Call时就已经是这个数了,所以做注册机时这两个地址的数据就很重要了

0167:00474354  FSQRT 
0167:00474356  FSTP    QWORD [ESP]
0167:00474359  WAIT   
0167:0047435A  FLD      QWORD [ESP]
0167:0047435D  CALL    00402C38          <----Call (1)
0167:00474362  MOV      [ESP+10],ESI      <----esi=1A,这个记得吧,如果是查后3位的话esi=A
0167:00474366  FILD    DWORD [ESP+10]
0167:0047436A  FMULP    ST1                <----因为用Trw的原故,这里显示不完整,写注册机时这里应写成fmulp st(1),st(0)
0167:0047436C  FADD    DWORD [004743BC]  <----[004743BC]=3F800000
0167:00474372  FSTP    QWORD [ESP]
0167:00474375  WAIT   
0167:00474376  FLD      QWORD [ESP]
0167:00474379  CALL    00402C10          <----Call (2)
0167:0047437E  FSTP    QWORD [ESP]
0167:00474381  WAIT   
0167:00474382  FLD      QWORD [ESP]
0167:00474385  CALL    00402C54          <----Call (3)
0167:0047438A  MOV      EBX,EAX            <----到这里eax已经是我们想要的17啦,暂放到ebx中
0167:0047438C  CALL    0040BBC8          <----Forgot it!
0167:00474391  FSUBR    QWORD [ESP+08]
0167:00474395  FSTP    QWORD [ESP+08]
0167:00474399  WAIT   
0167:0047439A  FLD      TWORD [004743C0]
0167:004743A0  FCOMP    QWORD [ESP+08]
0167:004743A4  FNSTSW  AX
0167:004743A6  SAHF   
0167:004743A7  JNC      004743AE
0167:004743A9  MOV      EBX,01
0167:004743AE  MOV      EAX,EBX            <----把17放回eax中,出了这个Call就用它来查表了
0167:004743B0  ADD      ESP,BYTE +14
0167:004743B3  POP      ESI
0167:004743B4  POP      EBX
0167:004743B5  RET   
==Call (1)========================================
0167:00402C38  FLD      ST0
0167:00402C3A  SUB      ESP,BYTE +04
0167:00402C3D  FSTCW    [ESP]
0167:00402C41  WAIT   
0167:00402C42  FLDCW    [005A2028]        <----[005A2028]=1F32
说明一下FSTCW和FLDCW命令,因为我在查这两个命令的资料时找不到详细的说明,搞不懂它们是怎么用的,后来经过我的实验才搞懂的.FSTCW [ESP]是将现在的浮点标志寄存器状态写入[ESP]中,浮点标志寄存器是用来控制浮点运算的舍入、精度之类的,它的状态会影响浮点运算结果的精确度,我这里写入的是1272,二进制是1001001110010,分别对应寄存器的各字段.而FLDCW则相反,它是将内存中的一个字写入到寄存器中,这样就可以按自己的要求来控制浮点运算的结果.这是我个人理解,请指正.

0167:00402C48  FRNDINT
0167:00402C4A  WAIT   
0167:00402C4B  FLDCW    [ESP]
0167:00402C4E  ADD      ESP,BYTE +04
0167:00402C51  FSUBP    ST1        <-----这个应为fsubp st(1),st(0)
0167:00402C53  RET   
==Call (2)========================================
0167:00402C10  SUB      ESP,BYTE +04
0167:00402C13  FSTCW    [ESP]
0167:00402C17  WAIT   
0167:00402C18  FLDCW    [005A2028]
0167:00402C1E  FRNDINT
0167:00402C20  WAIT   
0167:00402C21  FLDCW    [ESP]
0167:00402C24  ADD      ESP,BYTE +04
0167:00402C27  RET   
==Call (3)=========================================
0167:00402C54  SUB      ESP,BYTE +08
0167:00402C57  FISTP    QWORD [ESP]
0167:00402C5A  WAIT   
0167:00402C5B  POP      EAX
0167:00402C5C  POP      EDX
0167:00402C5D  RET   
==Call End=========================================

总结:累死了!已经太罗嗦了,把每个步骤前的说明加起来就是总结了.我怕论坛贴不完!呵呵~~~~~




~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
下面附上注册机,汇编写的,C语言我已经忘记了,我不知道这个注册机能否用C语言写出来,主要是指浮点运算那部分.当然我写得不好,基本上我是将机器码照搬上来的,我想应该可以写得更加简洁些.将下面的代码保存为*.rek文件,用注册机编写器(v1.51以上调试通过)打开,编译后就可以了,支持中文注册名.另外注册机编写器在编译的时候大家最好编译两次,如果我们改了源代码,只编译一次的话生成的文件和没改的一样,就算你把旧文件删掉也是如此,此问题我已向作者提出,希望他能改正.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

.data
szHomePage db "http://www.365hz.net",0
szEmail    db "mailto:ljyljx@mail.china.com",0
szErrMess  db "注册名不能大于34位!",0    ;/经过调试注册名大于34位后结果不正确
DATA1 db "Kalua2000Kal",0                ;/后缀字串
DATA2 db 50 dup(0)
DATA3 db 13 dup(0)
DATA4 db 0,0,0e0h,40h,0,0,80h,3fh        ;/[004743B8]和[004743BC]里的数据
DATA5 db "abcdefghijklmnopqrstuvwxyz",0  ;/两个表
DATA6 db "1234567890",0
DATA7 db 13 dup(0)
FDATA db 72h,12h,32h,1fh                  ;/浮点寄存器的状态
.code
mov esi,eax                ;/先将一些重要的数据保存
    invoke lstrlen,eax
    cmp eax,34
    jg ERR
    mov edx,eax
    mov ebx,eax
    mov eax,esi
    xor edi,edi

PRO1:
    xor ecx,ecx
    mov cl,[eax]            ;/Step 1
    add edi,ecx
    inc eax
    dec edx
    jnz PRO1
    mov eax,edi
    mov ecx,000000FFh
    cdq
    idiv ecx
    push edx                ;/保存结果
    mov eax,esi
    mov ecx,ebx
    lea edi,DATA2          ;/Step 2
    rep movsb
    lea esi,DATA1
    mov ecx,12
    rep movsb

    mov ebx,1              ;/Step 3
    lea eax,DATA2
    lea edi,DATA3
    mov esi,eax
PRO2:
    mov ecx,ebx
    add ecx,ecx
    dec ecx
    mov edx,12
    sub edx,ebx
    mov dl,byte ptr [esi+edx]
    mov [edi],dl
    mov dl,[eax]
    mov [edi+1],dl
    inc ebx
    inc eax
    add edi,2
    cmp ebx,7
    jnz PRO2

    mov ebx,1              ;/Step 4
    lea esi,DATA3
    lea ebp,DATA1
    pop edi                ;/Step 1中的结果
PRO3:
    xor ecx,ecx
    mov cl,[esi]
    xor eax,eax
    mov al,byte ptr [ebp]
    add ecx,eax
    cmp ebx,12
    jnl PRO4
    xor eax,eax
    mov al,byte ptr [esi+1]
    add edi,eax
PRO4:
    add ecx,edi
    mov eax,ecx
    mov ecx,000000FFh
    cdq
    idiv ecx
    mov ecx,edx
    cmp ecx,1
    jnl PRO5
    add ecx,000000FFh
PRO5:
    mov [esi],cl
    inc ebx
    inc ebp
    inc esi
    cmp ebx,13
    jnz PRO3

    mov ebx,1
    lea eax,DATA3
    lea edi,DATA2
    mov esi,eax
PRO6:
    mov ecx,ebx
    add ecx,ecx
    dec ecx
    mov edx,12
    sub edx,ebx
    mov dl,byte ptr [esi+edx]
    mov [edi],dl
    mov dl,[eax]
    mov [edi+1],dl
    inc ebx
    inc eax
    add edi,2
    cmp ebx,7
    jnz PRO6          ;/这里完成Step 4得到我们要的查表数据放在DATA2中

    mov ebx,9          ;/PRO7和PRO8分别查表
    lea edi,DATA2
    lea esi,DATA3
PRO7:
    xor ecx,ecx
    mov cl,byte ptr [edi]
    mov edx,0000001Ah   
    call Sam
    lea eax,DATA5
    mov al,byte ptr [eax+ecx-1]
    mov [esi],byte ptr al
    inc esi
    inc edi
    dec ebx
    jnz PRO7
   
    mov ebx,3
    lea edi,DATA2+9
    lea esi,DATA3+9
PRO8:
    xor ecx,ecx
    mov cl,byte ptr [edi]
    mov edx,0000000Ah
    call Sam
    lea eax,DATA6
    mov al,byte ptr [eax+ecx-1]
    mov [esi],byte ptr al
    inc esi
    inc edi
    dec ebx
    jnz PRO8

    lea esi,DATA3        ;/将查表后的注册码摆好位置
    lea edi,DATA7
    mov ecx,3
    rep movsb
    lea esi,DATA3+9
    mov ecx,3
    rep movsb
    lea esi,DATA3+3
    mov ecx,6
    rep movsb
    lea eax,DATA7
    jmp PRO9

Sam:
    push ebp          ;/这里保存现场,为了这个子程序,我的机死了n次,主要是不懂保存
    mov ebp,esp        ;/现场,下面三个push如果去掉也会出错,调试一下就知
    push ebx
    push edi
    push esi
    push 0            ;/这里push了两个0因为下面要用到qword
    push 0
    mov [esp],ecx
    lea eax,FDATA
    fldcw [eax]          ;/因为在破解时程序在运行浮点运算前的浮点寄存器状态是1272H,
    fild dword ptr [esp] ;/而我试过注册机运行时的状态不同,为了保证注册机的准确性,所
    fstp qword ptr [esp] ;/以尽量让注册机与原程序的寄存器状态保持一致
    fld qword ptr [esp]
    lea eax,DATA4
    fdiv dword ptr [eax]
    fsqrt
    fstp qword ptr [esp]
    fld qword ptr [esp]
    fld st
    lea eax,FDATA
    fldcw [eax+2]
    frndint
    fldcw [eax]
    fsubp st(1),st(0)  ;/这个开始我写成fsubp st1,st 因为我在Trw中U出来的是
    mov [esp],edx      ;/FSUBP ST1,害我查了很久书
    fild dword ptr [esp]
    fmulp st(1),st(0)
    lea eax,DATA4
    fadd dword ptr [eax+4]
    fstp qword ptr [esp]
    fld qword ptr [esp]
    lea eax,FDATA
    fldcw [eax+2]
    frndint
    fldcw [eax]
    fstp qword ptr [esp]
    fld qword ptr [esp]
    fistp qword ptr [esp]
    pop ecx
    pop ebx   
    ret 0              ;/这里返回一定要加0,不然就~~~~~

ERR:
    lea eax,szErrMess
PRO9:




      _/_/_/
    _/          _/_/_/  _/_/_/  _/_/
    _/_/    _/    _/  _/    _/    _/
        _/  _/    _/  _/    _/    _/
_/_/_/      _/_/_/  _/    _/    _/

                                                  Sam.com
                                                18:34 2002-2-27