说明:有朋友要找个视频会议系统,找了几个试用一下。看看这个好象还不错。但是
      只支持一个用户,厂家说可以免费注册,有可能是注册信息随便乱写的,没有
      收到注册码,于是就自己看看了。这里主要是给大家看看程序算法的实现。请
      支持国产软件。

系统:windows2003 
使用工具:OllyDbg 1.1

1,注册码生成。

进入服务器的管理程序,在许可管理里,两个文本框,一个是机器码,一个是注册码。
随便添入一个字符串后会提示成功,重新启动服务器。然后该不好使还是不好使。这
里跟踪一下,看如何处理的。

bp GetVolumeInformationA

然后打开许可界面,程序就断下了:

0040EE27   .  6A 50         push    50                                           ; /pFileSystemNameSize = 00000050
0040EE29   .  52            push    edx                                          ; |pFileSystemNameBuffer
0040EE2A   .  50            push    eax                                          ; |pFileSystemFlags
0040EE2B   .  8D5424 24     lea     edx, [esp+24]                                ; |
0040EE2F   .  51            push    ecx                                          ; |pMaxFilenameLength
0040EE30   .  52            push    edx                                          ; |pVolumeSerialNumber
0040EE31   .  8D8424 880300>lea     eax, [esp+388]                               ; |
0040EE38   .  68 04010000   push    104                                          ; |MaxVolumeNameSize = 104 (260.)
0040EE3D   .  8D8C24 740100>lea     ecx, [esp+174]                               ; |
0040EE44   .  50            push    eax                                          ; |VolumeNameBuffer
0040EE45   .  51            push    ecx                                          ; |RootPathName
0040EE46   .  FF15 80704100 call    [<&KERNEL32.GetVolumeInformationA>]          ; \GetVolumeInformationA ;取C盘卷标
0040EE4C   .  3BC3          cmp     eax, ebx
0040EE4E   .  74 2F         je      short 0040EE7F
0040EE50   .  395C24 18     cmp     [esp+18], ebx
0040EE54   .  75 15         jnz     short 0040EE6B
0040EE56   .  8D5424 18     lea     edx, [esp+18]
0040EE5A   .  8D8424 5C0100>lea     eax, [esp+15C]
0040EE61   .  52            push    edx
0040EE62   .  50            push    eax
0040EE63   .  E8 38FBFFFF   call    0040E9A0
0040EE68   .  83C4 08       add     esp, 8
0040EE6B   >  8B4C24 18     mov     ecx, [esp+18]
0040EE6F   .  8D9424 940000>lea     edx, [esp+94]
0040EE76   .  51            push    ecx
0040EE77   .  68 4CD54100   push    0041D54C                                     ;  %x
0040EE7C   .  52            push    edx
0040EE7D   .  EB 14         jmp     short 0040EE93
0040EE7F   >  FF15 F4704100 call    [<&KERNEL32.GetLastError>]                   ; [GetLastError
0040EE85   .  50            push    eax
0040EE86   .  8D8424 980000>lea     eax, [esp+98]
0040EE8D   .  68 4CD54100   push    0041D54C                                     ;  %x
0040EE92   .  50            push    eax
0040EE93   >  FFD6          call    esi                                          ;sprintf 把C盘卷标转换成16进字符串
0040EE95   .  83C4 0C       add     esp, 0C
0040EE98   .  8D4C24 24     lea     ecx, [esp+24]
0040EE9C   .  8D9424 5C0100>lea     edx, [esp+15C]
0040EEA3   .  C74424 24 C70>mov     dword ptr [esp+24], 0C7
0040EEAB   .  51            push    ecx                                          ; /pBufferSize
0040EEAC   .  52            push    edx                                          ; |Buffer
0040EEAD   .  FF15 84704100 call    [<&KERNEL32.GetComputerNameA>]               ; \GetComputerNameA  ;取得主机名称
0040EEB3   .  8DBC24 5C0100>lea     edi, [esp+15C]
0040EEBA   .  83C9 FF       or      ecx, FFFFFFFF
0040EEBD   .  33C0          xor     eax, eax
0040EEBF   .  8D9424 940000>lea     edx, [esp+94]
0040EEC6   .  F2:AE         repne   scas byte ptr es:[edi]                        ;以下几行代码功能是把C盘卷标
0040EEC8   .  F7D1          not     ecx
0040EECA   .  2BF9          sub     edi, ecx                                      ;连接在一起
0040EECC   .  8BF7          mov     esi, edi
0040EECE   .  8BFA          mov     edi, edx
0040EED0   .  8BD1          mov     edx, ecx
0040EED2   .  83C9 FF       or      ecx, FFFFFFFF
0040EED5   .  F2:AE         repne   scas byte ptr es:[edi]
0040EED7   .  8BCA          mov     ecx, edx
0040EED9   .  4F            dec     edi
0040EEDA   .  C1E9 02       shr     ecx, 2
0040EEDD   .  F3:A5         rep     movs dword ptr es:[edi], dword ptr [esi]   ;
0040EEDF   .  8BCA          mov     ecx, edx
0040EEE1   .  8D8424 940000>lea     eax, [esp+94]
0040EEE8   .  83E1 03       and     ecx, 3
0040EEEB   .  50            push    eax                                           ;这里是保存连接后字符串的地址
0040EEEC   .  F3:A4         rep     movs byte ptr es:[edi], byte ptr [esi]
0040EEEE   .  8BCD          mov     ecx, ebp
0040EEF0   .  E8 7B020000   call    0040F170                                      ;进行运算
0040EEF5   .  8DBC24 940000>lea     edi, [esp+94]
0040EEFC   .  83C9 FF       or      ecx, FFFFFFFF
0040EEFF   .  33C0          xor     eax, eax
0040EF01   .  8D55 68       lea     edx, [ebp+68]
0040EF04   .  F2:AE         repne   scas byte ptr es:[edi]
0040EF06   .  F7D1          not     ecx
0040EF08   .  2BF9          sub     edi, ecx
0040EF0A   .  8BC1          mov     eax, ecx
0040EF0C   .  8BF7          mov     esi, edi
0040EF0E   .  8BFA          mov     edi, edx
0040EF10   .  C1E9 02       shr     ecx, 2
0040EF13   .  F3:A5         rep     movs dword ptr es:[edi], dword ptr [esi]
0040EF15   .  8BC8          mov     ecx, eax
0040EF17   .  83E1 03       and     ecx, 3
0040EF1A   .  F3:A4         rep     movs byte ptr es:[edi], byte ptr [esi]
0040EF1C   .  8D8C24 940000>lea     ecx, [esp+94]
0040EF23   .  51            push    ecx
0040EF24   .  68 07040000   push    407
0040EF29   .  8BCD          mov     ecx, ebp
0040EF2B   .  E8 60540000   call    <jmp.&MFC42.#5953_CWnd::SetDlgItemTextA>     ;运算完后写到文本框里 
0040EF30   .  68 48D54100   push    0041D548                                     ;  3.0%x
0040EF35   .  68 09040000   push    409
0040EF3A   .  8BCD          mov     ecx, ebp
0040EF3C   .  E8 4F540000   call    <jmp.&MFC42.#5953_CWnd::SetDlgItemTextA>
0040EF41   .  8B15 54D64100 mov     edx, [41D654]
0040EF47   .  B9 19000000   mov     ecx, 19
0040EF4C   .  33C0          xor     eax, eax
0040EF4E   .  8D7C24 30     lea     edi, [esp+30]
0040EF52   .  F3:AB         rep     stos dword ptr es:[edi]
0040EF54   .  52            push    edx                                          ; /IniFileName => "C:\WINNT\lrmcu.ini"
0040EF55   .  8D4424 34     lea     eax, [esp+34]                                ; |
0040EF59   .  6A 64         push    64                                           ; |BufSize = 64 (100.)
0040EF5B   .  50            push    eax                                          ; |ReturnBuffer
0040EF5C   .  68 D8D54100   push    0041D5D8                                     ; |Default = ""
0040EF61   .  68 40D54100   push    0041D540                                     ; |code
0040EF66   .  68 E4D34100   push    0041D3E4                                     ; |regcode   ;这里是注册码保存的地方。
0040EF6B   .  FF15 14714100 call    [<&KERNEL32.GetPrivateProfileStringA>]       ; \GetPrivateProfileStringA 

接下来后面有WritetPrivateProfileStringA,可以看出,程序只是把注册码保存起来,并不做验证,验证是由服务程序启动时候检验的。

在看看0040F170处:
0040F170  /$  56            push    esi
0040F171  |.  8B7424 08     mov     esi, [esp+8]           ;取参数
0040F175  |.  57            push    edi
0040F176  |.  8BFE          mov     edi, esi
0040F178  |.  83C9 FF       or      ecx, FFFFFFFF
0040F17B  |.  33C0          xor     eax, eax
0040F17D  |.  33D2          xor     edx, edx
0040F17F  |.  F2:AE         repne   scas byte ptr es:[edi]  ;取参数长度
0040F181  |.  F7D1          not     ecx
0040F183  |.  49            dec     ecx
0040F184  |.  74 1F         je      short 0040F1A5
0040F186  |>  8A0C32        /mov     cl, [edx+esi]          ;取出一位
0040F189  |.  8AC2          |mov     al, dl                 ;初始时候是0
0040F18B  |.  24 01         |and     al, 1                  ;al只能为0和1
0040F18D  |.  8BFE          |mov     edi, esi               ;保存
0040F18F  |.  FEC0          |inc     al                     ;al加1,可以看出,当循环计数是偶数时这里是,为奇数时候,是2
0040F191  |.  02C8          |add     cl, al                 ;偶数加1,奇数加2
0040F193  |.  33C0          |xor     eax, eax               
0040F195  |.  880C32        |mov     [edx+esi], cl          ;保存回去 
0040F198  |.  83C9 FF       |or      ecx, FFFFFFFF
0040F19B  |.  42            |inc     edx                    ;计数加1  
0040F19C  |.  F2:AE         |repne   scas byte ptr es:[edi] ;取长度 
0040F19E  |.  F7D1          |not     ecx
0040F1A0  |.  49            |dec     ecx
0040F1A1  |.  3BD1          |cmp     edx, ecx               ;没完继续
0040F1A3  |.^ 72 E1         \jb      short 0040F186
0040F1A5  |>  5F            pop     edi
0040F1A6  |.  5E            pop     esi
0040F1A7  \.  C2 0400       retn    4

这里比较简单,只是把字符串按每一位是偶数加1,奇数加2。逆也简单,分别减1减2就可以了。

void DecodeMathineCode( char *szMachineCode )
{
  int i,nFlag,nLength;

  nLength = strlen( szMachineCode );

  for( i=0;i<nLength;i++ )
  {
    nFlag = i%2==0?1:2;
    szMachineCode[i] -= nFlag;
  }
  
  if( nLength < 11 )   //这里我把不足11位的补'0'了,不知道实际上是怎么处理的
  {
    for( i=nLength;i<11;i++ )
    {
      szMachineCode[i] = '0';
    }
  }

  szMachineCode[11] = 0;
}


2,服务端验证

有几个服务程序,找了一下,是在LRMCU.exe中进行验证的。可能是开发的程序员为了调试方便,留了个-debug的命令行运行的接口。
这给我们调试也带来了方便。OD 载入,参数里输入-debug。然后重新启动程序。这个程序没有反调试手段。

bp GetPrivateProfileStringA [esp+4]=="regcode"

F9走,中断第二次的时候,取消断点ALT+F9返回:

0040F36C   .  68 38494200   push    00424938                         ; /lrmcu.ini
0040F371   .  8D8424 500300>lea     eax, [esp+350]                   ; |
0040F378   .  68 C8000000   push    0C8                              ; |BufSize = C8 (200.)
0040F37D   .  50            push    eax                              ; |ReturnBuffer
0040F37E   .  68 B0754200   push    004275B0                         ; |Default = ""
0040F383   .  68 B4604200   push    004260B4                         ; |code
0040F388   .  68 A8604200   push    004260A8                         ; |regcode
0040F38D   .  FF15 FC854200 call    [<&KERNEL32.GetPrivateProfileStr>; \GetPrivateProfileStringA
0040F393   .  8D8C24 480100>lea     ecx, [esp+148]                   ; 这是返回值,就是我们在注册界面里随便写入的东西
0040F39A   .  8D9424 4C0300>lea     edx, [esp+34C]
0040F3A1   .  51            push    ecx                              ;  注册码地址
0040F3A2   .  52            push    edx
0040F3A3   .  E8 981DFFFF   call    00401140                         ;  这个CALL的功能是把注册码去掉'-'后格式变16进格式
0040F3A8   .  83C4 08       add     esp, 8
0040F3AB   .  8D8424 800000>lea     eax, [esp+80]
0040F3B2   .  6A 3B         push    3B
0040F3B4   .  6A 3F         push    3F
0040F3B6   .  6A 24         push    24
0040F3B8   .  6A 47         push    47
0040F3BA   .  6A 5E         push    5E
0040F3BC   .  6A 42         push    42
0040F3BE   .  6A 31         push    31
0040F3C0   .  6A 62         push    62
0040F3C2   .  68 94604200   push    00426094                         ;  %c%c%c%c%c%c%c%c
0040F3C7   .  50            push    eax
0040F3C8   .  FFD5          call    ebp                              ;  这里是解密用到的KEY,怕写字符串被发现,用sprintf
0040F3CA   .  8D8C24 A80000>lea     ecx, [esp+A8]                    ;  KEY地址
0040F3D1   .  8D9424 700100>lea     edx, [esp+170]                   ;  注册码16进格式
0040F3D8   .  51            push    ecx                              ;  KEY进栈
0040F3D9   .  6A 18         push    18                               ;  长度是24
0040F3DB   .  52            push    edx                              ;  注册码
0040F3DC   .  E8 9FDE0000   call    <jmp.&encryptlib.DecodeBin>      ;  解码函数,返回的值还在EDX中 
0040F3E1   .  83C4 34       add     esp, 34
0040F3E4   .  8D8424 4C0300>lea     eax, [esp+34C]                   ;
0040F3EB   .  6A 5C         push    5C
0040F3ED   .  6A 3A         push    3A
0040F3EF   .  6A 43         push    43
0040F3F1   .  68 905F4200   push    00425F90                         ;  %c%c%c
0040F3F6   .  50            push    eax
0040F3F7   .  FFD5          call    ebp                              ;又是sprintf,凑成"c:\"
0040F3F9   .  83C4 14       add     esp, 14
0040F3FC   .  8D8C24 A40900>lea     ecx, [esp+9A4]
0040F403   .  8D5424 7C     lea     edx, [esp+7C]
0040F407   .  8D4424 70     lea     eax, [esp+70]
0040F40B   .  6A 50         push    50                               ; /pFileSystemNameSize = 00000050
0040F40D   .  51            push    ecx                              ; |pFileSystemNameBuffer
0040F40E   .  52            push    edx                              ; |pFileSystemFlags
0040F40F   .  8D4C24 1C     lea     ecx, [esp+1C]                    ; |
0040F413   .  50            push    eax                              ; |pMaxFilenameLength
0040F414   .  51            push    ecx                              ; |pVolumeSerialNumber
0040F415   .  8D9424 080A00>lea     edx, [esp+A08]                   ; |
0040F41C   .  68 04010000   push    104                              ; |MaxVolumeNameSize = 104 (260.)
0040F421   .  8D8424 640300>lea     eax, [esp+364]                   ; |
0040F428   .  52            push    edx                              ; |VolumeNameBuffer
0040F429   .  50            push    eax                              ; |RootPathName
0040F42A   .  FF15 88854200 call    [<&KERNEL32.GetVolumeInformation>; \GetVolumeInformationA ;取c盘卷标
0040F430   .  85C0          test    eax, eax
0040F432   .  74 31         je      short 0040F465
0040F434   .  8B4424 10     mov     eax, [esp+10]                    ;  C盘卷标
0040F438   .  85C0          test    eax, eax
0040F43A   .  75 15         jnz     short 0040F451
0040F43C   .  8D4C24 10     lea     ecx, [esp+10]
0040F440   .  8D9424 4C0300>lea     edx, [esp+34C]
0040F447   .  51            push    ecx
0040F448   .  52            push    edx
0040F449   .  E8 611CFFFF   call    004010AF
0040F44E   .  83C4 08       add     esp, 8
0040F451   >  8B4424 10     mov     eax, [esp+10]                    ;  C盘卷标
0040F455   .  8D8C24 800000>lea     ecx, [esp+80]                    ;  返回地址,存放卷标16进字符串
0040F45C   .  50            push    eax
0040F45D   .  68 88604200   push    00426088                         ;  %x
0040F462   .  51            push    ecx
0040F463   .  EB 14         jmp     short 0040F479
0040F465   >  FF15 84854200 call    [<&KERNEL32.GetLastError>]       ; [GetLastError
0040F46B   .  50            push    eax
0040F46C   .  8D9424 840000>lea     edx, [esp+84]
0040F473   .  68 88604200   push    00426088                         ;  %x
0040F478   .  52            push    edx
0040F479   >  FFD5          call    ebp                              ;这里又一个sprintf,把c盘卷标转成16进制字符串
0040F47B   .  83C4 0C       add     esp, 0C
0040F47E   .  8D4424 28     lea     eax, [esp+28]
0040F482   .  8D8C24 4C0300>lea     ecx, [esp+34C]
0040F489   .  C74424 28 C70>mov     dword ptr [esp+28], 0C7
0040F491   .  50            push    eax
0040F492   .  51            push    ecx
0040F493   .  FFD6          call    esi                              ;  取计算机名
0040F495   .  8DBC24 4C0300>lea     edi, [esp+34C]                   ;  计算机名
0040F49C   .  83C9 FF       or      ecx, FFFFFFFF
0040F49F   .  33C0          xor     eax, eax
0040F4A1   .  8D9424 800000>lea     edx, [esp+80]                    ;  c盘卷标字符串
0040F4A8   .  F2:AE         repne   scas byte ptr es:[edi]
0040F4AA   .  F7D1          not     ecx                              ;  计算机名长度
0040F4AC   .  2BF9          sub     edi, ecx
0040F4AE   .  8BF7          mov     esi, edi                         ;  计算机名
0040F4B0   .  8BE9          mov     ebp, ecx                         ;  计算机名长度
0040F4B2   .  8BFA          mov     edi, edx                         ;  卷标
0040F4B4   .  83C9 FF       or      ecx, FFFFFFFF
0040F4B7   .  F2:AE         repne   scas byte ptr es:[edi]
0040F4B9   .  8BCD          mov     ecx, ebp
0040F4BB   .  4F            dec     edi
0040F4BC   .  C1E9 02       shr     ecx, 2
0040F4BF   .  F3:A5         rep     movs dword ptr es:[edi], dword p>
0040F4C1   .  8BCD          mov     ecx, ebp
0040F4C3   .  83E1 03       and     ecx, 3
0040F4C6   .  F3:A4         rep     movs byte ptr es:[edi], byte ptr>;  以上是把C盘卷标和计算机名连起来。保留前11位。
0040F4C8   .  888424 8B0000>mov     [esp+8B], al
0040F4CF   .  8D8424 800000>lea     eax, [esp+80]                    ;  取出计算出的11位字符
0040F4D6   .  8D8C24 480100>lea     ecx, [esp+148]                   ;  这是上面那个regcode运算后的结果
0040F4DD   .  50            push    eax
0040F4DE   .  51            push    ecx
0040F4DF   .  FFD3          call    ebx
0040F4E1   .  83C4 08       add     esp, 8                           ;  看注册码计算结果中是否有C盘卷标和机器名
0040F4E4      85C0            test    eax, eax                       ;  如果没有就是未注册的,跳走 
0040F4E6      0F84 DD000000   je      0040F5C9
0040F4EC      8B35 44874200   mov     esi, [<&MSVCRT.strncpy>]         ;  msvcrt.strncpy
0040F4F2      B9 32000000     mov     ecx, 32
0040F4F7      33C0            xor     eax, eax
0040F4F9   ?  8DBC24 80000000 lea     edi, [esp+80]                    ; 卷标和机器名连接
0040F500   ?  F3:AB           rep     stos dword ptr es:[edi]          ; 如果正确,先把前面计算的卷标和计算机名清空
0040F502   .  8D9424 53010000 lea     edx, [esp+153]
0040F509   ?  6A 03           push    3                                ;取3个字符
0040F50B   ?  8D8424 84000000 lea     eax, [esp+84]                    ; 
0040F512   .  52            push    edx                                ;注册码计算后,第12位的指针,可以看出前11位应该                                                                               ;是C盘卷标字符和计算机名连接起来的前11位
0040F513   .  50            push    eax
0040F514   .  FFD6          call    esi                              ; strncpy 从12位起取3位
0040F516   .  8B2D 48874200 mov     ebp, [<&MSVCRT.atoi>]            ;  msvcrt.atoi
0040F51C   .  8D8C24 8C0000>lea     ecx, [esp+8C]
0040F523   .  51            push    ecx                              ; /s
0040F524   .  FFD5          call    ebp                              ; \atoi
0040F526   .  A3 E47A4200   mov     [427AE4], eax                    ;  取出三位,变为整数,保存在[427AE4]处
0040F52B   .  B9 32000000   mov     ecx, 32
0040F530   .  33C0          xor     eax, eax
0040F532   .  8DBC24 900000>lea     edi, [esp+90]
0040F539   .  F3:AB         rep     stos dword ptr es:[edi]
0040F53B   .  8D9424 660100>lea     edx, [esp+166]
0040F542   .  6A 03         push    3
0040F544   .  8D8424 940000>lea     eax, [esp+94]
0040F54B   .  52            push    edx
0040F54C   .  50            push    eax                              ;  再取三位
0040F54D   .  FFD6          call    esi
0040F54F   .  8D8C24 9C0000>lea     ecx, [esp+9C]
0040F556   .  51            push    ecx
0040F557   .  FFD5          call    ebp
0040F559   .  A3 484C4200   mov     [424C48], eax                    ;  再三位变整数,保存在[424C48]
0040F55E   .  B9 32000000   mov     ecx, 32
0040F563   .  33C0          xor     eax, eax
0040F565   .  8DBC24 A00000>lea     edi, [esp+A0]
0040F56C   .  F3:AB         rep     stos dword ptr es:[edi]
0040F56E   .  8D9424 790100>lea     edx, [esp+179]
0040F575   .  6A 03         push    3
0040F577   .  8D8424 A40000>lea     eax, [esp+A4]
0040F57E   .  52            push    edx
0040F57F   .  50            push    eax                              ;  再来三位
0040F580   .  FFD6          call    esi
0040F582   .  8D8C24 AC0000>lea     ecx, [esp+AC]
0040F589   .  51            push    ecx
0040F58A   .  FFD5          call    ebp
0040F58C   .  A3 EC7A4200   mov     [427AEC], eax                    ;  再三位变整数结果保存在[427AEC]
0040F591   .  B9 32000000   mov     ecx, 32
0040F596   .  33C0          xor     eax, eax
0040F598   .  8DBC24 B00000>lea     edi, [esp+B0]
0040F59F   .  F3:AB         rep     stos dword ptr es:[edi]
0040F5A1   .  8D9424 8C0100>lea     edx, [esp+18C]
0040F5A8   .  6A 03         push    3
0040F5AA   .  8D8424 B40000>lea     eax, [esp+B4]
0040F5B1   .  52            push    edx
0040F5B2   .  50            push    eax                              ;  再来三位
0040F5B3   .  FFD6          call    esi
0040F5B5   .  8D8C24 BC0000>lea     ecx, [esp+BC]
0040F5BC   .  51            push    ecx
0040F5BD   .  FFD5          call    ebp
0040F5BF   .  83C4 40       add     esp, 40
0040F5C2   .  A3 E87A4200   mov     [427AE8], eax                    ;  变整后保存在[427AE8]
0040F5C7   .  EB 20         jmp     short 0040F5E9
0040F5C9   .  33C0          xor     eax, eax                         ;  这里是上面出错后跳转的地方
0040F5CB   .  C705 E47A4200>mov     dword ptr [427AE4], 1            ;  如果出错,这里设置默认值。
0040F5D5   .  A3 E87A4200   mov     [427AE8], eax                    ;  结合使用结果,可以看出[427AE4]处保存的就是
0040F5DA   .  C705 484C4200>mov     dword ptr [424C48], 2DA          ;  会议室最大登录的用户数。其他几个值未知
0040F5E4   .  A3 EC7A4200   mov     [427AEC], eax                    ;
0040F5E9   >  B9 10000000   mov     ecx, 10
0040F5EE   .  33C0          xor     eax, eax
0040F5F0   .  8D7C24 30     lea     edi, [esp+30]

到这简单整理一下,可以得出注册码在经过call <jmp.&encryptlib.DecodeBin>计算后大概应该是这样子的:

aaaaaaaaaaabbbcccdddeee

a是11位字符串,C盘卷标16进字符串和计算记名连在一起,保留11位
b是表示会议室最大登录用户数
c,d,e数字意义未知

是不是觉得这里可以爆破了?不这才刚开始。

现在来看看encryptlib.DecodeBin是什么东西,在这里下个断点后,重新载入:

10001260 >/$  83EC 08                 sub     esp, 8
10001263  |.  8B4424 0C               mov     eax, [esp+C]                               ;  注册码
10001267  |.  53                      push    ebx
10001268  |.  55                      push    ebp
10001269  |.  8B6C24 18               mov     ebp, [esp+18]                              ;  长度
1000126D  |.  56                      push    esi
1000126E  |.  57                      push    edi
1000126F  |.  894424 1C               mov     [esp+1C], eax                              ;  注册码地址
10001273  |>  BB 08000000             /mov     ebx, 8                                    ;  8个一计算
10001278  |.  3BEB                    |cmp     ebp, ebx                                  ;  
1000127A  |.  7D 02                   |jge     short 1000127E                            ; 
1000127C  |.  8BDD                    |mov     ebx, ebp                                  ;  
1000127E  |>  33C9                    |xor     ecx, ecx
10001280  |.  8B7424 1C               |mov     esi, [esp+1C]                             ;  注册码地址
10001284  |.  894C24 10               |mov     [esp+10], ecx                             ;  
10001288  |.  8D7C24 10               |lea     edi, [esp+10]                             ;  
1000128C  |.  894C24 14               |mov     [esp+14], ecx                             ;  
10001290  |.  8BCB                    |mov     ecx, ebx
10001292  |.  8BD1                    |mov     edx, ecx                                  ;  
10001294  |.  8B4424 24               |mov     eax, [esp+24]                             ;  解密KEY
10001298  |.  C1E9 02                 |shr     ecx, 2                                    ;  
1000129B  |.  F3:A5                   |rep     movs dword ptr es:[edi], dword ptr [esi]  ;  
1000129D  |.  8BCA                    |mov     ecx, edx                                  ;  
1000129F  |.  50                      |push    eax                                       ;  解密KEY
100012A0  |.  83E1 03                 |and     ecx, 3                                    ;  
100012A3  |.  F3:A4                   |rep     movs byte ptr es:[edi], byte ptr [esi]    ;  
100012A5  |.  8D4C24 14               |lea     ecx, [esp+14]
100012A9  |.  51                      |push    ecx                                       ;  注册码
100012AA      E8 51FFFFFF             call    10001200                                   ;  KEY和注册码进去,计算
100012AF  |.  8B4424 24               |mov     eax, [esp+24]                             ;  注册码地址
100012B3  |.  8BCB                    |mov     ecx, ebx                                  ;  
100012B5  |.  8BD1                    |mov     edx, ecx
100012B7  |.  8D7424 18               |lea     esi, [esp+18]                             ;  刚计算完的中间结果
100012BB  |.  8BF8                    |mov     edi, eax                                  ;  注册码
100012BD  |.  2BEB                    |sub     ebp, ebx
100012BF  |.  C1E9 02                 |shr     ecx, 2
100012C2  |.  F3:A5                   |rep     movs dword ptr es:[edi], dword ptr [esi]
100012C4  |.  8BCA                    |mov     ecx, edx
100012C6  |.  83C4 08                 |add     esp, 8
100012C9  |.  83E1 03                 |and     ecx, 3
100012CC  |.  03C3                    |add     eax, ebx
100012CE  |.  85ED                    |test    ebp, ebp
100012D0  |.  F3:A4                   |rep     movs byte ptr es:[edi], byte ptr [esi]
100012D2  |.  894424 1C               |mov     [esp+1C], eax
100012D6  |.^ 7F 9B                   \jg      short 10001273
100012D8  |.  5F                      pop     edi
100012D9  |.  5E                      pop     esi
100012DA  |.  5D                      pop     ebp
100012DB  |.  33C0                    xor     eax, eax
100012DD  |.  5B                      pop     ebx
100012DE  |.  83C4 08                 add     esp, 8
100012E1  \.  C3                      retn

这里就是把进来的24字符分成3个8 BYTE,然后同解密KEY一起调用10001200。所以可以大概判定原始注册码应该是去掉'-'后有48个字符。

继续进到 10001200

10001200  /$  53                      push    ebx
10001201  |.  56                      push    esi
10001202  |.  8B7424 0C               mov     esi, [esp+C]                               ;  值
10001206  |.  57                      push    edi
10001207  |.  8B7C24 14               mov     edi, [esp+14]                              ;  KEY
1000120B  |.  6A 02                   push    2
1000120D  |.  57                      push    edi                                        ;  KEY
1000120E  |.  56                      push    esi                                        ;  值地址,函数返回也在这里
1000120F  |.  E8 3CFEFFFF             call    10001050                                   ;  计算,取8个值同KEY异或
10001214  |.  6A 02                   push    2                                          ;  进去个2
10001216  |.  68 20330010             push    10003320                                   ;  这是一个索引表的地址
1000121B  |.  56                      push    esi                                        ;  再算
1000121C  |.  E8 7FFEFFFF             call    100010A0                                   ;  查索引表,返回值还在ESI中
10001221  |.  83C4 18                 add     esp, 18
10001224  |.  BB 05000000             mov     ebx, 5                                     ;  循环5次
10001229  |>  6A 02                   /push    2                                         ;  2进去
1000122B  |.  57                      |push    edi                                       ;  KEY
1000122C  |.  56                      |push    esi                                       ;  计算中间结果
1000122D  |.  E8 1EFEFFFF             |call    10001050                                  ;  异或啊
10001232  |.  6A 02                   |push    2                                         ;  2
10001234  |.  56                      |push    esi                                       ;  值进去,再计算
10001235  |.  E8 A6FEFFFF             |call    100010E0                                  ;  来回查表,完事,值还在ESI中
1000123A  |.  6A 02                   |push    2
1000123C  |.  68 20330010             |push    10003320
10001241  |.  56                      |push    esi
10001242  |.  E8 59FEFFFF             |call    100010A0                                  ;  算出的东西再查表
10001247  |.  83C4 20                 |add     esp, 20
1000124A  |.  4B                      |dec     ebx
1000124B  |.^ 75 DC                   \jnz     short 10001229
1000124D  |.  6A 02                   push    2
1000124F  |.  57                      push    edi
10001250  |.  56                      push    esi
10001251  |.  E8 FAFDFFFF             call    10001050
10001256  |.  83C4 0C                 add     esp, 0C
10001259  |.  33C0                    xor     eax, eax
1000125B  |.  5F                      pop     edi
1000125C  |.  5E                      pop     esi
1000125D  |.  5B                      pop     ebx
1000125E  \.  C3                      retn

到这里,熟悉算法的人应该能大概看出是什么东西了。不过我跟的时候不熟。一直把里面的都跟完了。并把这个过程用C还原了。
我知道这个过程肯定是可逆的,但是我逆不出来。觉得应该不是作者自己开发的。所以到网上找对称算法。看到AES算法的介绍
后,里面有b,d,9,e几个参数跟100010E0里的几个对应上了才知道。

100010E0处:

100010E0  /$  83EC 0C                 sub     esp, 0C
100010E3  |.  8B5424 14               mov     edx, [esp+14]                              ;  参数1
100010E7  |.  53                      push    ebx
100010E8  |.  55                      push    ebp
100010E9  |.  8B6C24 18               mov     ebp, [esp+18]                              ;  值地址
100010ED  |.  56                      push    esi
100010EE  |.  57                      push    edi
100010EF  |.  33FF                    xor     edi, edi
100010F1  |.  81E2 FF000000           and     edx, 0FF
100010F7  |.  895424 10               mov     [esp+10], edx                              ;  2
100010FB  |.  0F8E B9000000           jle     100011BA
10001101  |>  8D443C 14               /lea     eax, [esp+edi+14]                         ;  地址定位
10001105  |.  8D4C24 14               |lea     ecx, [esp+14]
10001109  |.  894424 24               |mov     [esp+24], eax                             ;  地址定位
1000110D  |.  8BC5                    |mov     eax, ebp                                  ;  值
1000110F  |.  2BC1                    |sub     eax, ecx                                  ;  定位用
10001111  |.  BE 03000000             |mov     esi, 3                                    ;  
10001116  |.  894424 20               |mov     [esp+20], eax                             ;  存起来
1000111A  |>  8D56 FE                 |/lea     edx, [esi-2]
1000111D  |.  81E2 03000080           ||and     edx, 80000003                            ;  测试是否是负数?
10001123  |.  79 05                   ||jns     short 1000112A                           ;  没有走
10001125  |.  4A                      ||dec     edx
10001126  |.  83CA FC                 ||or      edx, FFFFFFFC
10001129  |.  42                      ||inc     edx
1000112A  |>  8D0457                  ||lea     eax, [edi+edx*2]                         ;  
1000112D  |.  8A0C28                  ||mov     cl, [eax+ebp]                            ;  取得一个索引的值
10001130  |.  51                      ||push    ecx                                      ;  
10001131  |.  6A 0B                   ||push    0B                                       ;  B
10001133  |.  E8 C8FEFFFF             ||call    10001000                                 ;  a表加b表/ff 余数再查表 回AL
10001138  |.  8D56 FF                 ||lea     edx, [esi-1]
1000113B  |.  8AD8                    ||mov     bl, al                                   ;  返回值,存起来
1000113D  |.  81E2 03000080           ||and     edx, 80000003                            ;  去掉进位,只要后3位
10001143  |.  79 05                   ||jns     short 1000114A
10001145  |.  4A                      ||dec     edx
10001146  |.  83CA FC                 ||or      edx, FFFFFFFC
10001149  |.  42                      ||inc     edx
1000114A  |>  8D0457                  ||lea     eax, [edi+edx*2]                         ;  
1000114D  |.  8A0C28                  ||mov     cl, [eax+ebp]                            ;  再取一位
10001150  |.  51                      ||push    ecx                                      ;  值为参数1
10001151  |.  6A 0D                   ||push    0D                                       ;  参数2
10001153  |.  E8 A8FEFFFF             ||call    10001000                                 ;  a表加b表/ff 余数再查表 回AL
10001158  |.  8BD6                    ||mov     edx, esi
1000115A  |.  32D8                    ||xor     bl, al                                   ;  俩次结果xor,还在BL中
1000115C  |.  81E2 03000080           ||and     edx, 80000003
10001162  |.  79 05                   ||jns     short 10001169
10001164  |.  4A                      ||dec     edx
10001165  |.  83CA FC                 ||or      edx, FFFFFFFC
10001168  |.  42                      ||inc     edx
10001169  |>  8D0457                  ||lea     eax, [edi+edx*2]
1000116C  |.  8A0C28                  ||mov     cl, [eax+ebp]                            ;  3位了
1000116F  |.  51                      ||push    ecx
10001170  |.  6A 09                   ||push    9
10001172  |.  E8 89FEFFFF             ||call    10001000
10001177  |.  8B5424 38               ||mov     edx, [esp+38]                            ;  定位值
1000117B  |.  32D8                    ||xor     bl, al                                   ;  结果又异或
1000117D  |.  8B4424 3C               ||mov     eax, [esp+3C]                            ;  取值地址。。。
10001181  |.  8A0C02                  ||mov     cl, [edx+eax]                            ;  0 位
10001184  |.  51                      ||push    ecx
10001185  |.  6A 0E                   ||push    0E
10001187  |.  E8 74FEFFFF             ||call    10001000                                 ;  再来
1000118C  |.  83C4 20                 ||add     esp, 20
1000118F  |.  32D8                    ||xor     bl, al                                   ;  XOR玩,4位完了
10001191  |.  8B4424 24               ||mov     eax, [esp+24]
10001195  |.  46                      ||inc     esi
10001196  |.  8818                    ||mov     [eax], bl                                ;  值存起来
10001198  |.  8D56 FD                 ||lea     edx, [esi-3]
1000119B  |.  83C0 02                 ||add     eax, 2
1000119E  |.  83FA 04                 ||cmp     edx, 4
100011A1  |.  894424 24               ||mov     [esp+24], eax                            ;  保存值的地址?
100011A5  |.^ 0F8C 6FFFFFFF           |\jl      1000111A
100011AB  |.  8B4424 10               |mov     eax, [esp+10]
100011AF  |.  47                      |inc     edi
100011B0  |.  3BF8                    |cmp     edi, eax
100011B2  |.^ 0F8C 49FFFFFF           \jl      10001101
100011B8  |.  8BD0                    mov     edx, eax
100011BA  |>  8D4C24 14               lea     ecx, [esp+14]                              ; 上面计算的结果
100011BE  |.  8D4424 14               lea     eax, [esp+14]                              ; 上面计算的结果
100011C2  |.  2BE9                    sub     ebp, ecx
100011C4  |.  C74424 24 04000000      mov     dword ptr [esp+24], 4                      ;  循环计数
100011CC  |>  85D2                    /test    edx, edx
100011CE  |.  7E 15                   |jle     short 100011E5
100011D0  |.  8BCA                    |mov     ecx, edx
100011D2  |.  8BF0                    |mov     esi, eax                                  ; 上面计算的中间结果
100011D4  |.  8BD9                    |mov     ebx, ecx
100011D6  |.  8D3C28                  |lea     edi, [eax+ebp]
100011D9  |.  C1E9 02                 |shr     ecx, 2
100011DC  |.  F3:A5                   |rep     movs dword ptr es:[edi], dword ptr [esi]  ; 结果保存
100011DE  |.  8BCB                    |mov     ecx, ebx
100011E0  |.  83E1 03                 |and     ecx, 3
100011E3  |.  F3:A4                   |rep     movs byte ptr es:[edi], byte ptr [esi]
100011E5  |>  8B4C24 24               |mov     ecx, [esp+24]
100011E9  |.  83C0 02                 |add     eax, 2
100011EC  |.  49                      |dec     ecx
100011ED  |.  894C24 24               |mov     [esp+24], ecx
100011F1  |.^ 75 D9                   \jnz     short 100011CC
100011F3  |.  5F                      pop     edi
100011F4  |.  5E                      pop     esi
100011F5  |.  5D                      pop     ebp
100011F6  |.  5B                      pop     ebx
100011F7  |.  83C4 0C                 add     esp, 0C
100011FA  \.  C3                      retn

这里看到b,d,9,e了。所以可以知道是AES算法的解密过程。10001000处大概可以用如下代码表示:

unsigned char GetMulCode( unsigned char k,unsigned char c )
{
  return k*c==0?0:alog[ (log[k]+log[c])%0xFF ];
}

其中alog和log知道aes算法的应该都知道是什么东西,反正我跟的时候是不知道。真晕。


到这里基本上差不多了。程序好象把行列变换都放在100010E0里了。不过到现在我还对这个算法不是太明白。这个程序中间
循环的次数是5次。是变形的AES?这都有什么规律可变,请达人指教一下。


现在整一下整个注册的过程。

1,服务管理器里,会根据C盘卷标和计算机名进行运算。得到一个字符串。然后发给厂家。
2,厂家会把字符串逆出后,取前11位,然后后面再加4个3字符的数字字符串。格式:aaaaaaaaaaabbbcccdddeee
3,用这个算法的加密过程进行加密,然后同当前机器的信息相比较,若正确,则把后面几个值解析出来放到相应
   的内存位置。若不正确。置默认值。   


程序运行时候,还有几处调用DecodeBin,若出错,还是在相应内存处置默认值。
Dll里只有解密算法,没有加密算法,但是现在我们知道了所使用的算法和KEY。就可以得出加密过程了。
后面附有完整的代码实现(程序中有一处是错的,明白算法的自然会知道,不明白的,拿来也不能直接用)。这并不是完整的AES算
法过程,只是这个程序里的实现。

虽然可以生成注册码了。但是那个最大用户数字若超过4,程序还是会报超过最大用户数。这是体验版的限制。在初始化
每个房间的时候,用一个双向链表保存登录用户的信息,这个链表只有4项。具体如果做这里就不说了。请支持国产软件。
因为注册码是免费发放的,但是我想也是在4个范围之内。就算你有注册机,你不给钱,也不得不到正式版的程序。


#include "stdio.h"
#include "string.h"

#define ENCODE 0
#define DECODE 1

unsigned char szIndexTable[]="...";  //这个表在程序中保存,1024个字节,里面包含了log,alog,sbox和sbox的逆,就不贴了。

unsigned char *log    =  szIndexTable;
unsigned char *alog    =  szIndexTable+0x100;
unsigned char *sbox    =  szIndexTable+0x200;
unsigned char *invsbox=  szIndexTable+0x300;
unsigned char *Key    =  "\x62\x31\x42\x5E\x47\x24\x3F\x3B";

int nRowsTable[8][4]={
  { 2,4,6,0 },
  { 3,5,7,1 },
  { 4,6,0,2 },
  { 5,7,1,3 },
  { 6,0,2,4 },
  { 7,1,3,5 },
  { 0,2,4,6 },
  { 1,3,5,7 }};

void AddRoundKey( unsigned char *Value,unsigned char *Key )
{
  int i;

  for ( i=0;i<8;i++ )
  {
    Value[i] ^= Key[i];
  }
}

void SubBytes( unsigned char *Value,int nFlag )
{
  int i;
  char *table = nFlag==ENCODE?sbox:invsbox;

  for( i=0;i<8;i++ )
  {
    Value[i] = table[ Value[i] ];
  }
}

unsigned char GetMulCode( unsigned char k,unsigned char c )
{
  return k*c==0?0:alog[ (log[k]+log[c])%0xFF ];
}

void MixColumns( unsigned char *Value,int nFlag )
{
  int i;
  unsigned char result[8];
  unsigned char a,b,c,d;

  a = nFlag==ENCODE?2:0xb;
  b = nFlag==ENCODE?1:0xd;
  c = nFlag==ENCODE?1:0x9;
  d = nFlag==ENCODE?3:0xe;

  for( i=0;i<8;i++ )
  {
    result[i] = GetMulCode( a,Value[ nRowsTable[i][0] ] )^
                GetMulCode( b,Value[ nRowsTable[i][1] ] )^
                GetMulCode( c,Value[ nRowsTable[i][2] ] )^
                GetMulCode( d,Value[ nRowsTable[i][3] ] );
  }

  memcpy( Value,result,8 );
}

void AesDecode( unsigned char *Value,unsigned char *Key )
{
  int i;

  AddRoundKey( Value,Key );
  SubBytes( Value,DECODE );

  for( i=0;i<5;i++ )
  {
    AddRoundKey( Value,Key );
    MixColumns( Value,DECODE );
    SubBytes( Value,DECODE );
  }

  AddRoundKey( Value,Key );
}

void AesEncode( unsigned char *Value,unsigned char *Key )
{
  int i;
  
  AddRoundKey( Value,Key );
  
  for( i=0;i<5;i++ )
  {
    SubBytes( Value,ENCODE );
    MixColumns( Value,ENCODE );
    AddRoundKey( Value,Key );
  }
  
  SubBytes( Value,ENCODE );
  AddRoundKey( Value,Key );
}

int MakeHex( unsigned char *Value )
{
  int i,nIndex=0;
  unsigned char tmpdat[100]={0},c1,c2;

  for( i=0;i<(int)strlen(Value);i++ )
  {
    if ( Value[i] != '-' )
    {
      tmpdat[nIndex++] = Value[i];
    }
  }
  
  if ( strlen( tmpdat ) != 48 )
  {
    return -1;
  }

  for( i=0;i< (int)strlen(tmpdat);i+=2 )
  {
    c1 = tmpdat[i];
    c2 = tmpdat[i+1];
    
    if ( c1 >= '0' && c1 <= '9' )
    {
      c1 -= '0';
    }
    else if( c1 >= 'a' && c1 <= 'f' )
    {
      c1 -= 'a';
      c1 += 10;
    }
    else
    {
      return -1;
    }

    if ( c2 >= '0' && c2 <= '9' )
    {
      c2 -= '0';
    }
    else if( c2 >= 'a' && c2 <= 'f' )
    {
      c2 -= 'a';
      c2 += 10;
    }
    else
    {
      return -1;
    }
    
    tmpdat[i/2] = c1*16+c2;
  }

  memcpy( Value,tmpdat,24 );

  return 0;
}

int MakeHexStr( unsigned char *Value,unsigned char *Output )
{
  int i,nIndex=0;
  unsigned char tmpdat[100]={0},c1,c2;

  for( i=0;i<24;i++ )
  {
    c1 = Value[i]>>4;
    c2 = Value[i]&0x0F; 

    if ( c1 >= 0 && c1 <= 9 )
    {
      tmpdat[i*2] = c1+'0';
    }
    else if( c1 >= 0xa && c1 <= 0xf )
    {
      tmpdat[i*2] = c1-10+'a';
    }
    else
    {
      return -1;
    }

    if ( c2 >= 0 && c2 <= 9 )
    {
      tmpdat[i*2+1] = c2 + '0';
    }
    else if( c2 >= 0xa && c2 <= 0xf )
    {
      tmpdat[i*2+1] = c2-10+'a';
    }
    else
    {
      return -1;
    }
  }

  for( i=0;i<4;i++)
  {
    strncpy( Output+i*13,tmpdat+i*12,12 );
    if ( i != 3 )
    {
      strcpy( Output+i*13+12,"-" );
    }
  }
  
  *( Output+51 ) = 0;
  return 0;
}

void MakeSuperVKey( unsigned char *Value,unsigned char*Key,unsigned char *OutPut,int nFlag )
{
  int i;
  unsigned char result[8];
  unsigned char tmpdat[100];

  strcpy(tmpdat,Value);
  
  if ( nFlag == DECODE )
  {
    MakeHex( tmpdat );
  }

  for( i=0;i<3;i++ )
  {
    memcpy( result,tmpdat+i*8,8 );
    if ( nFlag == ENCODE )
    {
      AesEncode( result,Key );
    }
    else
    {
      AesDecode( result,Key );
    }
    memcpy( tmpdat+i*8,result,8 );
  }

  if ( nFlag == ENCODE )
  {
    MakeHexStr( tmpdat,OutPut );
  }
  else
  {
    strcpy( OutPut,tmpdat );
  }
}

void DecodeMathineCode( char *szMachineCode )
{
  int i,nFlag,nLength;

  nLength = strlen( szMachineCode );

  for( i=0;i<nLength;i++ )
  {
    nFlag = i%2==0?1:2;
    szMachineCode[i] -= nFlag;
  }
  
  if( nLength < 11 )
  {
    for( i=nLength;i<11;i++ )
    {
      szMachineCode[i] = '0';
    }
  }

  szMachineCode[11] = 0;
}

int main()
{
  char szCode[100]="...";
  int val1,val2,val3,val4;

  printf( "Input Machine Code : " );
  scanf( "%s",szCode );

  DecodeMathineCode( szCode );

  printf( "Input Value 1  : " );
  scanf( "%d",&val1 );
  
  printf( "Input Value 2  : " );
  scanf( "%d",&val2 );
  
  printf( "Input Value 3  : " );
  scanf( "%d",&val3 );
  
  printf( "Input Value 4  : " );
  scanf( "%d",&val4 );
  
  sprintf( szCode+strlen(szCode),"%03d%03d%03d%03d",val1,val2,val3,val4 );
  
  MakeSuperVKey( szCode,Key,szCode,ENCODE );
  
  printf( "The RegCode Is : %s\n",szCode );

  return 0;  
}