Absolut Chess v1.5 注册算法分析

Absolut Chess v1.5 是一个国际象棋软件。下载的版本是演示版,有 10 次使用次数限制,否则将不能运行。演示版不能输入注册码(但实际上功能存在的,被隐藏掉了)。

补丁部分

首先是去掉使用次数限制。
10 次以后会跳出一个框,在 DialogBoxParamA 上设断点顺利截到。

0040F9EF   833D 50834300 00    cmp     dword ptr [438350], 0
0040F9F6   0F84 39000000       je      0040FA35
0040F9FC   6A 00               push    0                           ; /lParam = NULL
0040F9FE   68 0F104000         push    0040100F                    ; |DlgProc = AbsolutC.0040100F
0040FA03   8B45 08             mov     eax, dword ptr [ebp+8]      ; |
0040FA06   50                  push    eax                         ; |hOwner
0040FA07   68 30874300         push    00438730                    ; |pTemplate = "DLG_BUY"
0040FA0C   A1 848B4500         mov     eax, dword ptr [458B84]     ; |
0040FA11   50                  push    eax                         ; |hInst => 00400000
0040FA12   FF15 E0284700       call    dword ptr [<&USER32.DialogB>; /DialogBoxParamA
0040FA18   8945 E4             mov     dword ptr [ebp-1C], eax
0040FA1B   837D E4 00          cmp     dword ptr [ebp-1C], 0
0040FA1F   0F85 10000000       jnz     0040FA35
0040FA25   6A 00               push    0                           ; /lParam = 0
0040FA27   6A 00               push    0                           ; |wParam = 0
0040FA29   6A 02               push    2                           ; |Message = WM_DESTROY
0040FA2B   8B45 08             mov     eax, dword ptr [ebp+8]      ; |
0040FA2E   50                  push    eax                         ; |hWnd
0040FA2F   FF15 E4284700       call    dword ptr [<&USER32.SendMes>; /SendMessageA
0040FA35   833D 985E4400 00    cmp     dword ptr [445E98], 0

这部分第一行可以看到,根据 [438350] 是否为 0 来判断要不要显式使用次数已到的框。
再往上看:

0040F8D9   833D 948C4500 0A    cmp     dword ptr [458C94], 0A
0040F8E0   0F8E 0A000000       jle     0040F8F0
0040F8E6   C705 50834300 01000 mov     dword ptr [438350], 1
0040F8F0   C705 40834300 00000 mov     dword ptr [438340], 0
0040F8FA   E9 9F000000         jmp     0040F99E

 

如果 [458C94] <= 0Ah(10),就跳过给 [438350] 赋为 1 的那句。
由此推断,[458C94] 里面是当前使用次数。
重新开始调试,给 00458C94 设置内存写入硬件断点。
截到读取注册表写入内存变量部分如下:

0040E37E   C785 0CFCFFFF 04000 mov     dword ptr [ebp-3F4], 4
0040E388   8D85 0CFCFFFF       lea     eax, dword ptr [ebp-3F4]
0040E38E   50                  push    eax                         ; /pBufSize
0040E38F   8D85 10FCFFFF       lea     eax, dword ptr [ebp-3F0]    ; |
0040E395   50                  push    eax                         ; |Buffer
0040E396   6A 00               push    0                           ; |pValueType = NULL
0040E398   6A 00               push    0                           ; |Reserved = NULL
0040E39A   68 48854300         push    00438548                    ; |ValueName = "cvezes"
0040E39F   8B85 14FCFFFF       mov     eax, dword ptr [ebp-3EC]    ; |
0040E3A5   50                  push    eax                         ; |hKey
0040E3A6   FF15 74254700       call    dword ptr [<&ADVAPI32.RegQu>; /RegQueryValueExA
0040E3AC   8985 BCF7FFFF       mov     dword ptr [ebp-844], eax
0040E3B2   83BD BCF7FFFF 00    cmp     dword ptr [ebp-844], 0
0040E3B9   0F85 16000000       jnz     0040E3D5
0040E3BF   8B85 10FCFFFF       mov     eax, dword ptr [ebp-3F0]     ; 注册表中的值
0040E3C5   35 F4FE0E00         xor     eax, 0EFEF4                  ; 0xEFEF4^0xEFEF4=0, 0xEFEF4^0xEFEFF=0Ah
0040E3CA   A3 948C4500         mov     dword ptr [458C94], eax      ; 写到内存变量
0040E3CF   FF05 948C4500       inc     dword ptr [458C94]           ; 使用次数加1

于是可以把 eax, 0EFEF4 这据改掉,改为 xor eax, eax,这样每次都是第一次了。

第一处改动:0040E3C5   .  35 F4FE0E00         xor     eax, 0EFEF4
改为
0040E3C5      33C0                xor     eax, eax
0040E3C7      90                  nop
0040E3C8      90                  nop
0040E3C9      90                  nop

文件修补:0000D7C5 35 F4 FE 0E 00 -> 33 C0 90 90 90

接下来是两处输入注册码的按钮。

先是 10 次使用满了跳出来的那个框里。

按下输入注册码按钮,出来一个框说演示版不能注册。这个框是 MessageBox。
在 MessageBoxA 上设断点,调用处:

0041F7F1   837D F4 02    cmp     dword ptr [ebp-C], 2
0041F7F5   0F84 72FFFFFF je      0041F76D
看到 0041F76D 附近:

0041F76D   > /6A 30           push    30                               ; /Style = MB_OK|MB_ICONEXCLAMATION|MB_APPLMODAL
0041F76F   . |68 50954300     push    00439550                         ; |Title = "Demo Version"
0041F774   . |68 60954300     push    00439560                         ; |Text = "Operation do not allowed in this demo.",LF,LF,"Buy the full version online!",LF,LF,"http://www.overlans.com/shop.php",LF,LF,"Only $ 12"
0041F779   . |8B45 08         mov     eax, dword ptr [ebp+8]           ; |
0041F77C   . |50              push    eax                              ; |hOwner
0041F77D   . |FF15 54284700   call    dword ptr [<&USER32.MessageBoxA>>; /MessageBoxA
0041F783   . |68 D4954300     push    004395D4                         ; /Title = "Microsoft Internet Explorer"
0041F788   . |6A 00           push    0                                ; |Class = 0
0041F78A   . |6A 00           push    0                                ; |hAfterWnd = NULL
0041F78C   . |6A 00           push    0                                ; |hParent = NULL
0041F78E   . |FF15 68284700   call    dword ptr [<&USER32.FindWindowEx>; /FindWindowExA
0041F794   . |8945 FC         mov     dword ptr [ebp-4], eax
0041F797   . |6A 01           push    1                                ; /IsShown = 1
0041F799   . |6A 00           push    0                                ; |DefDir = NULL
0041F79B   . |6A 00           push    0                                ; |Parameters = NULL
0041F79D   . |68 F0954300     push    004395F0                         ; |FileName = "http://www.overlans.com/shop.php"
0041F7A2   . |68 14964300     push    00439614                         ; |Operation = "open"
0041F7A7   . |8B45 FC         mov     eax, dword ptr [ebp-4]           ; |
0041F7AA   . |50              push    eax                              ; |hWnd
0041F7AB   . |FF15 1C284700   call    dword ptr [<&SHELL32.ShellExecut>; /ShellExecuteA
0041F7B1   . |E9 27000000     jmp     0041F7DD
0041F7B6   . |6A 00           push    0                                ; /lParam = NULL
0041F7B8   . |68 90114000     push    00401190                         ; |DlgProc = AbsolutC.00401190
0041F7BD   . |8B45 08         mov     eax, dword ptr [ebp+8]           ; |
0041F7C0   . |50              push    eax                              ; |hOwner
0041F7C1   . |68 1C964300     push    0043961C                         ; |pTemplate = "DLG_LICENCA"
0041F7C6   . |A1 848B4500     mov     eax, dword ptr [458B84]          ; |
0041F7CB   . |50              push    eax                              ; |hInst => NULL
0041F7CC   . |FF15 E0284700   call    dword ptr [<&USER32.DialogBoxPar>; /DialogBoxParamA
0041F7D2   . |50              push    eax                              ; /Result
0041F7D3   . |8B45 08         mov     eax, dword ptr [ebp+8]           ; |
0041F7D6   . |50              push    eax                              ; |hWnd
0041F7D7   . |FF15 F8284700   call    dword ptr [<&USER32.EndDialog>]  ; /EndDialog
0041F7DD   > |E9 2B000000     jmp     0041F80D

看到先跳出一个框,再打开一个网址。注意到紧跟在它后面的 0041F7B6,DLG_LICENCA 这个名字好像是我们期待的。把 0041F7F5 的跳转改为 je 0041F7B6 试试看,果然见到了那个框。
第二处改动:0041F7F5 0F 84 72 FF FF FF (je long 0041F76D) 改为 0F 84 BB FF FF FF (je long 0041F7B6)                                          也可改为 74 BF 90 90 90 90 (je short 0041F7B6)

文件修补:0001EBF7 72 -> BB


再是帮助菜单里的注册菜单项。

同样截 MessageBoxA,可以找到 00410594 这个函数是调用者。它显示 Demo 版不可注册,并打开网址。
跟上面一模一样,紧跟在其后的 004105DD  用于弹出注册框用于输入。

向上看,找到

00411666  8B85 FCFBFFFF mov  eax, dword ptr [ebp-404]   ; eax=[0012F9Ec]=0000001A
0041166C  33C9          xor  ecx, ecx
0041166E  8A88 1F174100 mov  cl, byte ptr [eax+41171F]  ; cl=[41171F+1A]=[411739]=12
00411674  FF248D 7B1641 jmp  dword ptr [ecx*4+41167B]   ; [ecx*4+41167B]=[004116C3]=00410594

004116C3 处存放着这个地址。于是第三处改动:把 004116C3 处 94 05 41 00 改为 DD 05 41 00 就好了。文件修补:00010AC3 94 -> DD

下面来分析注册判断流程。

随便输注册码,截 MessageBoxA。下面这段是相关内容和分析:

 

0041FEE9  8D85 38FFFFFF lea  eax, dword ptr [ebp-C8]    ; 注册码 "1234"
0041FEEF  50            push eax                        ; 00401177 参数三
0041FEF0  8D45 9C       lea  eax, dword ptr [ebp-64]    ; 用户名 "kjj"
0041FEF3  50            push eax                        ; 00421B30 参数
0041FEF4  E8 371C0000   call 00421B30                   ; 求用户名长度?
0041FEF9  83C4 04       add  esp, 4                     ; 这里看出上面这个函数只有一个参数, "1234" 不是它的
0041FEFC  50            push eax                        ; eax=3, 00401177 参数二
0041FEFD  8D45 9C       lea  eax, dword ptr [ebp-64]    ; [ebp-64]="kjj"
0041FF00  50            push eax                        ; 00401177 参数一
0041FF01  E8 7112FEFF   call 00401177                   ;
{
    00401177  E9 F0CD0000   jmp  0040DF6C

    0040DF6C  55            push    ebp
    0040DF6D  8BEC          mov     ebp, esp
    0040DF6F  83EC 24       sub     esp, 24
    0040DF72  53            push    ebx
    0040DF73  56            push    esi
    0040DF74  57            push    edi
    0040DF75  837D 0C 00    cmp     dword ptr [ebp+C], 0    ; [ebp+C]=00000003, 用户名长度
    0040DF79  0F8F 07000000 jg      0040DF86
    0040DF7F  33C0          xor     eax, eax
    0040DF81  E9 80000000   jmp     0040E006
    0040DF86  8B45 10       mov     eax, dword ptr [ebp+10] ; [ebp+10]=[0012F614]=0012F62C="1234"
    0040DF89  50            push    eax                     ; 004012A8 的参数
    0040DF8A  E8 1933FFFF   call    004012A8                ; 判断是否是 20 个万能注册码之一
    {
        004012A8  E9 C3C50000   jmp     0040D870

        0040D870  55            push    ebp
        0040D871  8BEC          mov     ebp, esp
        0040D873  83EC 04       sub     esp, 4
        0040D876  53            push    ebx
        0040D877  56            push    esi
        0040D878  57            push    edi
        0040D879  C745 FC 00000 mov     dword ptr [ebp-4], 0        ; 这里把 [ebp-4] 弄成 0 了
        0040D880  E9 03000000   jmp     0040D888
        0040D885  FF45 FC       inc     dword ptr [ebp-4]           ; 循环首, [ebp-4] 加 1
        0040D888  A1 0C834300   mov     eax, dword ptr [43830C]
        0040D88D  3945 FC       cmp     dword ptr [ebp-4], eax
        0040D890  0F8D 34000000 jge     0040D8CA
        0040D896  8B45 08       mov     eax, dword ptr [ebp+8]      ; eax=[0012F400]="1234", 输入的注册码
        0040D899  50            push    eax                         ; 参数二
        0040D89A  8B45 FC       mov     eax, dword ptr [ebp-4]      ; eax=[ebp-4]
                                                                    ; 1st: 刚才它被弄成 0 了, 于是 eax=0
        0040D89D  03C0          add     eax, eax                    ; eax=eax*2=[ebp-4]*2
        0040D89F  8D0440        lea     eax, dword ptr [eax+eax*2]  ; eax=eax*3=[ebp-4]*6
        0040D8A2  8D0480        lea     eax, dword ptr [eax+eax*4]  ; eax=eax*5=[ebp-4]*1E, 于是这里都是 0
        0040D8A5  05 887F4300   add     eax, 00437F88               ; 00437F88="Ab200001FRvGKF"
                ; 这里有一张表:
                ; 00437F88+ 0*1E: Ab200001FRvGKF
                ; 00437F88+ 1*1E: Ab20001Mdvl6Il
                ; 00437F88+ 2*1E: Ab20002qMv1oxy
                ; 00437F88+ 3*1E: Ab20003C9kz5Kj
                ; 00437F88+ 4*1E: Ab20004oXz3iYB
                ; 00437F88+ 5*1E: Ab20005v63uo5b
                ; 00437F88+ 6*1E: Ab20006xx6wmGk
                ; 00437F88+ 7*1E: Ab20007iXrxYgx
                ; 00437F88+ 8*1E: Ab20008CAO55EP
                ; 00437F88+ 9*1E: Ab20009TUwNMYe
                ; 00437F88+ A*1E: Ab20010askrZO9
                ; 00437F88+ B*1E: Ab20011Q6VvIYZ
                ; 00437F88+ C*1E: Ab200122PGq2NF
                ; 00437F88+ D*1E: Ab20013KuI3ByH
                ; 00437F88+ E*1E: Ab20014hGZnATH
                ; 00437F88+ F*1E: Ab20015CIZD4Ji
                ; 00437F88+10*1E: Ab20016qGqvpsn
                ; 00437F88+11*1E: Ab200179Fq3nts
                ; 00437F88+12*1E: Ab20018QLHV24h
                ; 00437F88+13*1E: Ab20019nbbma0w
        0040D8AA  50            push    eax         ; 参数一, "Ab200001FRvGKF"
        0040D8AB  E8 F0410100   call    00421AA0    ; 这里面就是简单的字符串比较,害得我看了半天
        0040D8B0  83C4 08       add     esp, 8
        0040D8B3  85C0          test    eax, eax
        0040D8B5  0F85 0A000000 jnz     0040D8C5
        0040D8BB  B8 01000000   mov     eax, 1      ; 如果相同, 令 eax=1
        0040D8C0  E9 0C000000   jmp     0040D8D1    ; 跳到后面, 跳出这个函数, 这个函数返回值就是 1 了
        0040D8C5  E9 BBFFFFFF   jmp     0040D885
        0040D8CA  33C0          xor     eax, eax
        0040D8CC  E9 00000000   jmp     0040D8D1
        0040D8D1  5F            pop     edi
        0040D8D2  5E            pop     esi
        0040D8D3  5B            pop     ebx
        0040D8D4  C9            leave
        0040D8D5  C3            retn
    }
    0040DF8F  83C4 04       add     esp, 4
    0040DF92  85C0          test    eax, eax
    0040DF94  0F84 0A000000 je      0040DFA4                ; 如果不是万能注册码, 跳过下面两行
    0040DF9A  B8 01000000   mov     eax, 1                  ; 如果是万能注册码, 令 eax=1
    0040DF9F  E9 62000000   jmp     0040E006                ; 跳到后面, 跳出函数
                                                            ; 下面是非万能注册码时的处理
    0040DFA4  E8 2E31FFFF   call    004010D7                ; 把字母和数字数了个遍
                                                            ; [462658]=0000003E(62), al='Z'
    0040DFA9  8D45 DC       lea     eax, dword ptr [ebp-24] ; [ebp-24]=[0012F5E0], 缓冲区, 参数三
    0040DFAC  50            push    eax
    0040DFAD  8B45 0C       mov     eax, dword ptr [ebp+C]  ; eax=3, 用户名长度, 参数二
    0040DFB0  50            push    eax
    0040DFB1  8B45 08       mov     eax, dword ptr [ebp+8]  ; eax="kjj", 用户名, 参数一
    0040DFB4  50            push    eax
    0040DFB5  E8 1133FFFF   call    004012CB                ; 算法在这里, 详细内容见下面
                                                            ; [ebp-24]="CH&aIaJaIaIaJaIaIaKxA9"
    0040DFBA  83C4 0C       add     esp, 0C
    0040DFBD  C745 FC 00000 mov     dword ptr [ebp-4], 0
    0040DFC4  E9 03000000   jmp     0040DFCC
    0040DFC9  FF45 FC       inc     dword ptr [ebp-4]       ; 这个循环用来比较注册码是否正确
    0040DFCC  837D FC 12    cmp     dword ptr [ebp-4], 12   ; 仅仅比较前 18 位
    0040DFD0  0F8D 26000000 jge     0040DFFC
    0040DFD6  8B45 FC       mov     eax, dword ptr [ebp-4]
    0040DFD9  8B4D 10       mov     ecx, dword ptr [ebp+10]
    0040DFDC  0FBE0408      movsx   eax, byte ptr [eax+ecx]
    0040DFE0  8B4D FC       mov     ecx, dword ptr [ebp-4]
    0040DFE3  0FBE4C0D DC   movsx   ecx, byte ptr [ebp+ecx-24]
    0040DFE8  3BC1          cmp     eax, ecx
    0040DFEA  0F84 07000000 je      0040DFF7
    0040DFF0  33C0          xor     eax, eax
    0040DFF2  E9 0F000000   jmp     0040E006
    0040DFF7  E9 CDFFFFFF   jmp     0040DFC9
    0040DFFC  B8 01000000   mov     eax, 1
    0040E001  E9 00000000   jmp     0040E006
    0040E006  5F            pop     edi
    0040E007  5E            pop     esi
    0040E008  5B            pop     ebx
    0040E009  C9            leave
    0040E00A  C3            retn
}
0041FF06  83C4 0C       add  esp, 0C                    ; 这里看出这个函数是三个参数
0041FF09  85C0          test eax, eax
0041FF0B  0F84 56000000 je   0041FF67                   ; 无效注册码最后看注册算法这个函数。
004012CB   E9 3DC80000   jmp     0040DB0D

 

最后来看算注册码的函数。

 

0040DB0D   55            push    ebp
0040DB0E   8BEC          mov     ebp, esp
                                                            ; 传入参数
                                                            ; [ebp+8]: char *username
                                                            ; [ebp+C]: int length
                                                            ; [ebp+10]: char *buffer
0040DB10   83EC 10       sub     esp, 10                    ; 4 个局部变量, 记为 int var[4]
0040DB13   53            push    ebx
0040DB14   56            push    esi
0040DB15   57            push    edi
0040DB16   C745 F0 03000 mov     dword ptr [ebp-10], 3      ; [ebp-10]=0012F5B0=00000003, var[0]=3
0040DB1D   837D 0C 00    cmp     dword ptr [ebp+C], 0       ; 判断用户名是否零长度
0040DB21   0F8F 05000000 jg      0040DB2C
0040DB27   E9 4F010000   jmp     0040DC7B
0040DB2C   E8 A635FFFF   call    004010D7                   ; 又是这个函数, [462658]=0000003E, al='Z'
0040DB31   A0 807F4300   mov     al, byte ptr [437F80]      ; [437F80]='C'
0040DB36   8B4D 10       mov     ecx, dword ptr [ebp+10]    ; 缓冲区地址, 刚才的第三个参数
0040DB39   8801          mov     byte ptr [ecx], al
0040DB3B   A0 817F4300   mov     al, byte ptr [437F81]      ; [437F81]='H'
0040DB40   8B4D 10       mov     ecx, dword ptr [ebp+10]
0040DB43   8841 01       mov     byte ptr [ecx+1], al
0040DB46   A0 827F4300   mov     al, byte ptr [437F82]      ; [437F82]='&'
0040DB4B   8B4D 10       mov     ecx, dword ptr [ebp+10]
0040DB4E   8841 02       mov     byte ptr [ecx+2], al       ; 把 "CH&" 拷到缓冲区
0040DB51   C745 F4 03000 mov     dword ptr [ebp-C], 3       ; [ebp-C]=00000003, var[1]=3, var[1] 记为 i
0040DB58   E9 03000000   jmp     0040DB60                   ; 进入循环
0040DB5D   FF45 F4       inc     dword ptr [ebp-C]          ; 循环首
0040DB60   837D F4 12    cmp     dword ptr [ebp-C], 12      ; 一直循环到 i>=12,循环 15 次
0040DB64   0F8D 97000000 jge     0040DC01
0040DB6A   8B45 F4       mov     eax, dword ptr [ebp-C]     ; eax=i=3
0040DB6D   99            cdq                                ; edx=0
0040DB6E   F77D 0C       idiv    dword ptr [ebp+C]          ; eax=i/length=1, edx=i%length=0
0040DB71   8955 FC       mov     dword ptr [ebp-4], edx     ; var[3]=edx=i%length=0, var[3] 记为 r1
0040DB74   8B45 F4       mov     eax, dword ptr [ebp-C]     ; eax=i=3
0040DB77   0345 F0       add     eax, dword ptr [ebp-10]    ; eax=eax+var[0]=eax+3=6
0040DB7A   99            cdq                                ; edx=0
0040DB7B   F77D 0C       idiv    dword ptr [ebp+C]          ; eax=(i+3)/length=2, edx=(i+3)%length=0
0040DB7E   8955 F8       mov     dword ptr [ebp-8], edx     ; var[2]=edx=(i+3)%length=0,  var[2] 记为 r2
0040DB81   8B45 F4       mov     eax, dword ptr [ebp-C]     ; eax=i=3
0040DB84   99            cdq                                ; edx=0
0040DB85   33C2          xor     eax, edx                   ; eax=3
0040DB87   2BC2          sub     eax, edx                   ; eax=3
0040DB89   83E0 01       and     eax, 1                     ; eax=1
0040DB8C   33C2          xor     eax, edx                   ; eax=1
0040DB8E   2BC2          sub     eax, edx                   ; eax=1
                                                            ; 这段是判断 i 的奇偶
0040DB90   0F84 34000000 je      0040DBCA
0040DB96   8B45 F8       mov     eax, dword ptr [ebp-8]     ; eax=r2=0
0040DB99   8B4D 08       mov     ecx, dword ptr [ebp+8]     ; ecx=username
0040DB9C   0FBE0408      movsx   eax, byte ptr [eax+ecx]    ; eax=username[r2]
0040DBA0   8B4D FC       mov     ecx, dword ptr [ebp-4]     ; ecx=r1
0040DBA3   8B55 08       mov     edx, dword ptr [ebp+8]     ; edx=username
0040DBA6   320411        xor     al, byte ptr [ecx+edx]     ; al=al^username[r1]=username[r2]^username[r2]=0
0040DBA9   33C9          xor     ecx, ecx                   ; ecx=0
0040DBAB   8AC8          mov     cl, al                     ; cl=al=0
0040DBAD   8BC1          mov     eax, ecx                   ; eax=0
0040DBAF   99            cdq                                ; edx=0
0040DBB0   F73D 58264600 idiv    dword ptr [462658]         ; eax=eax/3E=0, edx=eax%3E=0
0040DBB6   8A82 60CA4600 mov     al, byte ptr [edx+46CA60]  ; al=chr[edx]='a'
; 46CA60: abcdefghijklmnopqrstuvwxyz0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ, 记为 char chr[62];
0040DBBC   8B4D F4       mov     ecx, dword ptr [ebp-C]     ; eax=i=3
0040DBBF   8B55 10       mov     edx, dword ptr [ebp+10]    ; edx=buffer
0040DBC2   880411        mov     byte ptr [ecx+edx], al     ; buffer[i]=al
; 小结(i 奇的时候)
; r1 = i % length;
; r2 = (i+3) % length;
; offset = (username[r]^username[r2]) % 0x5E;
; buffer[i] = chr[offset];
0040DBC5   E9 32000000   jmp     0040DBFC
0040DBCA   8B45 F8       mov     eax, dword ptr [ebp-8]     ; eax=r2=0
0040DBCD   8B4D 08       mov     ecx, dword ptr [ebp+8]     ; ecx=username
0040DBD0   0FBE0408      movsx   eax, byte ptr [eax+ecx]    ; eax=username[r2]
0040DBD4   8B4D FC       mov     ecx, dword ptr [ebp-4]     ; ecx=r1
0040DBD7   8B55 08       mov     edx, dword ptr [ebp+8]     ; edx=username
0040DBDA   0FBE0C11      movsx   ecx, byte ptr [ecx+edx]    ; eax=username[r1]
0040DBDE   23C1          and     eax, ecx                   ; eax=username[r2]&username[r1]
0040DBE0   33C9          xor     ecx, ecx
0040DBE2   8AC8          mov     cl, al
0040DBE4   8BC1          mov     eax, ecx                   ; eax 取最后两位
0040DBE6   99            cdq
0040DBE7   F73D 58264600 idiv    dword ptr [462658]
0040DBED   8A82 60CA4600 mov     al, byte ptr [edx+46CA60]
0040DBF3   8B4D F4       mov     ecx, dword ptr [ebp-C]
0040DBF6   8B55 10       mov     edx, dword ptr [ebp+10]
0040DBF9   880411        mov     byte ptr [ecx+edx], al     ; buffer[i]=al
; 小结(i 偶的时候)
; r1 = i % length;
; r2 = (i+3) % length;
; offset = (username[r]&username[r2]) % 0x5E;
; buffer[i] = chr[offset];
0040DBFC   E9 5CFFFFFF   jmp     0040DB5D                   ; 循环尾
0040DC01   6A 00         push    0
0040DC03   E8 D8390100   call    004215E0                   ; 生成一个随机值
0040DC08   83C4 04       add     esp, 4
0040DC0B   50            push    eax                        ; 这个值作为下面的用的值
0040DC0C   E8 8F390100   call    004215A0                   ; 仅仅设置一个初始值而已,看了好久,太浪费时间了
0040DC11   83C4 04       add     esp, 4
0040DC14   E8 97390100   call    004215B0
0040DC19   99            cdq
0040DC1A   F73D 58264600 idiv    dword ptr [462658]
0040DC20   8A82 60CA4600 mov     al, byte ptr [edx+46CA60]
0040DC26   8B4D 10       mov     ecx, dword ptr [ebp+10]
0040DC29   8841 12       mov     byte ptr [ecx+12], al      ; 加一个字符(但是注册码仅仅比较前面 18 位,这些是没用的)
0040DC2C   E8 7F390100   call    004215B0
0040DC31   99            cdq
0040DC32   F73D 58264600 idiv    dword ptr [462658]
0040DC38   8A82 60CA4600 mov     al, byte ptr [edx+46CA60]
0040DC3E   8B4D 10       mov     ecx, dword ptr [ebp+10]
0040DC41   8841 13       mov     byte ptr [ecx+13], al      ; 再加一个字符
0040DC44   E8 67390100   call    004215B0
0040DC49   99            cdq
0040DC4A   F73D 58264600 idiv    dword ptr [462658]
0040DC50   8A82 60CA4600 mov     al, byte ptr [edx+46CA60]
0040DC56   8B4D 10       mov     ecx, dword ptr [ebp+10]
0040DC59   8841 14       mov     byte ptr [ecx+14], al      ; 再加一个字符
0040DC5C   E8 4F390100   call    004215B0
0040DC61   99            cdq
0040DC62   F73D 58264600 idiv    dword ptr [462658]
0040DC68   8A82 60CA4600 mov     al, byte ptr [edx+46CA60]
0040DC6E   8B4D 10       mov     ecx, dword ptr [ebp+10]
0040DC71   8841 15       mov     byte ptr [ecx+15], al      ; 再加一个字符
0040DC74   8B45 10       mov     eax, dword ptr [ebp+10]
0040DC77   C640 16 00    mov     byte ptr [eax+16], 0       ; 结束符
0040DC7B   5F            pop     edi
0040DC7C   5E            pop     esi
0040DC7D   5B            pop     ebx
0040DC7E   C9            leave
0040DC7F   C3            retn

 

与最后面的 4 位生成有关的是 004215E0、004215A0、004215B0 这三个函数。由于经验不足,我在里面分析了好久。后来搞累了,随便乱输最后 4 位,发现总是可以的。不断的看软件自己生成的注册码,最后 4 位总是不一样的。然后回过头来看注册码比较的地方,是无视最后 4 位的,才知道那 4 位无关紧要。再再再后来用 IDA 看,原来是 _time、_srand、_rand 这三个函数……

把那些白看了的也贴出来吧

 

{
    004215E0  83EC 10       sub     esp, 10
    004215E3  8D4424 00     lea     eax, dword ptr [esp]                ; buffer
    004215E7  50            push    eax                                 ; pLocaltime
    004215E8  FF15 10274700 call    dword ptr [<&KERNEL32.GetLocalTime> ; GetLocalTime
    ; D8 07 06 00 06 00 07 00 0F 00 2D 00 03 00 2C 03
    ; typedef struct _SYSTEMTIME
    ; {
    ;     WORD wYear;           // 0x07D8=2008
    ;     WORD wMonth;          // 0x0006=6
    ;     WORD wDayOfWeek;      // 0x0007=6(Sat.)
    ;     WORD wDay;            // 0x0007=7
    ;     WORD wHour;           // 0x000F=15)
    ;     WORD wMinute;         // 0x002D=45
    ;     WORD wSecond;         // 0x0003=3
    ;     WORD wMilliseconds;   // 0x032C=812 (15:45:03.812)
    ; } SYSTEMTIME,  *PSYSTEMTIME;
    004215EE  8B4424 0C     mov     eax, dword ptr [esp+C]
    004215F2  25 FFFF0000   and     eax, 0FFFF              ; 秒   00000023
    004215F7  50            push    eax
    004215F8  33C0          xor     eax, eax
    004215FA  66:8B4424 0E  mov     ax, word ptr [esp+E]    ; 分钟 00000021
    004215FF  50            push    eax
    00421600  8B4424 10     mov     eax, dword ptr [esp+10]
    00421604  25 FFFF0000   and     eax, 0FFFF              ; 小时 00000011
    00421609  50            push    eax
    0042160A  33C0          xor     eax, eax
    0042160C  66:8B4424 12  mov     ax, word ptr [esp+12]   ; 日期 00000007
    00421611  50            push    eax
    00421612  33C0          xor     eax, eax
    00421614  66:8B4424 12  mov     ax, word ptr [esp+12]   ; 月份 00000006
    00421619  50            push    eax
    0042161A  8B4424 14     mov     eax, dword ptr [esp+14] ; 年份 000007D8
    0042161E  25 FFFF0000   and     eax, 0FFFF
    00421623  50            push    eax
    00421624  E8 37100000   call    00422660
    {
        00422660  83EC 24       sub     esp, 24
        00422663  53            push    ebx
        00422664  56            push    esi
        00422665  8B7424 30     mov     esi, dword ptr [esp+30]         ; 年份, esi=000007D8
        00422669  57            push    edi
        0042266A  55            push    ebp
        0042266B  81EE 6C070000 sub     esi, 76C                        ; esi=esi-0000076C(1900)=0000006C(108)
                                                                        ; 记为 years
        00422671  83FE 46       cmp     esi, 46                         ; 当前时间 1970 以前, eax=-1, 跳出
        00422674  0F8C AE000000 jl      00422728
        0042267A  81FE 8A000000 cmp     esi, 8A                         ; 当前时间 2038 以后, 处理同上
        00422680  0F8F A2000000 jg      00422728
        00422686  8B5C24 3C     mov     ebx, dword ptr [esp+3C]         ; ebx=月份=00000006
        0042268A  8B2C9D D4A743 mov     ebp, dword ptr [ebx*4+43A7D4]   ; ebp=00000096
            ; 0043A7D4+1*4: FFFFFFFF -1
            ; 0043A7D4+2*4: 0000001E 30  +31
            ; 0043A7D4+3*4: 0000003A 58  +28
            ; 0043A7D4+4*4: 00000059 89  +31
            ; 0043A7D4+5*4: 00000077 119 +30
            ; 0043A7D4+6*4: 00000096 150 +31
            ; 0043A7D4+7*4: 000000B4 180 +30
            ; 0043A7D4+8*4: 000000D3 211 +31
            ; 0043A7D4+9*4: 0000016C 242 +31
            ; 0043A7D4+A*4: 00000110 272 +30
            ; 0043A7D4+B*4: 0000012F 303 +31
            ; 0043A7D4+C*4: 0000014D 333 +30
        00422691  036C24 40     add     ebp, dword ptr [esp+40]         ; 加上日期, ebp=0000009D, 一年中的第几天
        00422695  F7C6 03000000 test    esi, 3                          ; 年份是否为 4 的倍数
        0042269B  75 06         jnz     short 004226A3
        0042269D  83FB 02       cmp     ebx, 2                          ; 月份是否为 2
        004226A0  7E 01         jle     short 004226A3
        004226A2  45            inc     ebp                             ; 加上一天, ebp=0000009E, 记为 yday
        004226A3  E8 F8420000   call    004269A0
        {
            004269A0  833D 64A74300 cmp     dword ptr [43A764], 0       ; [43A764]=1
            004269A7  75 28         jnz     short 004269D1              ; 直接跳出……忽悠人的?
            004269A9  6A 0B         push    0B
            004269AB  E8 F0C4FFFF   call    00422EA0
            004269B0  83C4 04       add     esp, 4
            004269B3  833D 64A74300 cmp     dword ptr [43A764], 0
            004269BA  75 0B         jnz     short 004269C7
            004269BC  E8 3F000000   call    00426A00
            004269C1  FF05 64A74300 inc     dword ptr [43A764]
            004269C7  6A 0B         push    0B
            004269C9  E8 42C5FFFF   call    00422F10
            004269CE  83C4 04       add     esp, 4
            004269D1  C3            retn
        }
        004226A8  8D14F6        lea     edx, dword ptr [esi+esi*8]      ; edx=esi*9=0000033CC(972)=years*9
        004226AB  8D04D6        lea     eax, dword ptr [esi+edx*8]      ; eax==esi*49h=00001ECC(7884)=years*73d
        004226AE  8B4C24 44     mov     ecx, dword ptr [esp+44]         ; ecx=小时=11, 记为 hour
        004226B2  8D1480        lea     edx, dword ptr [eax+eax*4]      ; edx=eax*5=000099FC(39420)=years*365d
        004226B5  8D46 FF       lea     eax, dword ptr [esi-1]          ; eax=0000006B(107)=years-1
        004226B8  03D5          add     edx, ebp                        ; edx=00009A9A=years*366d-1
        004226BA  83E0 FC       and     eax, FFFFFFFC                   ; eax 低两位变 0, =(years-1)-(years-1)%4
        004226BD  8D1490        lea     edx, dword ptr [eax+edx*4]      ; edx=(years*366-1)*4+((years-1)-(years-1)%4)
        004226C0  8D3C52        lea     edi, dword ptr [edx+edx*2]      ; edi=(years*366-1)*12+((years-1)-(years-1)%4)*3
        004226C3  8D1479        lea     edx, dword ptr [ecx+edi*2]      ; edx=(years*366-1)*24+((years-1)-(years-1)%4)*6+hour
        004226C6  C1E2 02       shl     edx, 2                          ; edx=(years*366-1)*6+(years-1)/4*6+hour/4
        004226C9  8D3C52        lea     edi, dword ptr [edx+edx*2]      ; edi=(years*366-1)*18+(years-1)/4*18+hour/4*3
        004226CC  8B4424 4C     mov     eax, dword ptr [esp+4C]         ; eax=秒, 记为 second
        004226D0  8D14BF        lea     edx, dword ptr [edi+edi*4]      ; edx=(years*366-1)*90+(years-1)/4*90+hour/4*15
        004226D3  896C24 2C     mov     dword ptr [esp+2C], ebp         ; [esp+2C]=yday
        004226D7  035424 48     add     edx, dword ptr [esp+48]         ; edx+=分钟, mimute
                                                                        ; edx=(years*366-1)*90+(years-1)/4*90+hour/4*15+minute
        004226DB  897424 24     mov     dword ptr [esp+24], esi         ; [esp+24]=years
        004226DF  C1E2 02       shl     edx, 2                          ; edx=(years*366-1)*90/4+(years-1)/4*90/4+hour/4*15/4+minute/4
        004226E2  4B            dec     ebx                             ; yday=yday-1
        004226E3  8D3C52        lea     edi, dword ptr [edx+edx*2]      ; edi=(years*366-1)*90/4*3+(years-1)/4*90/4*3+hour/4*15/4*3+minute/4*3
        004226E6  895C24 20     mov     dword ptr [esp+20], ebx         ; [esp+20]=yday-1
        004226EA  894C24 18     mov     dword ptr [esp+18], ecx         ; [esp+18]=hour
        004226EE  8D14BF        lea     edx, dword ptr [edi+edi*4]      ; edx=(years*366-1)*90/4*15+(years-1)/4*90/4*15+hour/4*15/4*15+minute/4*15
        004226F1  0315 70A74300 add     edx, dword ptr [43A770]         ; [43A770]=FFFF8F80
                                                                        ; edx=(years*366-1)*90/4*15+(years-1)/4*90/4*15+hour/4*15/4*15+minute/4*15+0xFFFF8F80
        004226F7  833D 74A74300 cmp     dword ptr [43A774], 0           ; [43A774]=00000000
        004226FE  8DBC02 808155 lea     edi, dword ptr [edx+eax+7C558180]
        ; edi=(years*366-1)*90/4*15+(years-1)/4*90/4*15+hour/4*15/4*15+minute/4*15+0xFFFF8F80+second+0x7C558180
        00422705  74 17         je      short 0042271E
        00422707  8D4424 10     lea     eax, dword ptr [esp+10]
        0042270B  50            push    eax
        0042270C  E8 6F450000   call    00426C80
        00422711  83C4 04       add     esp, 4
        00422714  85C0          test    eax, eax
        00422716  74 06         je      short 0042271E
        00422718  81EF 100E0000 sub     edi, 0E10
        0042271E  8BC7          mov     eax, edi
        00422720  5D            pop     ebp
        00422721  5F            pop     edi
        00422722  5E            pop     esi
        00422723  5B            pop     ebx
        00422724  83C4 24       add     esp, 24
        00422727  C3            retn
        00422728  B8 FFFFFFFF   mov     eax, -1
        0042272D  5D            pop     ebp
        0042272E  5F            pop     edi
        0042272F  5E            pop     esi
        00422730  5B            pop     ebx
        00422731  83C4 24       add     esp, 24
        00422734  C3            retn
    }
    00421629  8B4C24 2C     mov     ecx, dword ptr [esp+2C]
    0042162D  83C4 18       add     esp, 18
    00421630  85C9          test    ecx, ecx
    00421632  74 02         je      short 00421636
    00421634  8901          mov     dword ptr [ecx], eax
    00421636  83C4 10       add     esp, 10
    00421639  C3            retn
}

补丁&注册机。(仅用于学习研究,请下载后24 小时内删除。)

 

展开阅读全文

没有更多推荐了,返回首页