• 标 题:毫无长进,喜欢上了爆破,哈哈,来篇爆破的,不要笑! (15千字)
  • 作 者:Turkey2001
  • 时 间:2002-3-25 18:32:53
  • 链 接:http://bbs.pediy.com

目标:APIS32 v2.4(API Spy 32 v2.4)
最近一直心情不太好,也有将近2个月没有玩破解了,想找几个软件出出气,也当是复习一下。不料自己已经变懒了,不想分析什么算法之类的,一心只想爆破,不知道以后会不会变成爆破狂,呵呵!
不说废话了,今天的对象是一个协助Crack的辅助工具:APIS32 v2.4(API Spy 32 v2.4),用了监测程序调用了哪些api函数的工具,有了它,就不怕找不到函数下断点了,呵呵。那知道装上它一用,还要注册,那就不客气了,先拿它开刀了。
工具:Trw、冲击波、pw32das、ultraedit、peid
用peid检测得知,程序用petite 1.2加了壳,用冲击波+trw搞定它的壳;
用pw32das反编译脱壳后的程序,查找注册不成功的信息,来到这里:
* Reference To: KERNEL32.lstrcatA, Ord:0000h
                                  |
:00401764 FF15F8024100            Call dword ptr [004102F8]
:0040176A E8312F0000              call 004046A0//关键call,返回注册标志到eax,跟进去!
:0040176F A374CE4000              mov dword ptr [0040CE74], eax//这里的[0040CE74]存放有注册成功与否的标志,其它地方还会进行检查,所以不能简单的改下面那个跳转!
:00401774 EB01                    jmp 00401777
:00401776 B8                      BYTE B8        ---------
                                    |
* Referenced by a (U)nconditional or (C)onditional Jump at Address:        |  这里是花指令,在trw的动态调试时,
|:00401774(U)                                |==看到的是MOV [0040CE74],EAX指令
                                    |
:00401777 0AC0                    or al, al        ---------
:00401779 7402                    je 0040177D//要走到下面的指令,这里就不能跳,但不要改这里,看上面!
:0040177B EB2C                    jmp 004017A9//这里就能跳过去,

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401779(C)
|

* Possible StringData Ref from Data Obj ->"The registration information you "//出错信息!向上找跳,看哪里能跳过这里!
                                        ->"provided is incorrect. Please
verify "
                                        ->"that you entered your name and "
                                        ->"code properly, and try again.
If "
                                        ->"you encounter difficulties, please "
                                        ->"send mail to APIS32@Biosys.net
or "
                                        ->"visit our web site http://madmat.hypermart.net"
                                  |
:0040177D BFE8904000              mov edi, 004090E8
:00401782 BAE0D14000              mov edx, 0040D1E0
:00401787 83C9FF                  or ecx, FFFFFFFF
:0040178A 33C0                    xor eax, eax
:0040178C F2                      repnz
:0040178D AE                      scasb
:0040178E F7D1                    not ecx
:00401790 2BF9                    sub edi, ecx
:00401792 8BF7                    mov esi, edi
:00401794 8BC1                    mov eax, ecx
:00401796 8BFA                    mov edi, edx
:00401798 C1E902                  shr ecx, 02
:0040179B F3                      repz
:0040179C A5                      movsd
:0040179D 8BC8                    mov ecx, eax
:0040179F 83E103                  and ecx, 00000003
:004017A2 F3                      repz
:004017A3 A4                      movsb
:004017A4 E9B1000000              jmp 0040185A

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040177B(U)
|

* Possible StringData Ref from Data Obj ->"Registered to "
                                  |
:004017A9 BF40904000              mov edi, 00409040
:004017AE BAE0D14000              mov edx, 0040D1E0
:004017B3 83C9FF                  or ecx, FFFFFFFF
:004017B6 33C0                    xor eax, eax
:004017B8 F2                      repnz
:004017B9 AE                      scasb
:004017BA F7D1                    not ecx
:004017BC 2BF9                    sub edi, ecx
:004017BE 8BF7                    mov esi, edi
:004017C0 8BD9                    mov ebx, ecx
:004017C2 8BFA                    mov edi, edx
:004017C4 83C9FF                  or ecx, FFFFFFFF
:004017C7 33C0                    xor eax, eax
:004017C9 F2                      repnz
:004017CA AE                      scasb
:004017CB 83C7FF                  add edi, FFFFFFFF
:004017CE 8BCB                    mov ecx, ebx
:004017D0 C1E902                  shr ecx, 02
:004017D3 F3                      repz
:004017D4 A5                      movsd
:004017D5 8BCB                    mov ecx, ebx
:004017D7 83E103                  and ecx, 00000003
:004017DA F3                      repz
:004017DB A4                      movsb
:004017DC BF00CF4000              mov edi, 0040CF00
:004017E1 BAE0D14000              mov edx, 0040D1E0
:004017E6 83C9FF                  or ecx, FFFFFFFF
:004017E9 33C0                    xor eax, eax
:004017EB F2                      repnz
:004017EC AE                      scasb
:004017ED F7D1                    not ecx
:004017EF 2BF9                    sub edi, ecx
:004017F1 8BF7                    mov esi, edi
:004017F3 8BD9                    mov ebx, ecx
:004017F5 8BFA                    mov edi, edx
:004017F7 83C9FF                  or ecx, FFFFFFFF
:004017FA 33C0                    xor eax, eax
:004017FC F2                      repnz
:004017FD AE                      scasb
:004017FE 83C7FF                  add edi, FFFFFFFF
:00401801 8BCB                    mov ecx, ebx
:00401803 C1E902                  shr ecx, 02
:00401806 F3                      repz
:00401807 A5                      movsd
:00401808 8BCB                    mov ecx, ebx
:0040180A 83E103                  and ecx, 00000003
:0040180D F3                      repz
:0040180E A4                      movsb
:0040180F 68E0D14000              push 0040D1E0
:00401814 8B4508                  mov eax, dword ptr [ebp+08]
:00401817 50                      push eax

* Reference To: USER32.SetWindowTextA, Ord:0000h
                                  |
:00401818 FF15B4034100            Call dword ptr [004103B4]

* Possible StringData Ref from Data Obj ->"Thanks for Registering APIS32!"//注册成功的信息!
                                  |
:0040181E BFA8904000              mov edi, 004090A8
:00401823 BAE0D14000              mov edx, 0040D1E0
:00401828 83C9FF                  or ecx, FFFFFFFF
:0040182B 33C0                    xor eax, eax
:0040182D F2                      repnz

。。。。。。

跟进上面那个call,来到这里:
* Referenced by a CALL at Addresses:
|:004015CC  , :0040176A  , :00401D1A  , :00401F39  , :004025E6//这里表明有5处调用这段子程序!所以改这里最方便!
|
:004046A0 51                      push ecx
:004046A1 53                      push ebx
:004046A2 55                      push ebp
:004046A3 56                      push esi
:004046A4 57                      push edi
:004046A5 6A50                    push 00000050
:004046A7 68A0C64000              push 0040C6A0

* Possible StringData Ref from Data Obj ->"UserKey"
                                  |
:004046AC 6808964000              push 00409608
:004046B1 E81A030000              call 004049D0
:004046B6 83C40C                  add esp, 0000000C
:004046B9 83F810                  cmp eax, 00000010//检查注册码是不是小于16位
:004046BC 7D08                    jge 004046C6
:004046BE 33C0                    xor eax, eax
:004046C0 5F                      pop edi
:004046C1 5E                      pop esi
:004046C2 5D                      pop ebp
:004046C3 5B                      pop ebx
:004046C4 59                      pop ecx
:004046C5 C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004046BC(C)
|
:004046C6 6A2F                    push 0000002F
:004046C8 6800CF4000              push 0040CF00

* Possible StringData Ref from Data Obj ->"UserName"
                                  |
:004046CD 68F8954000              push 004095F8
:004046D2 E8F9020000              call 004049D0
:004046D7 83C40C                  add esp, 0000000C
:004046DA 83F805                  cmp eax, 00000005//检查用户名是不是小于5位
:004046DD 7D08                    jge 004046E7
:004046DF 33C0                    xor eax, eax
:004046E1 5F                      pop edi
:004046E2 5E                      pop esi
:004046E3 5D                      pop ebp
:004046E4 5B                      pop ebx
:004046E5 59                      pop ecx
:004046E6 C3                      ret



* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004046DD(C)
|
:004046E7 BFA0C64000              mov edi, 0040C6A0//这里开始漫长的注册码计算和验证过程,我懒,不管它,直接找返回标志的地方
:004046EC 83C9FF                  or ecx, FFFFFFFF
:004046EF 33C0                    xor eax, eax
:004046F1 C605B1C6400000          mov byte ptr [0040C6B1], 00
:004046F8 F2                      repnz
:004046F9 AE                      scasb
:004046FA F7D1                    not ecx
:004046FC 2BF9                    sub edi, ecx
:004046FE 8BC1                    mov eax, ecx
:00404700 8BF7                    mov esi, edi
:00404702 BFB4C64000              mov edi, 0040C6B4
:00404707 C1E902                  shr ecx, 02
:0040470A F3                      repz
:0040470B A5                      movsd
:0040470C 8BC8                    mov ecx, eax
:0040470E 33C0                    xor eax, eax
:00404710 83E103                  and ecx, 00000003
:00404713 F3                      repz
:00404714 A4                      movsb
:00404715 BFA9C64000              mov edi, 0040C6A9
:0040471A 83C9FF                  or ecx, FFFFFFFF
:0040471D F2                      repnz
:0040471E AE                      scasb
:0040471F F7D1                    not ecx
:00404721 2BF9                    sub edi, ecx
:00404723 8BD1                    mov edx, ecx
:00404725 8BF7                    mov esi, edi
:00404727 BFBCC64000              mov edi, 0040C6BC
:0040472C C1E902                  shr ecx, 02
:0040472F F3                      repz
:00404730 A5                      movsd
:00404731 8BCA                    mov ecx, edx
:00404733 83E103                  and ecx, 00000003
:00404736 32DB                    xor bl, bl
:00404738 F3                      repz
:00404739 A4                      movsb
:0040473A BEA1C64000              mov esi, 0040C6A1
:0040473F BFB4C64000              mov edi, 0040C6B4

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00404763(C)
|
:00404744 57                      push edi
:00404745 E8E6010000              call 00404930
:0040474A 8ACB                    mov cl, bl
:0040474C 83C404                  add esp, 00000004
:0040474F 80C150                  add cl, 50
:00404752 83C702                  add edi, 00000002
:00404755 32C1                    xor al, cl
:00404757 FEC3                    inc bl
:00404759 8846FF                  mov byte ptr [esi-01], al
:0040475C C60600                  mov byte ptr [esi], 00
:0040475F 46                      inc esi
:00404760 80FB08                  cmp bl, 08
:00404763 72DF                    jb 00404744
:00404765 68B4C64000              push 0040C6B4
:0040476A 68A0C64000              push 0040C6A0
:0040476F E8EC010000              call 00404960
:00404774 BF00CF4000              mov edi, 0040CF00
:00404779 83C9FF                  or ecx, FFFFFFFF
:0040477C 33C0                    xor eax, eax
:0040477E 83C408                  add esp, 00000008
:00404781 F2                      repnz
:00404782 AE                      scasb
:00404783 F7D1                    not ecx
:00404785 2BF9                    sub edi, ecx
:00404787 33ED                    xor ebp, ebp
:00404789 8BD1                    mov edx, ecx
:0040478B 8BF7                    mov esi, edi
:0040478D BFBEC64000              mov edi, 0040C6BE
:00404792 C1E902                  shr ecx, 02
:00404795 F3                      repz
:00404796 A5                      movsd
:00404797 8BCA                    mov ecx, edx
:00404799 83E103                  and ecx, 00000003
:0040479C F3                      repz
:0040479D A4                      movsb
:0040479E BF00CF4000              mov edi, 0040CF00
:004047A3 83C9FF                  or ecx, FFFFFFFF
:004047A6 F2                      repnz
:004047A7 AE                      scasb
:004047A8 F7D1                    not ecx
:004047AA 49                      dec ecx
:004047AB 80F908                  cmp cl, 08
:004047AE 884C2410                mov byte ptr [esp+10], cl
:004047B2 7330                    jnb 004047E4
:004047B4 8B542410                mov edx, dword ptr [esp+10]
:004047B8 BF00CF4000              mov edi, 0040CF00
:004047BD 81E2FF000000            and edx, 000000FF
:004047C3 83C9FF                  or ecx, FFFFFFFF
:004047C6 81C2BEC64000            add edx, 0040C6BE
:004047CC F2                      repnz
:004047CD AE                      scasb
:004047CE F7D1                    not ecx
:004047D0 2BF9                    sub edi, ecx
:004047D2 8BC1                    mov eax, ecx
:004047D4 8BF7                    mov esi, edi
:004047D6 8BFA                    mov edi, edx
:004047D8 C1E902                  shr ecx, 02
:004047DB F3                      repz
:004047DC A5                      movsd
:004047DD 8BC8                    mov ecx, eax
:004047DF 83E103                  and ecx, 00000003
:004047E2 F3                      repz
:004047E3 A4                      movsb

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004047B2(C)
|
:004047E4 C605C6C6400000          mov byte ptr [0040C6C6], 00
:004047EB B9B4C64000              mov ecx, 0040C6B4
:004047F0 BE08000000              mov esi, 00000008

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00404819(C)
|
:004047F5 8A01                    mov al, byte ptr [ecx]
:004047F7 3C20                    cmp al, 20
:004047F9 730E                    jnb 00404809
:004047FB 33D2                    xor edx, edx
:004047FD 25FF000000              and eax, 000000FF
:00404802 8A510A                  mov dl, byte ptr [ecx+0A]
:00404805 0BD0                    or edx, eax
:00404807 EB0C                    jmp 00404815

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004047F9(C)
|
:00404809 33D2                    xor edx, edx
:0040480B 25FF000000              and eax, 000000FF
:00404810 8A510A                  mov dl, byte ptr [ecx+0A]
:00404813 33D0                    xor edx, eax

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00404807(U)
|
:00404815 03EA                    add ebp, edx
:00404817 41                      inc ecx
:00404818 4E                      dec esi
:00404819 75DA                    jne 004047F5
:0040481B 33C0                    xor eax, eax//这里向下就是返回的参数了,找于al相关的,
:0040481D 5F                      pop edi
:0040481E 85ED                    test ebp, ebp//就是这里将z置0了,怎么才能让ebp为0呢,我不知道,不过上面有xor eax, eax这条指令,哈哈,把它变成test eax,eax吧,也就是85ED=>85C0
:00404820 5E                      pop esi
:00404821 5D                      pop ebp
:00404822 0F94C0                  sete al//在这里,程序让我们死翘翘了,向上看哪里把z这个flag置0了
:00404825 5B                      pop ebx
:00404826 59                      pop ecx
:00404827 C3                      ret

拿出ultraedit,将程序改了,运行测试,一切ok,收工!

最后总结:
脱壳后查找:33C0 5F 85ED 5E 5D,改成:33C0 5F 85C0 5E 5D

                            Cracker:Turkey/灭害灵
                                2002.3.25@18:00

  • 标 题:转贴:ddcrack的APISPY32 2.4的破解 (25千字)
  • 时 间:2002-3-29 12:28:16
  • 链 接:http://bbs.pediy.com

APISPY32 V2.4完全破解实战

  破解过程中你一定遇到过这样的情况:设置了好多断点,可就是拦截不住想要破解的应用程序。现在一切已成过去,有了APISPY32的帮助,我们就能清楚地知道应用程序调用了哪些API函数,设置断点就是轻而易举的事情了。

程序名 :APISPY32
版本   :V2.4
大小   :164KB
运行平台:Windows 9x/NT/2000
保护方式:注册码
破解方式:注册码破解
破解难度:难
程序下载:api32-24.zip
附件  :注册机及其C语言源程序

作者   :ddcrack (2001/06/14)
笨冬瓜 :ddcrack.yeah.net

破解步骤:

1. 用softice载入windows(通过CTRL+D来检查softice是否已经准备好,按F5退出);

2. 运行APIS32;

3. 选择“Register”进入注册框;

4. 在“Registration Name:”中输入:ddcrack(随意),“Registration Key:”中输入:12345678(随意);

5. 用CTRL+D呼出softice,下万能断点:bpx hmemcpy,按F5返回APIS32;

6. 在APIS32注册框中点击“OK”,很快程序就被softice拦截下来;

7. 用 bd * 暂停断点 bpx hmemcpy ;

8. 按F12键9次,返回到APIS32的领空,程序停留在下面的地方:
。。。
0167:00404859 TEST EAX,EAX         <-- 程序停在这里
0167:0040485B JZ 004048D3
0167:0040485D MOV EDI,0040CF00
0167:00404862 OR ECX,-01
0167:00404865 XOR EAX,EAX
0167:00404867 REPNZ SCASB          <-- EDI指向我们输入的注册码“12345678”
0167:00404869 NOT ECX
0167:0040486B DEC ECX
0167:0040486C PUSH ECX
0167:0040486D PUSH 0040CF00         <-- 内存地址0040CF00中是输入的注册码“12345678”
0167:00404872 PUSH 00409608         <-- 内存地址00409608中是字符串“UserKey”
0167:00404877 CALL 00404A50
0167:0040487C ADD ESP,0C
0167:0040487F PUSH 4E
0167:00404881 PUSH 0040CF00
0167:00404886 PUSH 000003F0
0167:0040488B PUSH ESI
0167:0040488C CALL EBX
0167:0040488E TEST EAX,EAX
0167:00404890 JZ 004048D3
0167:00404892 MOV EDI,0040CF00
0167:00404897 OR ECX,-01
0167:0040489A XOR EAX,EAX
0167:0040489C REPNZ SCASB          <-- EDI指向我们输入的用户名“ddcrack”
0167:0040489E NOT ECX
0167:004048A0 DEC ECX
0167:004048A1 PUSH ECX
0167:004048A2 PUSH 0040CF00         <-- 内存地址0040CF00中是输入的用户名“ddcrack”
0167:004048A7 PUSH 004095F8
0167:004048AC CALL 00404A50         <-- 内存地址00404A50中是字符串“UserName”
0167:004048B1 ADD ESP,0C
0167:004048B4 PUSH 01
0167:004048B6 PUSH ESI
0167:004048B7 CALL [USER32!EndDialog]    <-- 关闭注册框
0167:004048BD POP EDI
0167:004048BE POP ESI
0167:004048BF POP EBX
0167:004048C0 RET
。。。

9. 刚返回到APIS32的领空,我们就看见指令0167:00404859 TEST EAX,EAX和0167:0040485B JZ 004048D3,该不会是注册码已经判断过了吧?不太可能,首先是一般情况下应用程序不会这么快就会判断注册码的正确性(因为要进行很多处理和转换嘛),再者EAX既不等于1也不等于0,而是等于8。让我们往这条指令的前面看去,你会发现以下一些指令:
。。。
0167:00404844 MOV EBX,[USER32!GetDlgItemTextA]
0167:0040484A PUSH 4E
0167:0040484C PUSH 0040CF00
0167:00404851 PUSH 000003F1
0167:00404856 PUSH ESI
0167:00404857 CALL EBX
0167:00404859 TEXT EAX,EAX
0167:0040485B JZ 004048D3

  现在明白怎么回事了吧^_^——程序先将获取对话框文本的API函数GetDlgItemTextA的地址赋予EBX,下面用CALL EBX指令来调用它。所以这段程序是取得我们输入的文本,因为输入的注册码是8个字符的“12345678”,所以EAX才会等于8嘛,如果输入的字符为空,则EAX=0,程序跳到004048D3去,肯定会让你重新输入注册信息了;

10. 按F10几次走到0167:00404877 CALL 00404A50停下,然后分别用 D 0040CF00 和 D 00409608,你会看到内存地址0040CF00中是我们输入的注册码“12345678”,而内存地址00409608中有“UserKey.SOFTWARE\APIS32”的字符串,好象应该是跟注册表有关的东西;

11. 按F8进入这个CALL 00404A50里面去,你会看到有很多的注册表操作API函数,主要是在注册表中写入信息,显然此处不会去判断注册码。按F12一下走出这个CALL 00404A50来到它的下一句0167:0040487C ADD ESP,0C。先不用着急走,看看下面的程序段,跟上面走过的差不多,你可以一边按F10走一边观察内存数据,可以发现接着是用0167:0040488C的CALL EBX取得我们输入的用户名“ddcrack”,然后0167:004048AC CALL 00404A50将其写入注册表中,最后0167:004048B7 CALL [USER32!EndDialog]关闭注册信息输入框;

12. 按F10走完上面的程序之后继续往后走,你会发现再次进入系统区域(首先进入KERNEL32,然后是USER),按F12数次(多少次我也不清楚,反正挺多的,仔细看好,不要走过头了^_^)直到又重新返回APIS32的领空:
。。。
0167:0040172C CALL [USER32!DialodBoxParamA] <-- 获取对话框参数
0167:00401732 TEST EAX,EAX         <-- 程序停在这里
0167:00401734 JZ 00401873
0167:0040173A PUSH 00409020         <-- 地址00409020中是“APIS32”
0167:0040173F PUSH 0040D1E0         <-- 地址0040D1E0中是“The registration information you provided is incorrect”
0167:00401744 CALL [KERNEL32!lstrcpy]
0167:0040174A PUSH 00409038         <-- 地址00409038中是“V 2.4”
0167:0040174F PUSH 0040D1E0
0167:00401754 CALL [KERNEL32!lstrcat]
0167:0040175A PUSH 00409328         <-- 地址00409328中是“ - ”
0167:0040175F PUSH 0040D1E0
0167:00401764 CALL [KERNEL32!lstrcat]
0167:0040176A CALL 004046A0
0167:0040176F MOV [0040CE74],EAX
0167:00401774 JMP 00401777
0167:00401776 MOV EAX,0274C00A
0167:0040177B JMP 004017A9
。。。

13. 上面的程序都在对字符串进行复制和追加的操作,肯定和注册码的判断无关。按F10往下走,然后用 D 内存地址 可以看到上面注释中的内容。当走到0167:00401774 JMP 00401777时暂停,再按一次F10,你会看到下面的指令突然变掉了:
。。。
0167:00401774 JMP 00401777
0167:00401776 MOV EAX,0274C00A
0167:00401777 OR AL,AL           <-- 程序停在这里
0167:00401779 JZ 0040177D
0167:0040177B JMP 004017A9
。。。

14. 平白无故多了两条指令:0167:00401777 OR AL,AL和0167:00401779 JZ 0040177D,很可疑噢!再按一下F10,后面的指令又变掉了:
。。。
0167:00401774 JMP 00401777
0167:00401776 MOV EAX,0274C00A
0167:00401779 JZ 0040177D          <-- 程序停在这里
0167:0040177B JMP 004017A9
。。。

15. 走了两步,程序指令连续变了两次,上面的0167:0040176A CALL 004046A0肯定有问题(你也许会问:为什么程序的指令会动态改变呢?——其实这是APIS32设置的一个圈套,它并没有动态去修改执行指令代码,只是在0167:00401776处用伪指令 BYTE B8 在此放置了单字节数据B8,因为程序运行时并不知道这是个数据,只是运行到相关的地方才会跳过去(注意Softice一直是将B8作为一个指令代码来反汇编程序代码),所以我们看到的指令在不停的变来变去。需要注意的是:在跟踪很多狡猾的应用程序时你都会发现同样的伎俩,不要理它就是了,因为再狡猾的指令到了该执行的时候终归会原形必露,WINDOWS下的任何程序都没有办法逃过动态跟踪的)。首先将鼠标移到CALL 004046A0这行并点击一下,然后按F9在此设置断点。做好了准备工作,接着用 RFL Z 改变零标志位的状态,这样程序就不会按预定的路线跳到0040177D去,而是执行其后的指令0167:0040177B JMP 004017A9跳到004017A9,按F5让程序自己跑,看见了什么^_^——APIS32出现注册成功的信息“Thanks for registering APIS32!”。显然CALL 004046A0就是注册码检测子程序,只要EAX返回值不为0就表示注册码合法,让我们杀进去看看;

16. 返回到APIS32的注册框,重新输入用户名“ddcrack”和注册码“12345678”,按“OK”键,马上APIS32就被Softice拦截停在0167:0040176A CALL 004046A0上(因为刚才在这里设置了断点),然后按F8进入到这个CALL里去:
。。。
0167:004046A0 PUSH ECX
0167:004046A1 PUSH EBX
0167:004046A2 PUSH EBP
0167:004046A3 PUSH ESI
0167:004046A4 PUSH EDI
0167:004046A5 PUSH 50
0167:004046A7 PUSH 0040C6A0         <-- 内存地址0040C6A0中是输入的注册码“12345678”
0167:004046AC PUSH 00409608         <-- 内存地址00409608中是字符串“UserKey”
0167:004046B1 CALL 004049D0
0167:004046B6 ADD ESP,0C
0167:004046B9 CMP EAX,10          <-- 此时EAX=8
0167:004046BC JGE 004046C6
0167:004046BE XOR EAX,EAX
0167:004046C0 POP EDI
0167:004046C1 POP ESI
0167:004046C2 POP EBP
0167:004046C3 POP EBX
0167:004046C4 POP ECX
0167:004046C5 RET
0167:004046C6 PUSH 2F
0167:004046C8 PUSH 0040CF00         <-- 内存地址0040CF00中是输入的用户名“ddcrack”
0167:004046CD PUSH 004095F8         <-- 内存地址004095F8中是字符串“UserName”
0167:004046D2 CALL 004049D0
0167:004046D7 ADD ESP,0C
0167:004046DA CMP EAX,05          <-- 此时EAX=7
0167:004046DD JGE 004046E7
0167:004046DF XOR EAX,EAX
0167:004046E1 POP EDI
0167:004046E2 POP ESI
0167:004046E3 POP EBP
0167:004046E4 POP EBX
0167:004046E5 POP ECX
0167:004046E6 RET
。。。

17. 按F10走到0167:004046B1 CALL 004049D0停下,分别用 D 0040C6A0 和 D 00409608 命令,可以看到内存地址0040C6A0中是输入的注册码“12345678”,而内存地址00409608中是字符串“UserKey”,按F10两次停在0167:004046B9 CMP EAX,10上,此时EAX=8,很容易就能想到EAX中的8就是注册码“12345678”的字符数,而此处程序的作用就是判断输入的注册码字符数是否大于等于16进制值10,即字符数是否大于等于16,如果小于16个字符,下面的程序0167:004046BE XOR EAX,EAX就会将EAX清零,这样子程序返回后就完蛋了(因为步骤15是我们已经知道EAX的返回值不能等于0);

18. 按一次F10走到0167:004046BC JGE 004046C6处,用 RFL S 改变程序的执行方向(因为我们输入的注册码“12345678”字符数为8,小于16,如果让程序自己走下去就没戏唱了),按F10走下去,和刚才差不多,指令0167:004046DA CMP EAX,05会判断输入的用户名字符数是否大于5(我们输入的“ddcrack”是7个字符,自然没有问题了);

19. 按F5返回APIS32,进入注册框,输入用户名“ddcrack”和注册码“1234567890ABCDEF0”(17位,随意但要大于16位),按“OK”键,APIS32再次被Softice拦截停在0167:0040176A CALL 004046A0上。然后按F8进入CALL 004046A0,这下我们可以大踏步的按F10走到上面程序段的后面程序去了:
。。。
0167:004046E7 MOV EDI,0040C6A0
0167:004046EC OR ECX,-01
0167:004046EF XOR EAX,EAX
0167:004046F1 MOV BYTE PTR [0040C6B1],00
0167:004046F8 REPNZ SCASB
0167:004046FA NOT ECX
0167:004046FC SUB EDI,ECX
0167:004046FE MOV EAX,ECX
0167:00404700 MOV ESI,EDI
0167:00404702 MOV EDI,0040C6B4
0167:00404707 SHR ECX,02
0167:0040470A REPZ MOVSD
0167:0040470C MOV ECX,EAX
0167:0040470E XOR EAX,EAX
0167:00404710 AND ECX,03
0167:00404713 REPZ MOVSB
0167:00404715 MOV EDI,0040C6A9
0167:0040471A OR ECX,-01
0167:0040471D REPNZ SCASB
0167:0040471F NOT ECX
0167:00404721 SUB EDI,ECX
0167:00404723 MOV EDX,ECX
0167:00404725 MOV ESI,EDI
0167:00404727 MOV EDI,0040C6BC
0167:0040472C SHR ECX,02
0167:0040472F REPZ MOVSD
0167:00404731 MOV ECX,EDX
0167:00404733 AND ECX,03
0167:00404736 XOR BL,BL
0167:00404738 REPZ MOVSB
0167:0040473A MOV ESI,0040C6A1       <-- 内存地址0040C6A1中是字符串“234567890ABCDEF0”
0167:0040473F MOV EDI,0040C6B4       <-- 内存地址0040C6A1中是字符串“123456780ABCDEF0”
0167:00404745 CALL 00404930
0167:0040474A MOV CL,BL
。。。

20. 上面的程序段前大部分主要是字符串操作指令,将数据移来移去的,我们可以不用管它,。按F10走到0167:00404745 CALL 00404930停下,然后分别用 D ESI 和 D EDI ,你会看到ESI指向的内存中是字符串“234567890ABCDEF0”,EDI指向的内存地址中是字符串“123456780ABCDEF0”。什么意思呢?不清楚,按F8进入CALL 00404930里去查个究竟:
。。。
0167:00404930 MOV ECX,[ESP+04]       <-- 将字符串“123456780ABCDEF0”的地址赋予ECX
0167:00404934 MOV AL,[ECX]         <-- 取出ECX指向的内存地址中的第一个字符“1”
0167:00404936 CMP AL,39           <-- 判断字符“1”是否小于等于“9”
0167:00404938 JLE 0040493E
0167:0040493A ADD AL,C9           <-- 字符“1”大于“9”则将其ASCII码值加上C9
0167:0040493C JMP 00404940
0167:0040493E ADD AL,D0           <-- 字符“1”小于等于“9”则将其ASCII码值加上D0
0167:00404940 MOV CL,[ECX+01]        <-- 取出ECX指向的内存地址中的第二个字符“2”
0167:00404943 CMP CL,39           <-- 判断字符“2”是否小于等于“9”
0167:00404946 JLE 00404951
0167:00404948 SHL AL,04           <-- AL左移4位,即乘以16
0167:0040494B SUB CL,37           <-- 字符“2”大于“9”则将其ASCII码值减去37
0167:0040494E OR AL,CL           <-- 合并AL和CL,高位为AL,低位为CL
0167:00404950 RET
0167:00404951 SHL AL,04           <-- AL左移4位,即乘以16
0167:00404954 SUB CL,30           <-- 字符“2”小于等于“9”则将其ASCII码值减去30
0167:00404957 OR AL,CL           <-- 合并AL和CL,高位为AL(对应的字符是“1”),低位为CL(对应的字符是“2”)
0167:00404959 RET
。。。

  按一次F10走过0167:00404930 MOV ECX,[ESP+04],用 D ECX 可以看到ECX此时指向的内存区域中是字符串“123456780ABCDEF0”(以后可以看到ECX会递增加2,也就是依次取出后面的字符),仔细看清楚,我们输入的注册码是“1234567890ABCDEF0”,现在已经被APIS32将字符“9”剔除掉了。而上面的子程序其作用实际上是将字符串两个为一组(如“12”)合并成同样形式的16进制数(与“12”对应的是0x12),结果保存在AL中。程序假设输入的注册码只能有数字“1”到“9”和大写字母“A”到“Z”,若是数字,将其ASCII码值(0x30到0x39)加上D0或减去30得到对应的16进制值(0x00到0x09),若是大写字母则将其ASCII码值(0x41到0x46)加上C9或减去37得到其对应的16进制值(0x0A到0x0F),然后将两个16进制值拼装在一起;

21. 按F10走出子程序CALL 00404930,来到它的下一句(为了便于讲解,将其前面的几条指令也列出来):
。。。
0167:00404736 XOR BL,BL           <-- 寄存器BL清零
0167:00404738 REPZ MOVSB
0167:0040473A MOV ESI,0040C6A1
0167:0040473F MOV EDI,0040C6B4        <-- EDI指向字符串“123456780ABCDEF0”的某一位置,
                                初始时指向字符串“123456780ABCDEF0”的开始位置
0167:00404745 CALL 00404930          <-- 两个字符为一组(如“12”)转换为相同形式的16进制值(如 0x12)
0167:0040474A MOV CL,BL           <-- 将BL的值赋予CL
0167:0040474C ADD ESP,04
0167:0040474F ADD CL,50           <-- CL=BL+50
0167:00404752 ADD EDI,02           <-- 指针EDI递增加2,即依次顺序(两个字符为一组)指向字符串“123456780ABCDEF0”中的字符
0167:00404755 XOR AL,CL           <-- 将字符串对应形式的16进制值和CL相异或
0167:00404757 INC BL             <-- BL递增加1
0167:00404759 MOV [ESI-01],AL        <-- 将异或结果AL存入内存地址[ESI-01](即地址0040C6A0开始的内存)中
0167:0040475C MOV BYTE PTR [ESI],00     <-- 其后面补0作为结束标志
0167:0040475F INC ESI             <-- 地址指针ESI递增加1
0167:00404760 CMP BL,08           <-- 循环次数为8次,因为两个字符为一组,所以实际上注册码应为17位数(别忘了被剔除的那1位“9”噢^_^)
0167:00404763 JB 00404744
0167:00404765 PUSH 0040C6B4           <-- 内存地址0040C6B4中是字符串“123456780ABCDEF0”
0167:0040476A PUSH 0040C6A0           <-- 内存地址0040C6A0中是字符串“123456780ABCDEF0”经过上面的程序处理之后的结果,
                          “12 34 56 78 0A BC DE F0”对应的结果为16进制值“42 65 04 2B 5E E9 88 A7”
0167:0040476F CALL 00404960
。。。

22. 按F10继续走到0167:0040476F CALL 00404960时发现其入口参数为字符串“123456780ABCDEF0”和其转换后结果的内存地址,所以我们必须按F8跟进去看看:
。。。
0167:00404960 PUSH EBX
0167:00404961 PUSH EBP
0167:00404962 MOV EBP,[ESP+10]
0167:00404966 PUSH ESI
0167:00404967 PUSH EDI
0167:00404968 MOV EDI,[ESP+14]
0167:0040496C XOR ECX,ECX
0167:0040496E SUB EDI,EBP
0167:00404970 MOV [ESP+18],EDI
0167:00404974 JMP 0040497A
0167:00404976 MOV EDI,[ESP+18]
0167:0040497A LEA ESI,[ECX+EBP]
0167:0040497D XOR EDX,EDX           <-- EDX清零
0167:0040497F MOV EAX,00000001        <-- EAX初始值为1
0167:00404984 MOV DWORD PTR [ESP+14],00000007 <-- 循环次数为7次,放在内存[ESP+14]中
0167:0040498C MOV DL,[EDI+ESI]        <-- EDI+ESI指向刚才字符串的处理结果“42 65 04 2B 5E E9 88 A7”
0167:0040498F MOV EDI,EDX
0167:00404991 MOV EDX,EDI           <-- 将取出的值放在EDX中
0167:00404993 IMUL EAX,EDX          <-- EAX乘以EDX
0167:00404996 CMP EAX,00008899        <-- 乘法结果和00008899比较
0167:0040499B JLE 004049A7
0167:0040499D CDQ                 <-- 大于00008899则执行这里开始的程序
0167:0040499E MOV EBX,00008899        <-- EBX=00008899
0167:004049A3 IDIV EBX             <-- EAX除以00008899
0167:004049A5 MOV EAX,EDX           <-- 除法余数放回EAX中
0167:004049A7 MOV EDX,[ESP+14]       <-- 循环次数放入EDX
0167:004049AB DEC EDX             <-- 循环记数值减1
0167:004049AC MOV [ESP+14],EDX
0167:004049B0 JNZ 00404991          <-- 判断循环次数是否已满7次
0167:004049B2 CDQ               <-- 循环完毕将EAX的值扩展到EDX中
0167:004049B3 MOV EDI,000000BB        <-- EDI=000000BB
0167:004049B8 IDIV EDI             <-- EAX除以EDI
0167:004049BA INC ECX              <-- 外循环记数值递增加1
0167:004049BB CMP ECX,00000008        <-- 是否已将“42 65 04 2B 5E E9 88 A7”处理完毕
0167:004049BE MOV [ESI],DL          <-- 取除法余数作为结果并存在地址[ESI]中,
                   “42 65 04 2B 5E E9 88 A7”对应的处理结果为“6E 54 73 57 13 07 AA 28”
0167:004049C0 MOV BYTE PTR [ECX+EBP],00
0167:004049C4 JL 00404976
0167:004049C6 POP EDI
0167:004049C7 POP ESI
0167:004049C8 POP EBP
0167:004049C9 POP EBX
0167:004049CA RET
。。。

23. 上面的子程序再次对字符串“123456780ABCDEF0”的结果“42 65 04 2B 5E E9 88 A7”进行了处理,得到“6E 54 73 57 13 07 AA 28”。一直按F10走出这个CALL,回到它的下面一条指令:
。。。
0167:0040476F CALL 00404960
0167:00404774 MOV EDI,0040CF00        <-- 从子程序CALL 00404960返回停在这里
0167:00404779 OR ECX,-01
0167:0040477C XOR EAX,EAX
0167:0040477E ADD ESP,08
0167:00404781 REPNZ SCASB           <-- EDI指向输入的用户名“ddcrack”
0167:00404783 NOT ECX
0167:00404785 SUB EDI,ECX
0167:00404787 XOR EBP,EBP
0167:00404789 MOV EDX,ECX
0167:0040478B MOV ESI,EDI
0167:0040478D MOV EDI,0040C6BE
0167:00404792 SHR ECX,02
0167:00404795 REPZ MOVSD
0167:00404797 MOV ECX,EAX
0167:00404799 AND ECX,03
0167:0040479C REPZ MOVSB
0167:0040479E MOV EDI,0040CF00
0167:004047A3 OR ECX,-01
0167:004047A6 REPNZ SCASB           <-- EDI指向输入的用户名“ddcrack”
0167:004047A8 NOT ECX
0167:004047AA DEC ECX
0167:004047AB CMP CL,08            <-- 用户名字符数和8比较
0167:004047AE MOV [ESP+10],CL
0167:004047B2 JAE 004047E4          <-- 大于等于8则直接跳到004047E4去
0167:004047B4 MOV EDX,DOWRD PTR [ESP+10]   <-- 小于8则进行其它处理
0167:004047B8 MOV EDI,0040CF00
0167:004047BD AND EDX,000000FF
0167:004047C3 OR ECX,-01
0167:004047C6 ADD EDX,0040C6BE
0167:004047CC REPNZ SCASB
0167:004047CE NOT ECX
0167:004047D0 SUB EDI,ECX
0167:004047D2 MOV EAX,ECX
0167:004047D4 MOV ESI,EDI
0167:004047D6 MOV EDI,EDX
0167:004047D8 SHR ECX,02
0167:004047DB REPZ MOVSD
0167:004047DD MOV ECX,EAX
0167:004047DF AND ECX,00000003
0167:004047E2 REPZ MOVSB
0167:004047E4 MOV BYTE PTR [0040C6C6],00
。。。

24. 上面又是一段长长的字符串字符操作程序,我们不用仔细去跟踪它。首先按F10走到0167:00404781 REPNZ SCASB处,用 D EDI 命令,将会看到EDI指向输入的用户名“ddcrack”,说明这段程序在对用户名进行处理。走到0167:00404795 REPZ MOVSD时停下来,先用 D ESI ,可以看到相应的内存中是用户名“ddcrack”,再用 D EDI ,然后按F10,发现“ddcrack”已经被搬到EDI指向的内存中了。继续按F10走到0167:004047AB CMP CL,08,显然这条指令在判断用户名字符数是否大于等于8,这里CL=7(“ddcrack”是7位),所以程序接着往下走,当走过0167:004047DB REPZ MOVSD这条指令后你会发现原来内存中的“ddcrack”已经变成了 “ddcrackd”,正好是8位字符;

25. 现在我们知道程序将不足8位的用户名补足8位:规则就是顺序将用户名往后补足8位,例如“ddcrack”补足8位后成为“ddcrackd”。其实刚才我们只是碰巧发现了程序段的功能,如果你仔细去跟踪程序,一样能知道其具体作用,只是费点时间罢了。按F10继续走到上面程序段的后面去:
。。。
0167:004047E4 MOV BYTE PTR [0040C6C6],00
0167:004047EB MOV ECX,0040C6B4          <-- ECX指向注册码处理结果“6E 54 73 57 13 07 AA 28”
0167:004047F0 MOV ESI,00000008          <-- 分别对8个值进行处理
0167:004047F5 MOV AL,[ECX]            <-- 取出某个值
0167:004047F7 CMP AL,20              <-- 和20比较
0167:004047F9 JAE 00404809
0167:004047FB XOR EDX,EDX             <-- 如果小于20
0167:004047FD AND EAX,000000FF          <-- 将AL的值扩展到EAX中
0167:00404802 MOV DL,[ECX+0A]          <-- ECX+0A指向用户名处理结果“ddcrackd”
0167:00404805 OR EDX,EAX             <-- 注册码处理结果和用户名处理的结果对应位进行或运算
0167:00404807 JMP 00404815
0167:00404809 XOR EDX,EDX             <-- 如果大于20
0167:0040480B AND EAX,000000FF          <-- 将AL的值扩展到EAX中
0167:00404810 MOV DL,[ECX+0A]          <-- ECX+0A指向用户名处理结果“ddcrackd”
0167:00404813 XOR EDX,EAX             <-- 注册码处理结果和用户名处理的结果对应位进行异或运算
0167:00404815 ADD EBP,EDX             <-- 运算结果累加到EBP中
0167:00404817 INC ECX
0167:00404818 DEC ESI
0167:00404819 JNZ 004047F5
0167:0040481B XOR EAX,EAX
0167:0040481D POP EDI
0167:0040481E TEST EBP,EBP             <-- 测试EBP的值
0167:00404820 POP ESI
0167:00404821 POP EBP
0167:00404822 SETZ AL                 <-- 如果EBP=0,则AL=1,那么就表示注册码正确了^_^
0167:00404825 POP EBX
0167:00404826 POP ECX
0167:00404827 RET
。。。

26. 程序已经走完,相信你对注册码算法也有了一定的概念,现在让我们来清理一下大脑:

⑴  首先,用户名字符个数必须大于等于5,注册码为17位字符串且必须为数字1到9或者大写字母A到Z;

⑵  将输入的注册码字符串(以“1234567890ABCDEF0”为例)去掉第9位(变成“123456780ABCEDF0),也即表示注册码第9位是任意的;

⑶  将处理过的注册码字符两个为一组,转换成相同形式的16进制值Ri,i=0,1,2,3,4,5,6,7,(“12”“ 34”“ 56 ”“78”“ 0A ”“BC”“ DE”“ F0”分别变成 0x12 0x34 0x56 0x78 0x0A 0xBC 0xDE 0xF0);

⑷  Ri = Ri XOR (0x50+i);

⑸  EAX初值为1:
   FOR(J=0;J<7;J++)
    { EAX=EAX*Ri
      IF(EAX>00008899) EAX=EAX MOD 00008899
    }
   Ri = EAX MOD 000000BB

⑹  格式化输入的用户名为8位字符Ni,i=0,1,2,3,4,5,6,7:多余8位的将超过8位的字符截掉,不足8位的用用户名顺序补齐(如“ddcrack”补足8位后变成“ddcrackd”);

⑺  Ui = Ri XOR Ni(如果Ri大于等于20)或 Ri OR Ni(如果Ri小于20);

⑻  T = U0 + U1 + U2 + U3 + U4 + U5 + U6 + U7 ;

⑼  如果T=0表示注册码合法,否则显示错误信息;

⑽  若要 T = 0,则 U0 = U1 = U2 = U3 = U4 = U5 = U6 = U7 = 0 即可;但是 Ui = Ri XOR Ni 或者 Ri OR Ni,如果 Ri 恒定大于等于20,则 Ui = Ri XOR Ni;此时只要 Ri = Ni ,则 Ui == 0,那么 T == 0 ,就得到了正确的注册码。

27. 下面以我们输入的用户名“ddcrack”和注册码“1234567890ABCDEF0”为例将注册码的算法演示一遍:

注册码:              1 2 3 4 5 6 7 8 9 0 A B C D E F 0

两个一组转变成对应形式的16进制值:  12  34  56  78    0A  BC  DE  F0    (第9位被剔除掉)

⑴  12 XOR 50 = 42;
   34 XOR 51 = 65;
   56 XOR 52 = 04;
   78 XOR 53 = 2B;
   0A XOR 54 = 5E;
   BC XOR 55 = E9;
   DE XOR 56 = 88;
   F0 XOR 57 = A7;

⑵  对于16进制数42,其计算过程为:
     1 * 42 =  42 <= 00008899
    42 * 42 = 1104 <= 00008899
   1104 * 42 = 46308 > 00008899,46308 MOD 8899 = 1E40
   1E40 * 42 = 7CC80 > 00008899,7CC80 MOD 8899 = 5422
   5422 * 42 = 15B0C4 > 00008899,15B0C4 MOD 8899 = 58DC
   58DC * 42 = 16E8B8 > 00008899,16E8B8 MOD 8899 = 7E9E
   7E9E * 42 = 20E6BC > 00008899,20E6BC MOD 8899 = 5A47

省略其它数的计算过程,结果汇总:

   42 -> 5A47
   65 -> 1F02
   04 -> 4000
   2B -> 6DE9
   5E -> 3566
   E9 -> 5CCC
   88 -> 79EC
   A7 -> 0A62

⑶  5A47 MOD BB = 6E
   1F02 MOD BB = 54
   4000 MOD BB = 73
   6DE9 MOD BB = 57
   3566 MOD BB = 13
   5CCC MOD BB = 07
   79EC MOD BB = AA
   0A62 MOD BB = 28

输入用户名:   ddcrack

格式化为8位:   d  d  c  r  a  c  k  d

对应的16进制值: 64  64  63  72 61  63  6B  64

⑷  64 XOR 6E = 0A
   64 XOR 54 = 30
   63 XOR 73 = 10
   72 XOR 57 = 25
   61 OR 13 = 73
   63 OR 07 = 67
   6B XOR AA = C1
   64 XOR 28 = 4C

⑸  累加和为:0A + 30 + 10 + 25 +73 + 67 +C1 + 4C = 256不等于0,所以注册码不正确。

27. 虽然我们已经掌握了注册码的算法过程,但是我们的目标还是没有达到——仍然没有取得正确的注册码?显然我们是不可能根据用户名“ddcrack”推导出正确的注册码的,尽管我们已经非常清楚地知道了注册码的算法(算法过程太复杂,除非你的大脑像电脑^_^),所以必须要换个角度,从现有对程序跟踪的结果来推导出一个合法的注册码;

28. 让我们回头看看:输入的注册码注册码“12 34 56 78 (9) 0A BC DE F0”经过运算最终分别得到16进制数“6E 54 73 57 13 07 AA 28”。前面提到只有注册码处理后的数值分别等于相应的用户名的ASCII码值即可通过注册算法,既然我们已经知道“12 34 56 78 0A BC DE F0”计算后可以得到“6E 54 73 57 13 07 AA 28”,而其中的“6E”“ 54”“ 73 ”“57”分别对应字母“n”“T”“s”“W”,所以我们何不如假设用户名就是“TTTTTTTT”呢?因为从前面的算法演示中可知65经过步骤⑵和步骤⑶得到54,即字母“T”。也就是说假如某一注册码经过处理后得到16进制数值“65 65 65 65 65 65 65 65”,然后经过步骤⑵和步骤⑶后就可以得到“54 54 54 54 54 54 54 54”,分别对应字符“T T T T T T T T”,现在假设用户名是“TTTTTTTT”,那么经过步骤⑷和步骤⑸计算后累加和肯定为零,说明这个注册码是正确的;

29. 假设某一注册码经过拼装后分别为16进制值Si,i=0,1,2,3,4,5,6,7,根据步骤⑴可知:

   S0 XOR 50 = 65
   S1 XOR 51 = 65
   S2 XOR 52 = 65
   S3 XOR 53 = 65
   S4 XOR 54 = 65
   S5 XOR 55 = 65
   S6 XOR 56 = 65
   S7 XOR 57 = 65

根据异或运算的可逆性,我可以求得Si:
   S0 = 65 XOR 50 = 35
   S1 = 65 XOR 51 = 34
   S2 = 65 XOR 52 = 37
   S3 = 65 XOR 53 = 36
   S4 = 65 XOR 54 = 31
   S5 = 65 XOR 55 = 30
   S6 = 65 XOR 56 = 33
   S7 = 65 XOR 57 = 32

30. 我们已知 35 34 37 36 31 30 33 32 分别是注册码的字符两个一组拼装起来的,而注册码的第9位没有进行任何处理,也就是说是任意的,不妨假设它为“5”,由此可得到用户名“TTTTTTTT”对应的正确注册码为“35343736531303332”,赶紧拿去试一试,怎么样啊?是不是很管用呢^_^!

31. 哇噻!终于讲完了,是不是很累啊!为了能得到符合自己大名的正确注册码,只能去写注册机,让电脑帮我们推算了。我自己也写了一个注册机,大家可以参考参考,不过因为前面注册码算法已经讲得很详细,所以注册机的C语言源代码中没有注释信息,这里可以下载:APISPY32注册机和C语言源程序;

32. 最后别忘了用 BC * 清除所有断点,祝你好运^_^!

  • 标 题:转贴:ddcrack的APISPY32 2.4的注册机 (2千字)
  • 时 间:2002-3-29 12:32:02
  • 链 接:http://bbs.pediy.com

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <time.h>
#include <conio.h>

void main(void)
{
    char * name="";
    char regname[8];
    char regcode[17];
    unsigned int table[16]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F};
    unsigned long eax;
    unsigned int bl,cl,dl=0xBB;
    int i,j,k,s,base;
    unsigned int inc1,inc2;
    int flag=0,success=1;

    clrscr();
    printf("\n************************************************************************\n");
    printf("APISPY32 V2.4 Registration Key Generator\n");
    printf("Author: ddcrack ( 2001/06/15 )\n");
    printf("************************************************************************\n\n");

    printf("Registration Name ( more than 5 letters ): ");
    scanf("%s",name);
    printf("\n");
    if(strlen(name)<5)
    do
    {
      printf("\nInput Registration Name again ( 5 letters at least ): ");
      scanf("%s",name);
      printf("\n");
    }
    while (strlen(name)<5);

    if(strlen(name)>=8)
      for(i=0;i<8;i++) regname[i]=*(name+i);
    else
      {
    for(i=0;i<strlen(name);i++) regname[i]=*(name+i);
    for(i=0;i<(8-strlen(name));i++) regname[strlen(name)+i]=*(name+i);
      }

    for(i=0;i<8;i++)
      { for(j=0;j<16;j++)
    { for(k=0;k<16;k++)
      { cl=table[j];
        cl=cl<<4;
        cl=cl|table[k];
        bl=0x50+(unsigned int)i;
        cl=cl^bl;
        eax=1;
        for(s=0;s<7;s++)
          { eax=eax*cl;
        if(eax>0x00008899) eax=eax%0x00008899;
          }
        eax=eax%dl;
        if(eax<0x00000020) continue;
        if(eax==(unsigned long)regname[i])
          {
        if(j<=9) inc1=0x30; else inc1=0x37;
        if(k<=9) inc2=0x30; else inc2=0x37;
        if(i<=3)
          {  regcode[2*i]=(char)(table[j]+inc1);
            regcode[2*i+1]=(char)(table[k]+inc2);
          }
        else
          {  regcode[2*i+1]=(char)(table[j]+inc1);
            regcode[2*i+2]=(char)(table[k]+inc2);
          }
        flag=1;
        break;
          }
        else flag=0;
      }
    if(flag==1) break;
      }
      if(flag==0)
    { printf("\nSorry! No such registration key which matchs your name.\n");
      success=0;
      break;
    }
    }

    if(success==1)
    { printf("Registration Key: ");
      randomize();
      base=random(16);
      if(base<=9) regcode[8]=(char)(base+0x30);
     else regcode[8]=(char)(base+0x37);
      for(i=0;i<17;i++) printf("%c",regcode[i]);
      printf("\n");
    }
    getch();
}



标 题:看看我原来写的protectz的keygen,就知道不用穷举了。(空)

  • 作 者:[最弱智]
  • 时 间:2002-3-29 16:03:16
    详细信息:

    RSA8 ;) N=187, E=7, D=23