• 标 题:来篇恶心的:) (30千字)
  • 作 者:bbbsl
  • 时 间:2003-4-6 18:51:06
  • 链 接:http://bbs.pediy.com

还原精灵2003 单机版(我不知道网络版啥样,听说有狗狗???)算法分析

作者:    bbbsl[iPB]

工具:    ollydbg<我喜欢边听音乐边...^_*,用trw也可以听,不过只能听CD了:(...>

目的:    得到安装序列号!!!^_^

软件介绍:    还原精灵是南京远志公司推出的新型纯软件版硬盘还原工具。

它可以保护您的硬盘免受病毒侵害,重新恢复删除或覆盖的文件,彻底清除安装失败的程序,并避免由于系统死机带来的数据丢失等问题。只需

简单的几步安装,即可安全地保护您的硬盘数据。还原精灵的安装不会影响硬盘分区和操作系统。轻松安装、动态保护、实时瞬间恢复。

还原精灵采用新的内核技术,安装时由软件动态分配保留空间,无须预先设置其位置和大小,从而能够最大限度的利用硬盘空间。


前言:

    来段废话,DiKeN同志说让我以iPB成员的身份写一篇文章,我找不到变态的题材(关键是太变态的偶不是搞不定,就是没法写--

,嘿嘿,没办法,一拖再拖...),这次我朋友的机房要安装还原精灵,不过同一网络不能用一个序列号,所以让我写个KeyGen,偶一看,哇.....代码够变态够

恶心,所以就有了此文,在这里感谢这两年培育我茁壮成长的各位领导(DiKeN,peterchen...)还有各位FCG、iPB和OCN的兄弟们,特别是upfeed和

黑哥,感谢当初百忙之中和我聊天,嘿嘿,NOW,LET'S GO...

这儿是算法用到的数据:

convert_table[]={
    0x18 , 0x23 , 0x22 , 0x25 , 0x05 , 0x07 , 0x19 ,0x08 ,
    0x11 , 0x1E , 0x0D , 0x31 , 0x2C , 0x1B , 0x09 ,0x20 ,
    0x24 , 0x35 , 0x02 , 0x2F , 0x12 , 0x2E , 0x1F , 0x0B ,
    0x17 , 0x0F , 0x2B , 0x03 , 0x0E , 0x0A , 0x1D , 0x34 ,
    0x0C , 0x00 , 0x29 ,0x2A , 0x2D , 0x01 , 0x04 , 0x1A ,
    0x1C , 0x33 , 0x32 , 0x30 , 0x15 , 0x06 , 0x14 , 0x27 ,
    0x16 , 0x36 , 0x13 , 0x21 , 0x10 , 0x28 , 0x26 , 0x37
};
reverse_table[]={
    '0x21' , '0x25' , '0x12' , '0x1B' , '0x26' , '0x04' , '0x2D' , '0x05',
    '0x07' , '0x0E' , '0x1D' , '0x17' , '0x20' , '0x0A' , '0x1C' , '0x19',
    '0x34' , '0x08' , '0x14' , '0x32' , '0x2E' , '0x2C' , '0x30' , '0x18',
    '0x00' , '0x06' , '0x27' , '0x0D' , '0x28' , '0x1E' , '0x09' , '0x16',
    '0x0F' , '0x33' , '0x02' , '0x01' , '0x10' , '0x03' , '0x36' , '0x2F',
    '0x35' , '0x22' , '0x23' , '0x1A' , '0x0C' , '0x24' , '0x15' , '0x13',
    '0x2B' , '0x0B' , '0x2A' , '0x29' , '0x1F' , '0x11' , '0x31' , '0x37'
};
BASE_data[]={
    '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' ,
    'J' , 'K' , 'L' , 'M' , 'N' , 'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z'
};

主要算法从这里开始:
(1) 取序列号的后12个字母,查表BASE_data,得到12个字节变量,存放入ESP+14开始的缓冲区中,结果设为TEMP_L3W[12];

0040F258  /MOV DL,BYTE PTR DS:[ESI+EDI+14]
0040F25C  |MOV ECX,ESI
0040F25E  |PUSH EDX
0040F25F  |CALL SETUP.0040FB70                    ;  find the char in the table
0040F264  |MOV BYTE PTR SS:[ESP+EDI+14],AL
0040F268  |INC EDI
0040F269  |CMP EDI,0C
0040F26C  \JL SHORT SETUP.0040F258

(2) 用BASE32处理得到的12字节变量TEMP_L3W[]生成8 DWORD的数组,设为BASE_OUT_L3W;
     
      我自己起的BASE32,天知道应该叫啥,主要规则是上面查表得到的12字节变量每个有5位有效位,然后5位5位的连起来,组成12*5/8=7个
     
      DWORD变量,然后拿第12个变量直接赋给第8个DWORD变量;
     
0040F26E  MOV AL,BYTE PTR SS:[ESP+15]              ;  BASE32 routine
0040F272  MOV DL,BYTE PTR SS:[ESP+14]    ;ESP+14开始的缓冲区中存放着查表得到的12字节变量
0040F276  MOV CL,AL
0040F278  PUSH EBP
0040F279  OR CL,0E3
0040F27C  SHL DL,3
0040F27F  SAR CL,2
0040F282  OR DL,7
0040F285  AND CL,DL            ;
0040F287  MOV DL,BYTE PTR SS:[ESP+1A]
0040F28B  MOV BYTE PTR SS:[ESP+10],CL    ;NO.1
0040F28F  MOV CL,BYTE PTR SS:[ESP+1B]
0040F293  MOV BL,CL
0040F295  SHL DL,1
0040F297  OR BL,0EF
0040F29A  OR DL,0C1
0040F29D  SAR BL,4
0040F2A0  SHL AL,6
0040F2A3  AND DL,BL
0040F2A5  OR AL,3F
0040F2A7  AND DL,AL
0040F2A9  MOV AL,BYTE PTR SS:[ESP+1C]
0040F2AD  MOV BYTE PTR SS:[ESP+11],DL    ;NO.2
0040F2B1  MOV DL,AL
0040F2B3  OR DL,0E1
0040F2B6  SHL CL,4
0040F2B9  SAR DL,1
0040F2BB  OR CL,0F
0040F2BE  AND DL,CL
0040F2C0  MOV CL,BYTE PTR SS:[ESP+1D]
0040F2C4  SHL CL,2
0040F2C7  SHL AL,7
0040F2CA  OR CL,83
0040F2CD  OR AL,7F
0040F2CF  AND CL,AL
0040F2D1  MOV AL,BYTE PTR SS:[ESP+1E]
0040F2D5  MOV BYTE PTR SS:[ESP+12],DL    ;NO.3
0040F2D9  MOV DL,AL
0040F2DB  OR DL,0E7
0040F2DE  SAR DL,3
0040F2E1  AND CL,DL
0040F2E3  MOV BYTE PTR SS:[ESP+13],CL    ;NO.4
0040F2E7  MOV CL,BYTE PTR SS:[ESP+1F]
0040F2EB  SHL AL,5
0040F2EE  OR AL,1F
0040F2F0  OR CL,0E0
0040F2F3  AND AL,CL
0040F2F5  MOV CL,BYTE PTR SS:[ESP+20]
0040F2F9  MOV BYTE PTR SS:[ESP+14],AL    ;NO.5
0040F2FD  MOV AL,BYTE PTR SS:[ESP+21]
0040F301  MOV DL,AL
0040F303  OR DL,0E3
0040F306  SHL CL,3
0040F309  SAR DL,2
0040F30C  OR CL,7
0040F30F  AND DL,CL
0040F311  MOV CL,BYTE PTR SS:[ESP+23]
0040F315  MOV BYTE PTR SS:[ESP+15],DL    ;NO.6
0040F319  MOV DL,BYTE PTR SS:[ESP+22]
0040F31D  MOV BL,CL
0040F31F  MOV BYTE PTR SS:[ESP+17],CL    ;NO.8--直接把TEMP_L3W[11]放入第8个
0040F323  SHL DL,1
0040F325  OR BL,0EF
0040F328  OR DL,0C1
0040F32B  SAR BL,4
0040F32E  SHL AL,6
0040F331  AND DL,BL
0040F333  OR AL,3F
0040F335  AND DL,AL
0040F337  MOV EAX,DWORD PTR SS:[ESP+10]
0040F33B  MOV BYTE PTR SS:[ESP+16],DL    ;NO.7
0040F33F  MOV EDX,DWORD PTR SS:[ESP+14]
0040F343  AND ECX,0F              ;12字节中最后一个的数值与0xF相与作为循环右移计数器
0040F346  MOV DWORD PTR DS:[ESI+4],EAX
0040F349  MOV DWORD PTR DS:[ESI+8],EDX
0040F34C  JLE SETUP.0040F6A6          ;如果计数器为零则跳过循环

(4) BASE32得到的7字节数--BASE_OUT_L3W[0]-BASE_OUT_L3W[6](7字节而不是8字节,最后一个字节不参与运算)看成两个双字,会循环

    右移N次(N==(12字节中最后一个的数值与0xF相与的结果))
     
      靠,这代码太垃圾了N长的代码
   
0040F352  MOV EDI,DWORD PTR SS:[ESP+38]
0040F356  MOV EBP,ECX
0040F358  /MOV ECX,DWORD PTR DS:[ESI+4]            ;  ROR routine
0040F35B  |MOV EAX,ECX
0040F35D  |XOR EAX,EDI
0040F35F  |AND EAX,1
0040F362  |XOR EDI,EAX                  ;保存最后一位
0040F364  |MOV EAX,ECX
0040F366  |SHR EAX,1
0040F368  |AND EAX,1
0040F36B  |AND ECX,FFFFFFFE            ;往下就是不断的右移过程
0040F36E  |OR EAX,ECX
0040F370  |MOV ECX,EAX
0040F372  |AND AL,0FD
0040F374  |SHR ECX,1
0040F376  |AND ECX,2
0040F379  |OR ECX,EAX
0040F37B  |MOV EAX,ECX
0040F37D  |AND ECX,FFFFFFFB
0040F380  |SHR EAX,1
0040F382  |AND EAX,4
0040F385  |OR EAX,ECX
0040F387  |MOV ECX,EAX
0040F389  |AND AL,0F7
0040F38B  |SHR ECX,1
0040F38D  |AND ECX,8
0040F390  |OR ECX,EAX
0040F392  |MOV EAX,ECX
0040F394  |AND ECX,FFFFFFEF
0040F397  |SHR EAX,1
0040F399  |AND EAX,10
0040F39C  |OR EAX,ECX
0040F39E  |MOV ECX,EAX
0040F3A0  |AND AL,0DF
0040F3A2  |SHR ECX,1
0040F3A4  |AND ECX,20
0040F3A7  |OR ECX,EAX
0040F3A9  |MOV EAX,ECX
0040F3AB  |AND ECX,FFFFFFBF
0040F3AE  |SHR EAX,1
0040F3B0  |AND EAX,40
0040F3B3  |OR EAX,ECX
0040F3B5  |MOV ECX,EAX
0040F3B7  |AND AL,7F
0040F3B9  |SHR ECX,1
0040F3BB  |AND ECX,80
0040F3C1  |OR ECX,EAX
0040F3C3  |MOV EAX,ECX
0040F3C5  |AND CH,0FE
0040F3C8  |SHR EAX,1
0040F3CA  |AND EAX,100
0040F3CF  |OR EAX,ECX
0040F3D1  |MOV ECX,EAX
0040F3D3  |AND AH,0FD
0040F3D6  |SHR ECX,1
0040F3D8  |AND ECX,200
0040F3DE  |OR ECX,EAX
0040F3E0  |MOV EAX,ECX
0040F3E2  |AND CH,0FB
0040F3E5  |SHR EAX,1
0040F3E7  |AND EAX,400
0040F3EC  |OR EAX,ECX
0040F3EE  |MOV ECX,EAX
0040F3F0  |AND AH,0F7
0040F3F3  |SHR ECX,1
0040F3F5  |AND ECX,800
0040F3FB  |OR ECX,EAX
0040F3FD  |MOV EAX,ECX
0040F3FF  |AND CH,0EF
0040F402  |SHR EAX,1
0040F404  |AND EAX,1000
0040F409  |OR EAX,ECX
0040F40B  |MOV ECX,EAX
0040F40D  |AND AH,0DF
0040F410  |SHR ECX,1
0040F412  |AND ECX,2000
0040F418  |OR ECX,EAX
0040F41A  |MOV EAX,ECX
0040F41C  |AND CH,0BF
0040F41F  |SHR EAX,1
0040F421  |AND EAX,4000
0040F426  |OR EAX,ECX
0040F428  |MOV ECX,EAX
0040F42A  |SHR ECX,1
0040F42C  |AND ECX,8000
0040F432  |AND AH,7F
0040F435  |OR ECX,EAX
0040F437  |MOV EDX,DWORD PTR DS:[ESI+8]        ;第二个双字
0040F43A  |MOV EAX,ECX
0040F43C  |AND ECX,FFFEFFFF
0040F442  |SHR EAX,1
0040F444  |AND EAX,10000
0040F449  |OR EAX,ECX
0040F44B  |MOV ECX,EAX
0040F44D  |AND EAX,FFFDFFFF
0040F452  |SHR ECX,1
0040F454  |AND ECX,20000
0040F45A  |OR ECX,EAX
0040F45C  |MOV EAX,ECX
0040F45E  |AND ECX,FFFBFFFF
0040F464  |SHR EAX,1
0040F466  |AND EAX,40000
0040F46B  |OR EAX,ECX
0040F46D  |MOV ECX,EAX
0040F46F  |AND EAX,FFF7FFFF
0040F474  |SHR ECX,1
0040F476  |AND ECX,80000
0040F47C  |OR ECX,EAX
0040F47E  |MOV EAX,ECX
0040F480  |AND ECX,FFEFFFFF
0040F486  |SHR EAX,1
0040F488  |AND EAX,100000
0040F48D  |OR EAX,ECX
0040F48F  |MOV ECX,EAX
0040F491  |AND EAX,FFDFFFFF
0040F496  |SHR ECX,1
0040F498  |AND ECX,200000
0040F49E  |OR ECX,EAX
0040F4A0  |MOV EAX,ECX
0040F4A2  |AND ECX,FFBFFFFF
0040F4A8  |SHR EAX,1
0040F4AA  |AND EAX,400000
0040F4AF  |OR EAX,ECX
0040F4B1  |MOV ECX,EAX
0040F4B3  |AND EAX,FF7FFFFF
0040F4B8  |SHR ECX,1
0040F4BA  |AND ECX,800000
0040F4C0  |OR ECX,EAX
0040F4C2  |MOV EAX,ECX
0040F4C4  |AND ECX,FEFFFFFF
0040F4CA  |SHR EAX,1
0040F4CC  |AND EAX,1000000
0040F4D1  |OR EAX,ECX
0040F4D3  |MOV ECX,EAX
0040F4D5  |AND EAX,FDFFFFFF
0040F4DA  |SHR ECX,1
0040F4DC  |AND ECX,2000000
0040F4E2  |OR ECX,EAX
0040F4E4  |MOV EAX,ECX
0040F4E6  |AND ECX,FBFFFFFF
0040F4EC  |SHR EAX,1
0040F4EE  |AND EAX,4000000
0040F4F3  |OR EAX,ECX
0040F4F5  |MOV ECX,EAX
0040F4F7  |AND EAX,F7FFFFFF
0040F4FC  |SHR ECX,1
0040F4FE  |AND ECX,8000000
0040F504  |OR ECX,EAX
0040F506  |MOV EAX,ECX
0040F508  |AND ECX,EFFFFFFF
0040F50E  |SHR EAX,1
0040F510  |AND EAX,10000000
0040F515  |OR EAX,ECX
0040F517  |MOV ECX,EAX
0040F519  |AND EAX,DFFFFFFF
0040F51E  |SHR ECX,1
0040F520  |AND ECX,20000000
0040F526  |OR ECX,EAX
0040F528  |MOV EAX,ECX
0040F52A  |AND ECX,3FFFFFFF
0040F530  |SHR EAX,1
0040F532  |AND EAX,40000000
0040F537  |OR EAX,ECX
0040F539  |MOV ECX,EDX                ;第二个双字的第一位参与运算
0040F53B  |SHL ECX,1F
0040F53E  |OR EAX,ECX                ;赋给右移后的第一个字节最高位
0040F540  |MOV DWORD PTR DS:[ESI+4],EAX        ;保存一个...
0040F543  |MOV EAX,EDX
0040F545  |SHR EAX,1
0040F547  |AND EAX,1
0040F54A  |AND EDX,FFFFFFFE
0040F54D  |OR EAX,EDX
0040F54F  |MOV ECX,EAX
0040F551  |AND AL,0FD
0040F553  |SHR ECX,1
0040F555  |AND ECX,2
0040F558  |OR ECX,EAX
0040F55A  |MOV EAX,ECX
0040F55C  |AND ECX,FFFFFFFB
0040F55F  |SHR EAX,1
0040F561  |AND EAX,4
0040F564  |OR EAX,ECX
0040F566  |MOV ECX,EAX
0040F568  |AND AL,0F7
0040F56A  |SHR ECX,1
0040F56C  |AND ECX,8
0040F56F  |OR ECX,EAX
0040F571  |MOV EAX,ECX
0040F573  |AND ECX,FFFFFFEF
0040F576  |SHR EAX,1
0040F578  |AND EAX,10
0040F57B  |OR EAX,ECX
0040F57D  |MOV ECX,EAX
0040F57F  |AND AL,0DF
0040F581  |SHR ECX,1
0040F583  |AND ECX,20
0040F586  |OR ECX,EAX
0040F588  |MOV EAX,ECX
0040F58A  |AND ECX,FFFFFFBF
0040F58D  |SHR EAX,1
0040F58F  |AND EAX,40
0040F592  |OR EAX,ECX
0040F594  |MOV ECX,EAX
0040F596  |AND AL,7F
0040F598  |SHR ECX,1
0040F59A  |AND ECX,80
0040F5A0  |OR ECX,EAX
0040F5A2  |MOV EAX,ECX
0040F5A4  |AND CH,0FE
0040F5A7  |SHR EAX,1
0040F5A9  |AND EAX,100
0040F5AE  |OR EAX,ECX
0040F5B0  |MOV ECX,EAX
0040F5B2  |AND AH,0FD
0040F5B5  |SHR ECX,1
0040F5B7  |AND ECX,200
0040F5BD  |OR ECX,EAX
0040F5BF  |MOV EAX,ECX
0040F5C1  |AND CH,0FB
0040F5C4  |SHR EAX,1
0040F5C6  |AND EAX,400
0040F5CB  |OR EAX,ECX
0040F5CD  |MOV ECX,EAX
0040F5CF  |AND AH,0F7
0040F5D2  |SHR ECX,1
0040F5D4  |AND ECX,800
0040F5DA  |OR ECX,EAX
0040F5DC  |MOV EAX,ECX
0040F5DE  |AND CH,0EF
0040F5E1  |SHR EAX,1
0040F5E3  |AND EAX,1000
0040F5E8  |OR EAX,ECX
0040F5EA  |MOV ECX,EAX
0040F5EC  |AND AH,0DF
0040F5EF  |SHR ECX,1
0040F5F1  |AND ECX,2000
0040F5F7  |OR ECX,EAX
0040F5F9  |MOV EAX,ECX
0040F5FB  |AND CH,0BF
0040F5FE  |SHR EAX,1
0040F600  |AND EAX,4000
0040F605  |OR EAX,ECX
0040F607  |MOV ECX,EAX
0040F609  |SHR ECX,1
0040F60B  |AND ECX,8000
0040F611  |AND AH,7F
0040F614  |OR ECX,EAX
0040F616  |MOV EAX,ECX
0040F618  |AND ECX,FFFEFFFF
0040F61E  |SHR EAX,1
0040F620  |AND EAX,10000
0040F625  |OR EAX,ECX
0040F627  |MOV ECX,EAX
0040F629  |AND EAX,FFFDFFFF
0040F62E  |SHR ECX,1
0040F630  |AND ECX,20000
0040F636  |OR ECX,EAX
0040F638  |MOV EAX,ECX
0040F63A  |AND ECX,FFFBFFFF
0040F640  |SHR EAX,1
0040F642  |AND EAX,40000
0040F647  |OR EAX,ECX
0040F649  |MOV ECX,EAX
0040F64B  |AND EAX,FFF7FFFF
0040F650  |SHR ECX,1
0040F652  |AND ECX,80000
0040F658  |OR ECX,EAX
0040F65A  |MOV EAX,ECX
0040F65C  |AND ECX,FFEFFFFF
0040F662  |SHR EAX,1
0040F664  |AND EAX,100000
0040F669  |OR EAX,ECX
0040F66B  |MOV ECX,EAX
0040F66D  |AND EAX,FFDFFFFF
0040F672  |SHR ECX,1
0040F674  |AND ECX,200000
0040F67A  |OR ECX,EAX
0040F67C  |MOV EAX,EDI            ;最开始保存的那一位
0040F67E  |MOV EDX,ECX
0040F680  |AND EAX,1
0040F683  |SHR EDX,1
0040F685  |AND EDX,400000
0040F68B  |AND ECX,FF3FFFFF
0040F691  |SHL EAX,17            ;存到这个双字的第0X17位
0040F694  |OR EDX,EAX
0040F696  |OR EDX,ECX
0040F698  |DEC EBP
0040F699  |MOV DWORD PTR DS:[ESI+8],EDX    ;保存另一个
0040F69C  \JNZ SETUP.0040F358        ;循环N次完毕否???


//好可怕的代码...就上面一段就看了一小时...

(5) 利用converse_table进行运算,得到reverse_table...

0040F6A2  MOV DWORD PTR SS:[ESP+38],EDI
0040F6A6  XOR ECX,ECX
0040F6A8  MOV EAX,SETUP.0043DC90
0040F6AD  /MOV EDX,DWORD PTR DS:[EAX]
0040F6AF  |ADD EAX,4
0040F6B2  |MOV DWORD PTR SS:[ESP+EDX*4+40],ECX
0040F6B6  |INC ECX
0040F6B7  |CMP EAX,SETUP.0043DD70
0040F6BC  \JL SHORT SETUP.0040F6AD        //这个循环负责生成reverse_table..
0040F6BE  MOV EAX,DWORD PTR DS:[ESI+4]
0040F6C1  MOV ECX,DWORD PTR DS:[ESI+8]
0040F6C4  OR EDX,FFFFFFFF
0040F6C7  MOV DWORD PTR SS:[ESP+10],EAX
0040F6CB  MOV DWORD PTR SS:[ESP+18],EDX
0040F6CF  LEA EAX,DWORD PTR SS:[ESP+40]
0040F6D3  MOV DWORD PTR SS:[ESP+14],ECX
0040F6D7  MOV DWORD PTR SS:[ESP+1C],EDX
0040F6DB  XOR EBP,EBP
0040F6DD  MOV DWORD PTR SS:[ESP+24],EAX

(6) 对BASE_OUT_L3W进行类似DES的56 bit 的选择,不过具体选择的参照表不同,并且位选择的方法也是别别扭扭:)
   
    (拿出两个DWORD,先置两个的值为-1(即0XFFFFFFFF),然后只使用第一个的4字节和第二个的3字节,最后
   
    一个字节不变,始终为0XFF)生成结果

0040F6E1  /MOV ECX,DWORD PTR SS:[ESP+24]          ;  56 bit select
0040F6E5  |MOV EAX,DWORD PTR DS:[ECX]
0040F6E7  |MOV EDI,EAX
0040F6E9  |AND EDI,80000007
0040F6EF  |JNS SHORT SETUP.0040F6F6
0040F6F1  |DEC EDI
0040F6F2  |OR EDI,FFFFFFF8
0040F6F5  |INC EDI
0040F6F6  |CDQ
0040F6F7  |AND EDX,7
0040F6FA  |MOV ECX,EBP
0040F6FC  |ADD EAX,EDX
0040F6FE  |MOV EBX,EAX
0040F700  |MOV EAX,EBP
0040F702  |CDQ
0040F703  |AND EDX,7
0040F706  |ADD EAX,EDX
0040F708  |SAR EBX,3
0040F70B  |SAR EAX,3
0040F70E  |AND ECX,80000007
0040F714  |JNS SHORT SETUP.0040F71B
0040F716  |DEC ECX
0040F717  |OR ECX,FFFFFFF8
0040F71A  |INC ECX
0040F71B  |MOV AL,BYTE PTR SS:[ESP+EAX+10]
0040F71F  |SAR AL,CL
0040F721  |MOV ECX,EDI
0040F723  |OR AL,0FE
0040F725  |SHL AL,CL                ;FT,0 bit not 1 bit makes result...
0040F727  |CMP EDI,1
0040F72A  |JL SHORT SETUP.0040F72E
0040F72C  |OR AL,1
0040F72E  |CMP EDI,2
0040F731  |JL SHORT SETUP.0040F735
0040F733  |OR AL,2
0040F735  |CMP EDI,3
0040F738  |JL SHORT SETUP.0040F73C
0040F73A  |OR AL,4
0040F73C  |CMP EDI,4
0040F73F  |JL SHORT SETUP.0040F743
0040F741  |OR AL,8
0040F743  |CMP EDI,5
0040F746  |JL SHORT SETUP.0040F74A
0040F748  |OR AL,10
0040F74A  |CMP EDI,6
0040F74D  |JL SHORT SETUP.0040F751
0040F74F  |OR AL,20
0040F751  |CMP EDI,7
0040F754  |JL SHORT SETUP.0040F758
0040F756  |OR AL,40
0040F758  |LEA ECX,DWORD PTR SS:[ESP+EBX+18]
0040F75C  |MOV BL,BYTE PTR SS:[ESP+EBX+18]
0040F760  |AND BL,AL
0040F762  |INC EBP
0040F763  |MOV BYTE PTR DS:[ECX],BL
0040F765  |MOV ECX,DWORD PTR SS:[ESP+24]
0040F769  |ADD ECX,4
0040F76C  |CMP EBP,38
0040F76F  |MOV DWORD PTR SS:[ESP+24],ECX
0040F773  \JL SETUP.0040F6E1                      ;  56bit选择

(7) 从下面这里开始就是序列号的判断了,首先是判断上面结果,首先是看BASE_OUT_L3W第55bit(0为基数),要求是其余55bit的和(就是55个
   
    1 or 0加起来^_*)的最后一位与第55bit相同
   
    (看下面的代码,主要目的只是求所有位的值之和)
   
0040F779  MOV EDX,DWORD PTR SS:[ESP+18]
0040F77D  MOV EAX,DWORD PTR SS:[ESP+1C]
0040F781  MOV DWORD PTR DS:[ESI+4],EDX
0040F784  MOV DWORD PTR DS:[ESI+8],EAX
0040F787  MOV ECX,DWORD PTR DS:[ESI+8]
0040F78A  MOV EAX,DWORD PTR DS:[ESI+4]
0040F78D  MOV EDX,ECX
0040F78F  MOV EDI,ECX
0040F791  SHR EDI,15
0040F794  SHR EDX,16
0040F797  ADD EDX,EDI
0040F799  MOV EDI,ECX
0040F79B  SHR EDI,14
0040F79E  ADD EDX,EDI
0040F7A0  MOV EDI,ECX
0040F7A2  SHR EDI,13
0040F7A5  ADD EDX,EDI
0040F7A7  MOV EDI,ECX
0040F7A9  SHR EDI,12
0040F7AC  ADD EDX,EDI
0040F7AE  MOV EDI,ECX
0040F7B0  SHR EDI,11
0040F7B3  ADD EDX,EDI
0040F7B5  MOV EDI,ECX
0040F7B7  SHR EDI,10
0040F7BA  ADD EDX,EDI
0040F7BC  MOV EDI,ECX
0040F7BE  SHR EDI,0F
0040F7C1  ADD EDX,EDI
0040F7C3  MOV EDI,ECX
0040F7C5  SHR EDI,0E
0040F7C8  ADD EDX,EDI
0040F7CA  MOV EDI,ECX
0040F7CC  SHR EDI,0D
0040F7CF  ADD EDX,EDI
0040F7D1  MOV EDI,ECX
0040F7D3  SHR EDI,0C
0040F7D6  ADD EDX,EDI
0040F7D8  MOV EDI,ECX
0040F7DA  SHR EDI,0B
0040F7DD  ADD EDX,EDI
0040F7DF  MOV EDI,ECX
0040F7E1  SHR EDI,0A
0040F7E4  ADD EDX,EDI
0040F7E6  MOV EDI,ECX
0040F7E8  SHR EDI,9
0040F7EB  ADD EDX,EDI
0040F7ED  MOV EDI,ECX
0040F7EF  SHR EDI,8
0040F7F2  ADD EDX,EDI
0040F7F4  MOV EDI,ECX
0040F7F6  SHR EDI,7
0040F7F9  ADD EDX,EDI
0040F7FB  MOV EDI,ECX
0040F7FD  SHR EDI,6
0040F800  ADD EDX,EDI
0040F802  MOV EDI,ECX
0040F804  SHR EDI,5
0040F807  ADD EDX,EDI
0040F809  MOV EDI,ECX
0040F80B  SHR EDI,4
0040F80E  ADD EDX,EDI
0040F810  MOV EDI,ECX
0040F812  SHR EDI,3
0040F815  ADD EDX,EDI
0040F817  MOV EDI,ECX
0040F819  SHR EDI,2
0040F81C  ADD EDX,EDI
0040F81E  MOV EDI,ECX
0040F820  SHR EDI,1
0040F822  ADD EDX,EDI
0040F824  MOV EDI,EAX
0040F826  SHR EDI,1F
0040F829  ADD EDX,EDI
0040F82B  MOV EDI,EAX
0040F82D  SHR EDI,1E
0040F830  ADD EDX,EDI
0040F832  MOV EDI,EAX
0040F834  SHR EDI,1D
0040F837  ADD EDX,EDI
0040F839  MOV EDI,EAX
0040F83B  SHR EDI,1C
0040F83E  ADD EDX,EDI
0040F840  MOV EDI,EAX
0040F842  SHR EDI,1B
0040F845  ADD EDX,EDI
0040F847  MOV EDI,EAX
0040F849  SHR EDI,1A
0040F84C  ADD EDX,EDI
0040F84E  MOV EDI,EAX
0040F850  SHR EDI,19
0040F853  ADD EDX,EDI
0040F855  MOV EDI,EAX
0040F857  SHR EDI,18
0040F85A  ADD EDX,EDI
0040F85C  MOV EDI,EAX
0040F85E  SHR EDI,17
0040F861  ADD EDX,EDI
0040F863  MOV EDI,EAX
0040F865  SHR EDI,16
0040F868  ADD EDX,EDI
0040F86A  MOV EDI,EAX
0040F86C  SHR EDI,15
0040F86F  ADD EDX,EDI
0040F871  MOV EDI,EAX
0040F873  SHR EDI,14
0040F876  ADD EDX,EDI
0040F878  MOV EDI,EAX
0040F87A  SHR EDI,13
0040F87D  ADD EDX,EDI
0040F87F  MOV EDI,EAX
0040F881  SHR EDI,12
0040F884  ADD EDX,EDI
0040F886  MOV EDI,EAX
0040F888  SHR EDI,11
0040F88B  ADD EDX,EDI
0040F88D  MOV EDI,EAX
0040F88F  SHR EDI,10
0040F892  ADD EDX,EDI
0040F894  MOV EDI,EAX
0040F896  SHR EDI,0F
0040F899  ADD EDX,EDI
0040F89B  MOV EDI,EAX
0040F89D  SHR EDI,0E
0040F8A0  ADD EDX,EDI
0040F8A2  MOV EDI,EAX
0040F8A4  SHR EDI,0D
0040F8A7  ADD EDX,EDI
0040F8A9  MOV EDI,EAX
0040F8AB  SHR EDI,0C
0040F8AE  ADD EDX,EDI
0040F8B0  MOV EDI,EAX
0040F8B2  SHR EDI,0B
0040F8B5  ADD EDX,EDI
0040F8B7  MOV EDI,EAX
0040F8B9  SHR EDI,0A
0040F8BC  ADD EDX,EDI
0040F8BE  MOV EDI,EAX
0040F8C0  SHR EDI,9
0040F8C3  ADD EDX,EDI
0040F8C5  MOV EDI,EAX
0040F8C7  SHR EDI,8
0040F8CA  ADD EDX,EDI
0040F8CC  MOV EDI,EAX
0040F8CE  SHR EDI,7
0040F8D1  ADD EDX,EDI
0040F8D3  MOV EDI,EAX
0040F8D5  SHR EDI,6
0040F8D8  ADD EDX,EDI
0040F8DA  MOV EDI,EAX
0040F8DC  SHR EDI,5
0040F8DF  ADD EDX,EDI
0040F8E1  MOV EDI,EAX
0040F8E3  SHR EDI,4
0040F8E6  ADD EDX,EDI
0040F8E8  MOV EDI,EAX
0040F8EA  SHR EDI,3
0040F8ED  ADD EDX,EDI
0040F8EF  MOV EDI,EAX
0040F8F1  SHR EDI,2
0040F8F4  ADD EDI,ECX
0040F8F6  MOV EBX,EAX
0040F8F8  SHR EBX,1
0040F8FA  ADD EDI,EDX
0040F8FC  POP EBP
0040F8FD  ADD EBX,EDI
0040F8FF  ADD EBX,EAX
0040F901  SHR ECX,17
0040F904  AND EBX,1
0040F907  AND ECX,1
0040F90A  XOR EBX,ECX
0040F90C  JNZ SETUP.0040FB5D    //判断第55bit是否符合要求

(8) 下面是其余bit的判断,首先把我们输入的序列号的前8个查表BASE_data,得到两个双字

0040F912  XOR EDI,EDI
0040F914  /MOV AL,BYTE PTR DS:[ESI+EDI+C]
0040F918  |MOV ECX,ESI
0040F91A  |PUSH EAX
0040F91B  |CALL SETUP.0040FB70
0040F920  |MOV BYTE PTR SS:[ESP+EDI+C],AL
0040F924  |INC EDI
0040F925  |CMP EDI,8
0040F928  \JL SHORT SETUP.0040F914

(9) 先把由序列号第二个框的4个字母变成的DWORD进行处理,首先DWORD的每个BYTE的和设为BYTE1,然后求每个BYTE相异或得到的数设为
   
    BYTE2,然后用0XD-(BYTE1%0XD) 得到BYTE3,形成一个新的DWORD,theLaw (内存中的表现为 BYTE1 BYTE2 BYTE3 0X0),而序列号
   
    前4个字节同样得到的DWORD设为theRule,位判断具体要求如下:
                
    theRule        H_BASE_OUT_L3W        (BASE_OUT_L3W[1])
    
    12-14        0-2            ==
    18-1c        3-7            ==
    
    theLaw        H_BASE_OUT_L3W        (BASE_OUT_L3W[1])
    
        0-4        8-c            ==
    8-c        d-11            ==
    10-14        12-16            ==
    
    
    theRule        L_BASE_OUT_L3W        (BASE_OUT_L3W[0])
    
    0-4        14-18            ==
    8-c        19-1d            ==
    10        1e            ==
            1f            ==0
    可以看到,BASE_OUT_L3W[1]的除了0XFF以外的所有BIT都经过判断了,但是BASE_OUT_L3W[0]却还有20BIT没有判断,我开始猜可能有安装
   
    后有隐藏的判断,但是做出KEYGEN后安装后一直没报错??? :(

0040F92A  MOV CL,BYTE PTR SS:[ESP+13]              ;  last routine to check result
0040F92E  MOV DL,BYTE PTR SS:[ESP+12]
0040F932  MOVSX EAX,CL
0040F935  MOVSX EDI,DL
0040F938  MOV BL,BYTE PTR SS:[ESP+10]
0040F93C  ADD EAX,EDI
0040F93E  MOVSX EDI,BYTE PTR SS:[ESP+11]
0040F943  ADD EAX,EDI
0040F945  XOR CL,DL
0040F947  MOV DL,BYTE PTR SS:[ESP+11]
0040F94B  MOVSX EDI,BL
0040F94E  XOR CL,DL
0040F950  ADD EAX,EDI
0040F952  XOR CL,BL
0040F954  MOV BYTE PTR SS:[ESP+1D],AL    ;    FIRST BYTE OF theLaw:)
0040F958  MOV BYTE PTR SS:[ESP+1E],CL    ;    AND SECOND BYTE OF theLaw:)
0040F95C  MOV ECX,0D
0040F961  CDQ
0040F962  IDIV ECX
0040F964  MOV EDI,DWORD PTR DS:[ESI+8]
0040F967  MOV AL,CL
0040F969  MOV ECX,EDI
0040F96B  SHR ECX,8            ;    to check the 8-0xc bit(base 0)
0040F96E  SUB AL,DL
0040F970  MOV DX,WORD PTR SS:[ESP+1D]
0040F975  MOV WORD PTR SS:[ESP+34],DX
0040F97A  MOV BYTE PTR SS:[ESP+36],AL    ;    THE THIRD BYTE OF theLaw:)
0040F97E  MOV EAX,DWORD PTR SS:[ESP+34]
0040F982  MOV EDX,ECX
0040F984  XOR EDX,EAX
0040F986  TEST DL,1            ;    8 bit( base 1 decimal)
0040F989  JNZ SETUP.0040FB5D
0040F98F  MOV EDX,ECX
0040F991  XOR EDX,EAX
0040F993  TEST DL,2            ;    9 bit
0040F996  JNZ SETUP.0040FB5D
0040F99C  MOV EDX,ECX
0040F99E  XOR EDX,EAX
0040F9A0  TEST DL,4
0040F9A3  JNZ SETUP.0040FB5D        ;    a bit    
0040F9A9  MOV EDX,ECX
0040F9AB  XOR EDX,EAX
0040F9AD  TEST DL,8
0040F9B0  JNZ SETUP.0040FB5D        ;    b bit
0040F9B6  XOR ECX,EAX
0040F9B8  TEST CL,10
0040F9BB  JNZ SETUP.0040FB5D        ;    c bit
0040F9C1  MOV ECX,EDI
0040F9C3  SHR ECX,5            ;    check 0xd-0x11 bit
0040F9C6  MOV EDX,ECX
0040F9C8  XOR EDX,EAX
0040F9CA  TEST DH,1
0040F9CD  JNZ SETUP.0040FB5D        ;    d bit
0040F9D3  MOV EDX,ECX
0040F9D5  XOR EDX,EAX
0040F9D7  TEST DH,2
0040F9DA  JNZ SETUP.0040FB5D        ;    e bit
0040F9E0  MOV EDX,ECX
0040F9E2  XOR EDX,EAX
0040F9E4  TEST DH,4
0040F9E7  JNZ SETUP.0040FB5D        ;    f bit
0040F9ED  MOV EDX,ECX
0040F9EF  XOR EDX,EAX
0040F9F1  TEST DH,8
0040F9F4  JNZ SETUP.0040FB5D        ;    10 bit
0040F9FA  XOR ECX,EAX
0040F9FC  TEST CH,10
0040F9FF  JNZ SETUP.0040FB5D`        ;    11 bit
0040FA05  MOV ECX,EDI
0040FA07  SHR ECX,2            ;    check 0x12-16 bit
0040FA0A  MOV EDX,ECX
0040FA0C  XOR EDX,EAX
0040FA0E  TEST EDX,10000
0040FA14  JNZ SETUP.0040FB5D        ;     12 bit
0040FA1A  MOV EDX,ECX
0040FA1C  XOR EDX,EAX
0040FA1E  TEST EDX,20000
0040FA24  JNZ SETUP.0040FB5D        ;    13 bit
0040FA2A  MOV EDX,ECX
0040FA2C  XOR EDX,EAX
0040FA2E  TEST EDX,40000
0040FA34  JNZ SETUP.0040FB5D        ;    14 bit
0040FA3A  MOV EDX,ECX
0040FA3C  XOR EDX,EAX
0040FA3E  TEST EDX,80000
0040FA44  JNZ SETUP.0040FB5D        ;    15 bit
0040FA4A  XOR ECX,EAX
0040FA4C  TEST ECX,100000
0040FA52  JNZ SETUP.0040FB5D        ;    16 bit
0040FA58  MOV ESI,DWORD PTR DS:[ESI+4]
0040FA5B  MOV EAX,DWORD PTR SS:[ESP+C]
0040FA5F  MOV ECX,ESI
0040FA61  SHR ECX,14            ;    check BASE_OUT_L3W[0]
0040FA64  MOV EDX,ECX            ;    from 0x14 bit
0040FA66  XOR EDX,EAX
0040FA68  TEST DL,1
0040FA6B  JNZ SETUP.0040FB5D        ;    14 bit
0040FA71  MOV EDX,ECX
0040FA73  XOR EDX,EAX
0040FA75  TEST DL,2
0040FA78  JNZ SETUP.0040FB5D        ;    15 bit
0040FA7E  MOV EDX,ECX
0040FA80  XOR EDX,EAX
0040FA82  TEST DL,4
0040FA85  JNZ SETUP.0040FB5D        ;    16 bit
0040FA8B  MOV EDX,ECX
0040FA8D  XOR EDX,EAX
0040FA8F  TEST DL,8
0040FA92  JNZ SETUP.0040FB5D        ;    17 bit
0040FA98  XOR ECX,EAX
0040FA9A  TEST CL,10
0040FA9D  JNZ SETUP.0040FB5D        ;    18 bit
0040FAA3  MOV ECX,ESI
0040FAA5  SHR ECX,11            ;    from 19 bit
0040FAA8  MOV EDX,ECX
0040FAAA  XOR EDX,EAX
0040FAAC  TEST DH,1
0040FAAF  JNZ SETUP.0040FB5D        ;    19 bit
0040FAB5  MOV EDX,ECX
0040FAB7  XOR EDX,EAX
0040FAB9  TEST DH,2
0040FABC  JNZ SETUP.0040FB5D        ;    1a bit
0040FAC2  MOV EDX,ECX
0040FAC4  XOR EDX,EAX
0040FAC6  TEST DH,4
0040FAC9  JNZ SETUP.0040FB5D        ;    1b bit
0040FACF  MOV EDX,ECX
0040FAD1  XOR EDX,EAX
0040FAD3  TEST DH,8
0040FAD6  JNZ SETUP.0040FB5D        ;    1c bit
0040FADC  XOR ECX,EAX
0040FADE  TEST CH,10
0040FAE1  JNZ SHORT SETUP.0040FB5D        ;    1d bit
0040FAE3  MOV ECX,ESI
0040FAE5  SHR ECX,0E
0040FAE8  MOV EDX,ECX
0040FAEA  XOR EDX,EAX
0040FAEC  TEST EDX,10000            ;    1e bit
0040FAF2  JNZ SHORT SETUP.0040FB5D
0040FAF4  MOV EDX,EAX
0040FAF6  AND EDX,20000
0040FAFC  XOR EDX,ECX
0040FAFE  TEST EDX,FFFE0000
0040FB04  JNZ SHORT SETUP.0040FB5D        ;    1f bit
0040FB06  MOV ECX,EAX            ;    check BASE_OUT_L3W[1]
0040FB08  SHR ECX,12            
0040FB0B  MOV EDX,ECX
0040FB0D  XOR EDX,EDI
0040FB0F  TEST DL,1
0040FB12  JNZ SHORT SETUP.0040FB5D        ;    0 bit
0040FB14  MOV EDX,ECX
0040FB16  XOR EDX,EDI
0040FB18  TEST DL,2
0040FB1B  JNZ SHORT SETUP.0040FB5D        ;    1 bit
0040FB1D  XOR ECX,EDI
0040FB1F  TEST CL,4
0040FB22  JNZ SHORT SETUP.0040FB5D        ;    2 bit
0040FB24  SHR EAX,15
0040FB27  MOV ECX,EAX
0040FB29  XOR ECX,EDI
0040FB2B  TEST CL,8
0040FB2E  JNZ SHORT SETUP.0040FB5D        ;    3 bit
0040FB30  MOV EDX,EAX
0040FB32  XOR EDX,EDI
0040FB34  TEST DL,10
0040FB37  JNZ SHORT SETUP.0040FB5D        ;    4 bit
0040FB39  MOV ECX,EAX
0040FB3B  XOR ECX,EDI
0040FB3D  TEST CL,20
0040FB40  JNZ SHORT SETUP.0040FB5D        ;    5 bit    
0040FB42  MOV EDX,EAX
0040FB44  XOR EDX,EDI
0040FB46  TEST DL,40
0040FB49  JNZ SHORT SETUP.0040FB5D        ;    6 bit
0040FB4B  XOR EAX,EDI
0040FB4D  TEST AL,80
0040FB4F  JNZ SHORT SETUP.0040FB5D        ;    7 bit
0040FB51  POP EDI
0040FB52  POP ESI
0040FB53  MOV AL,1            ;    ohhh........yeah....result is TRUE^_*
0040FB55  POP EBX
0040FB56  ADD ESP,110
0040FB5C  RETN

总结一下:
    算法不难,就是麻烦点,要逆出来也不难,需要点耐心:)
    
    我觉得那些用经典密码学写出来的还不如这些自己编的烂算法有用,至少这个没有可参考的算法说明和可用的算法包...
    
    送份垃圾代码,没打草,想到哪写到哪了,所以一些变量名可能很恶心:)

#include "windows.h"
#include "time.h"
#include "resource.h"


HINSTANCE    hInst;
char        szCode[21];
const char        szAbout[]="\n  KeyGen for 还原精灵2003 \n\n\t by bbbsl[iPB]";

void GENERATE(void){
    int i,j=0;
    unsigned char MCode[21];
    BYTE temp2[8];
    union{
        BYTE ohfuck[8];
        DWORD yumen[2];
    } woria,wokao;
    union{
        BYTE test2[4];
        DWORD newdw;
    } test1;
    DWORD result[2];
    memset(&test1,0x0,4);
    memset(&result,0x0,2*sizeof(DWORD));
    unsigned char BASE_data[]={
        '2' , '3' , '4' , '5' , '6' , '7' , '8' , '9' , 'A' , 'B' , 'C' , 'D' , 'E' , 'F' , 'G' , 'H' ,
        'J' , 'K' , 'L' , 'M' , 'N' , 'P' , 'Q' , 'R' , 'S' , 'T' , 'U' , 'V' , 'W' , 'X' , 'Y' , 'Z'
    };// VIP chart...
    BYTE reverse_table[]={
        0x21 , 0x25 , 0x12 , 0x1B , 0x26 , 0x04 , 0x2D , 0x05,
        0x07 , 0x0E , 0x1D , 0x17 , 0x20 , 0x0A , 0x1C , 0x19,
        0x34 , 0x08 , 0x14 , 0x32 , 0x2E , 0x2C , 0x30 , 0x18,
        0x00 , 0x06 , 0x27 , 0x0D , 0x28 , 0x1E , 0x09 , 0x16,
        0x0F , 0x33 , 0x02 , 0x01 , 0x10 , 0x03 , 0x36 , 0x2F,
        0x35 , 0x22 , 0x23 , 0x1A , 0x0C , 0x24 , 0x15 , 0x13,
        0x2B , 0x0B , 0x2A , 0x29 , 0x1F , 0x11 , 0x31 , 0x37
    };//for 56 bit select...
    BYTE Mask[]={
        0x1,0x2,0x4,0x8,0x10,0x20,0x40,0x80
    };//Masks usually be convient:)
    //get the random 8 chars ...
    srand((unsigned)time(NULL));
    for (i=0;i<8;i++)
        MCode[i]=BASE_data[rand()%0x20];
        //find the char in the table...
    memset(&temp2,0xff,8);
    for (i=0;i<8;i++){
        while(BASE_data[j]!=MCode[i])
            j++;
        if (j>=0x20)    temp2[i]=0xff;
        else        temp2[i]=j;
            
        j=0;
    }
    test1.test2[0]=test1.test2[1]=0x0;
    for (i=0;i<4;i++){
        test1.test2[0]+=temp2[i+4];
        test1.test2[1]^=temp2[i+4];
    }
    test1.test2[2]=0xd-test1.test2[0]%0xd;
    result[0]=(test1.newdw&0x1f)<<8|(test1.newdw&0x1f00)<<5|(test1.newdw&0x1f0000)<<2;
    //8--23 bits;
    for (i=0;i<4;i++) test1.test2[i]=temp2[i];
    result[1]=(test1.newdw&0x1f)<<0x14|(test1.newdw&0x1f00)<<0x11|(test1.newdw&0x10000)<<0xe|(test1.newdw&0x20000)<<0xe;
    //hmm...there must be another area to check result[1]'s other bits
    result[0]|=(test1.newdw>>0x12)&0x7;  //0-2 bits;
    result[0]|=(test1.newdw>>0x15)&0xf8; //3-7 bits;
    result[0]|=0xff000000;    //25-31 bits..
    
    memset(temp2,0x0,8);

    woria.yumen[0]=result[1];
    woria.yumen[1]=result[0];
    int sum=0;    //bit sum;
    for (i=1;i<8;i++)
        for (j=0;j<8;j++)
            if(woria.ohfuck[i]&Mask[j])
                sum++;
    sum%=2;
    if (sum)
        woria.ohfuck[6]|=0x80;
    //the highest bit --24 bit
    //set every bit to the correct value:)
    memset(result,0x0,8);
    memset(&wokao,0x0,8);
    
    for (i=0;i<56;i++)
        if(woria.ohfuck[reverse_table[i]>>3]&Mask[reverse_table[i]&0x7])
            wokao.ohfuck[i>>3]|=Mask[i&0x7];
    //56 bit select;
    wokao.ohfuck[7]=0xe;
    BYTE stamp=0x0,stamp1=0x0;
    j=wokao.ohfuck[7];//backup high byte...
    for (i=0;i<j;i++){
        if(wokao.yumen[0]&0x80000000)
            stamp=0x1;
        if(wokao.yumen[1]&0x800000)
            stamp1=0x1;
        wokao.yumen[0]<<=1;
        wokao.yumen[0]|=stamp1;
        wokao.yumen[1]<<=1;
        wokao.yumen[1]|=stamp;
        stamp1=stamp=0x0;
    }//ROL routine;
    wokao.ohfuck[7]=j;//and set the high byte back...
    BYTE d[12];
    d[0]= wokao.ohfuck[0]>>3;                                d[1]=((wokao.ohfuck[0]&0x7)<<2)|(wokao.ohfuck[1]>>6);
    d[2]=(wokao.ohfuck[1]>>1)&0x1f;                            d[3]=((wokao.ohfuck[1]&0x1)<<4)|(wokao.ohfuck[2]>>4);
    d[4]=((wokao.ohfuck[2]&0xf)<<1)|(wokao.ohfuck[3]>>7);    d[5]=(wokao.ohfuck[3]>>2)&0x1f;
    d[6]=((wokao.ohfuck[3]&0x3)<<3)|(wokao.ohfuck[4]>>5);    d[7]=wokao.ohfuck[4]&0x1f;
    d[8]= wokao.ohfuck[5]>>3;                                d[9]=((wokao.ohfuck[5]&0x7)<<2)|(wokao.ohfuck[6]>>6);
    d[10]=(wokao.ohfuck[6]>>1)&0x1f;                        d[11]=((wokao.ohfuck[6]&0x1)<<4)|(wokao.ohfuck[7]&0xf);
    for (i=0;i<12;i++)
        MCode[i+8]=BASE_data[d[i]];
    MCode[20]='\0';
    strcpy(szCode,(const char *)MCode);
    return;
}
    
LRESULT CALLBACK MainProc(HWND hWnd,UINT MsG,WPARAM wParam,LPARAM lParam)
{
    HWND    hMcode;
    switch(MsG)
    {
        case WM_INITDIALOG:
            hMcode=GetDlgItem(hWnd,IDC_Code);
            SetFocus(hMcode);
            break;
        case WM_COMMAND:
            switch(wParam)
            {
                case IDC_GEN:
                    GENERATE();
                    SetDlgItemText(hWnd,IDC_Code,szCode);
                    break;
                case IDC_ABOUT:
                    MessageBox(hWnd,szAbout,NULL,MB_OK);
                    break;
                case IDC_EXIT:
                    EndDialog(hWnd,0);
                    break;
            }
            break;
        case WM_LBUTTONDOWN:
            PostMessage(hWnd, WM_NCLBUTTONDOWN, HTCAPTION, NULL);
            break;
    }
    return 0;
}
        
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,\
                  int nShowCmd)
{
    hInst=hInstance;
    DialogBox(hInstance,(LPTSTR)IDD_MainDlg,0,(DLGPROC)MainProc);
    return 0;
}