标 题:毫无长进,喜欢上了爆破,哈哈,来篇爆破的,不要笑! (15千字)
发信人:Turkey2001
时 间:2002-3-25
18:32:53
详细信息:
目标: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
详细信息:
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
详细信息:
#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
| | |||
|