• 标 题:AddRemove 4GOOD 注册算法+注册机 
  • 作 者:RoBa
  • 时 间:2003/07/25 05:21pm
  • 链 接:http://bbs.pediy.com

AddRemove 4GOOD 2.0 完全破解 算法分析+注册机

最近一直在从古董光盘上找软件练习,这个软件至少也得有两三年的岁数了。以前一直在爆破,或者直接从内存中看出明码来,这次终于静下心来把算法仔细分析了一下,写出注册机来的感觉,爽!兴奋之余写下这篇文章,请各位大哥指正。

好,闲话少说,书归正题。运行软件,点击"Order Info",填入NAME: RoBa, CODE: 87654321

下bpx hmemcpy (我用的98),点Unlock,按22次F12到了AR4的领空,再按F10直到如下:

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040192E(C)
|
:00401949 E8D2FCFFFF              call 00401620<-这个是关键的CALL
:0040194E 85C0                    test eax, eax
:00401950 0F84A2000000            je 004019F8<-eax为0就完蛋了
:00401956 8D45E8                  lea eax, dword ptr [ebp-18]
:00401959 8D4DEC                  lea ecx, dword ptr [ebp-14]
:0040195C C745E800000000          mov [ebp-18], 00000000
:00401963 C745EC00000000          mov [ebp-14], 00000000
:0040196A 50                      push eax
:0040196B 51                      push ecx
:0040196C 6A00                    push 00000000
:0040196E 683F000F00              push 000F003F
:00401973 6A00                    push 00000000
:00401975 6A00                    push 00000000
:00401977 6A00                    push 00000000

在401949处F8跟进CALL,直接就来到这里:

* Referenced by a CALL at Addresses:
|:00401611   , :00401949  
|
:00401620 64A100000000            mov eax, dword ptr fs:[00000000]
:00401626 55                      push ebp
:00401627 8BEC                    mov ebp, esp
:00401629 6AFF                    push FFFFFFFF

* Possible StringData Ref from Code Obj ->"竝n@"
                                 |
:0040162B 68A5174000              push 004017A5
:00401630 B9FFFFFFFF              mov ecx, FFFFFFFF
:00401635 50                      push eax
:00401636 64892500000000          mov dword ptr fs:[00000000], esp
:0040163D 83EC0C                  sub esp, 0000000C
:00401640 2BC0                    sub eax, eax
:00401642 57                      push edi
:00401643 BF60834000              mov edi, 00408360
:00401648 F2                      repnz
:00401649 AE                      scasb
:0040164A F7D1                    not ecx
:0040164C 49                      dec ecx<-ecx为注册名的长度(下面简称长度)
:0040164D 83F906                  cmp ecx, 00000006<-与6比较
:00401650 7311                    jnb 00401663<-大于6就跳
                                             <-所以我把RoBa改为RoBa1986
                                           
* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:0040177F(U), :00401790(U)
|
:00401652 33C0                    xor eax, eax<-eax被干掉了

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040176E(U)
|
:00401654 8B4DF4                  mov ecx, dword ptr [ebp-0C]
:00401657 5F                      pop edi
:00401658 64890D00000000          mov dword ptr fs:[00000000], ecx
:0040165F 8BE5                    mov esp, ebp
:00401661 5D                      pop ebp
:00401662 C3                      ret<-如果长度小于6直接返回去就死翘翘了
<-所以我把RoBa改为RoBa1986

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:00401650(C)
|
:00401663 BF60834000              mov edi, 00408360
:00401668 B9FFFFFFFF              mov ecx, FFFFFFFF
:0040166D 2BC0                    sub eax, eax
:0040166F F2                      repnz
:00401670 AE                      scasb<-上面这几句会出现好几次,看不懂
:00401671 F7D1                    not ecx<-总之得到ecx为长度+1
:00401673 2BD2                    sub edx, edx
:00401675 8D41FF                  lea eax, dword ptr [ecx-01]<-eax为长度
:00401678 B90C000000              mov ecx, 0000000C<-ecx为0000000C(即十进制12)
:0040167D F7F1                    div ecx<-eax为长度除以ecx的整数部分
<-edx为长度除以ecx的余数

* Possible StringData Ref from Data Obj ->"87ae2401my69"<-一个小密码表
                                 |
:0040167F A15C834000              mov eax, dword ptr [0040835C]<-eax为密码表第一个字符的地址
:00401684 8D4DF0                  lea ecx, dword ptr [ebp-10]<-[ebp-10]即为长度+1
:00401687 8A0410                  mov al, byte ptr [eax+edx]<-得到密码表中第(edx+1)个字符
:0040168A 50                      push eax<-压入堆栈

* Possible StringData Ref from Data Obj ->"6582-"
                                 |
:0040168B 689C854000              push 0040859C<-把字串"6582-"压入

* Reference To: MFC40.Ordinal:01E3, Ord:01E3h
                                 |
:00401690 E8F13C0000              Call 00405386
:00401695 50                      push eax
:00401696 8D4DEC                  lea ecx, dword ptr [ebp-14]
:00401699 C745FC00000000          mov [ebp-04], 00000000
:004016A0 51                      push ecx

* Reference To: MFC40.Ordinal:0332, Ord:0332h
                                 |
:004016A1 E8EC3C0000              Call 00405392
:004016A6 C645FC02                mov [ebp-04], 02
:004016AA E8EE000000              call 0040179D
:004016AF BF60834000              mov edi, 00408360
:004016B4 B9FFFFFFFF              mov ecx, FFFFFFFF
:004016B9 C745F000000000          mov [ebp-10], 00000000
:004016C0 2BC0                    sub eax, eax
:004016C2 F2                      repnz
:004016C3 AE                      scasb
:004016C4 F7D1                    not ecx
:004016C6 49                      dec ecx
:004016C7 7478                    je 00401741

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:0040173F(C)
|
:004016C9 F645F001                test [ebp-10], 01<-循环开始
:004016CD 7559                    jne 00401728<-这里不知是怎么回事
<-如果[ebp-10]为偶数就跳过
<-也就是说只有奇数位参加计算
:004016CF 8B45F0                  mov eax, dword ptr [ebp-10]
:004016D2 8A8060834000            mov al, byte ptr [eax+00408360]<-得到要计算的字符
:004016D8 3C7F                    cmp al, 7F<-与7F比较
:004016DA 0F8F93000000            jg 00401773<-大于就跳
:004016E0 3C20                    cmp al, 20<-与20比较
:004016E2 0F8C9C000000            jl 00401784<-小于就跳
<-键盘输入的字符都在这个范围吧?
:004016E8 6698                    cbw
:004016EA B102                    mov cl, 02<-cl=2
:004016EC F6F9                    idiv cl<-al为al除以2的整数部分
:004016EE 0420                    add al, 20<-al=al+20;
:004016F0 3C5A                    cmp al, 5A<-与5A比较,ASC(5A)='Z'
:004016F2 7E06                    jle 004016FA<-小于等于就跳
:004016F4 3C61                    cmp al, 61<-与61比较,ASC(61)='a'
:004016F6 7D02                    jge 004016FA<-大于等于就跳
:004016F8 0406                    add al, 06<-如果al在5A与61之间则+6

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004016F2(C), :004016F6(C)
|
:004016FA 3C39                    cmp al, 39<-与39比较,ASC(39)='9'
:004016FC 7E06                    jle 00401704<-小于等于就跳
:004016FE 3C41                    cmp al, 41<-与41比较,ASC(41)='A'
:00401700 7D02                    jge 00401704<-大于等于就跳
:00401702 0408                    add al, 08<-如果al在39与41之间则+8

* Referenced by a (U)nconditional or (C)onditional Jump at Addresses:
|:004016FC(C), :00401700(C)
|
:00401704 50                      push eax<-把结果压入堆栈
:00401705 8D4DE8                  lea ecx, dword ptr [ebp-18]
:00401708 8D45EC                  lea eax, dword ptr [ebp-14]
:0040170B 50                      push eax
:0040170C 51                      push ecx

* Reference To: MFC40.Ordinal:0332, Ord:0332h
                                 |
:0040170D E8803C0000              Call 00405392
:00401712 50                      push eax
:00401713 8D4DEC                  lea ecx, dword ptr [ebp-14]
:00401716 C645FC03                mov [ebp-04], 03

* Reference To: MFC40.Ordinal:02F8, Ord:02F8h
                                 |
:0040171A E86D3C0000              Call 0040538C
:0040171F C645FC02                mov [ebp-04], 02
:00401723 E86D000000              call 00401795

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004016CD(C)
|
:00401728 BF60834000              mov edi, 00408360
:0040172D B9FFFFFFFF              mov ecx, FFFFFFFF
:00401732 FF45F0                  inc [ebp-10]<-[ebp-10]+1
:00401735 2BC0                    sub eax, eax
:00401737 F2                      repnz
:00401738 AE                      scasb
:00401739 F7D1                    not ecx
:0040173B 49                      dec ecx<-得到注册名长度
:0040173C 3B4DF0                  cmp ecx, dword ptr [ebp-10]<-将长度与[ebp-10]比较
:0040173F 7788                    ja 004016C9<-大于则跳回去算下一个数
<-可以看出[ebp-10]为循环变量

* Referenced by a (U)nconditional or (C)onditional Jump at Address:
|:004016C7(C)
|
:00401741 6860844000              push 00408460<-d 408460可看到假码
:00401746 8B45EC                  mov eax, dword ptr [ebp-14]
:00401749 50                      push eax<-d eax即可看到正确的注册码

* Reference To: MSVCRT40._mbscmp, Ord:02ECh
                                 |
:0040174A FF1510A84000            Call dword ptr [0040A810]
:00401750 83C408                  add esp, 00000008
:00401753 8B4DF0                  mov ecx, dword ptr [ebp-10]
:00401756 C745FCFFFFFFFF          mov [ebp-04], FFFFFFFF
:0040175D 83F801                  cmp eax, 00000001
:00401760 194DF0                  sbb dword ptr [ebp-10], ecx
:00401763 F75DF0                  neg [ebp-10]
:00401766 E844000000              call 004017AF
:0040176B 8B45F0                  mov eax, dword ptr [ebp-10]
:0040176E E9E1FEFFFF              jmp 00401654
...........

可以看到注册码由三部分组成: 固定字串"6582-"+在密码表中得到的一个字符+注册名经过运算得到的字符

一个简易的注册机: (Borland Pascal 7.0)(写得很烂,高手莫笑)

Program CrackADDREMOVE;
var name,code,st :string;
   ch :char;
   len,p :integer;
begin
    st:='87ae2401my69';
    repeat
          write('Please input the name:');
          readln(name);
          len:=length(name);
    until len>=6;
    ch:=st[(len mod 12)+1];
    code:='6582-'+ch;
    for p:=1 to len do
    if (p mod 2)=1 then
    begin
       ch:=name[p];
       ch:=chr(ord(ch) div 2+32);
       if (ch>'Z') and (ch<'a') then ch:=chr(ord(ch)+6);
       if (ch>'9') and (ch<'A') then ch:=chr(ord(ch)+8);
       code:=code+ch;
    end;
    writeln('Your Register Code is:',code);
    writeln;
    writeln('Crack by RoBa         Thank you');
end.

我实在不明白代码中出现很多次的 repnz  scasb 是什么意思,请大侠指教。