【标题】【VC】【简单】CDSpace V5.1.0 注册算法分析
【作者】forever[RCT]
【语言】VC5
【保护】无壳,注册码
【级别】简单
【简介】
 
        一个非常不错的虚拟光驱程序,操作简单,最大可同时使用23个虚拟光驱,并且还支持网络的功能。比起一般的虚拟光驱优点在于增加减少虚拟光驱数目的时候都不需要重启动机器,可以把CD、游戏光盘、数据音频混合光盘等等都压缩成LCD文件。还可以把ISO文件直接转换成LCD文件,游戏迷们再也不用怕光驱和光盘两败俱伤了。
        这个软件不错。可惜保护太简单了点,比较适合初学破解的练手。
        软件在注册不成功是提示注册码错误,因此从这个MessageBox下手。od载入后进入注册界面,在命令行下断点:bp MessageBoxA.输入假注册码,会被拦下。取消断点,逐层返回,会来到下面:

.text:0042C460 sub_42C460      proc near     
.text:0042C460
.text:0042C460 var_14          = dword ptr -14h
.text:0042C460 var_4           = dword ptr -4
.text:0042C460
.text:0042C460                 push    ecx
.text:0042C461                 push    esi
.text:0042C462                 push    edi
.text:0042C463                 mov     edi, ecx
.text:0042C465                 push    1
.text:0042C467                 call    CWnd::UpdateData(int)
.text:0042C46C                 mov     eax, [edi+10ACh]
.text:0042C472                 cmp     dword ptr [eax-8], 1
.text:0042C476                 jge     short loc_42C497 ; 注册名必须大于等于1个字符
.text:0042C478                 push    0
.text:0042C47A                 push    ecx
.text:0042C47B                 mov     ecx, esp
.text:0042C47D                 mov     [esp+14h+var_4], esp
.text:0042C481                 push    offset aMsg_sharewar_2 ; "MSG_SHAREWARE_SHORTNAME"
.text:0042C486                 call    CString::CString(char const *)
.text:0042C48B                 call    sub_416AE0
.text:0042C490                 add     esp, 8
.text:0042C493                 pop     edi
.text:0042C494                 pop     esi
.text:0042C495                 pop     ecx
.text:0042C496                 retn
.text:0042C497 loc_42C497:                           
.text:0042C497                 lea     esi, [edi+10B0h]
.text:0042C49D                 push    offset unk_44AE80
.text:0042C4A2                 push    offset asc_44A45C ; "-"
.text:0042C4A7                 mov     ecx, esi
.text:0042C4A9                 call    MFC42_6877      ; 去掉‘-’
.text:0042C4AE                 push    offset unk_44AE80
.text:0042C4B3                 push    offset asc_4491EC ; " "
.text:0042C4B8                 mov     ecx, esi
.text:0042C4BA                 call    MFC42_6877      ; 去掉空格
.text:0042C4BF                 mov     esi, [esi]
.text:0042C4C1                 cmp     dword ptr [esi-8], 16
.text:0042C4C5                 jz      short loc_42C4E6 ; 注册码去掉空格和‘-’后必须是16个字符
.text:0042C4C7                 push    0
.text:0042C4C9                 push    ecx
.text:0042C4CA                 mov     ecx, esp
.text:0042C4CC                 mov     [esp+24h+var_14], esp
.text:0042C4D0                 push    offset aMsg_sharewar_3 ; "MSG_SHAREWARE_SHORTSERIAL"
.text:0042C4D5                 call    CString::CString(char const *)
.text:0042C4DA                 call    sub_416AE0
.text:0042C4DF                 add     esp, 8
.text:0042C4E2                 pop     edi
.text:0042C4E3                 pop     esi
.text:0042C4E4                 pop     ecx
.text:0042C4E5                 retn
.text:0042C4E6 loc_42C4E6:                             
.text:0042C4E6                 push    esi
.text:0042C4E7                 mov     ecx, edi
.text:0042C4E9                 call    sub_42CD70      ; 验证的CALL,要跟进
.text:0042C4EE                 push    0
.text:0042C4F0                 push    ecx
.text:0042C4F1                 test    eax, eax
.text:0042C4F3                 mov     ecx, esp
.text:0042C4F5                 jz      short loc_42C518
.text:0042C4F7                 mov     [esp+24h+var_14], esp
.text:0042C4FB                 push    offset aMsg_sharewar_4 ; "MSG_SHAREWARE_REGISTERED"
.text:0042C500                 call    CString::CString(char const *)
.text:0042C505                 call    sub_416AE0
.text:0042C50A                 add     esp, 8
.text:0042C50D                 mov     ecx, edi
.text:0042C50F                 call    CDialog::OnOK(void)
.text:0042C514                 pop     edi
.text:0042C515                 pop     esi
.text:0042C516                 pop     ecx
.text:0042C517                 retn
.text:0042C518
.text:0042C518 loc_42C518:                             
.text:0042C518                 mov     [esp+24h+var_14], esp
.text:0042C51C                 push    offset aMsg_sharewar_5 ; "MSG_SHAREWARE_INVALIDSERIAL"
.text:0042C521                 call    CString::CString(char const *)
.text:0042C526                 call    sub_416AE0
.text:0042C52B                 add     esp, 8
.text:0042C52E                 pop     edi
.text:0042C52F                 pop     esi
.text:0042C530                 pop     ecx
.text:0042C531                 retn
.text:0042C531 sub_42C460      endp ; sp = -10h

      到这里可以看出注册名必须至少一个字符,注册码在去掉空格和'-'后必须是16个字符长。
      继续跟进下面的CALL:
      
.text:0042CD70 sub_42CD70      proc near             
.text:0042CD70
.text:0042CD70 hKey            = dword ptr -2Ch
.text:0042CD70 dwDisposition   = dword ptr -28h
.text:0042CD70 var_24          = dword ptr -24h
.text:0042CD70 Data            = byte ptr -20h
.text:0042CD70 var_1B          = dword ptr -1Bh
.text:0042CD70 var_17          = dword ptr -17h
.text:0042CD70 var_13          = dword ptr -13h
.text:0042CD70 var_C           = dword ptr -0Ch
.text:0042CD70 var_4           = dword ptr -4
.text:0042CD70 arg_0           = dword ptr  4
.text:0042CD70
.text:0042CD70                 push    0FFFFFFFFh
.text:0042CD72                 push    offset loc_43A5E8
.text:0042CD77                 mov     eax, large fs:0
.text:0042CD7D                 push    eax
.text:0042CD7E                 mov     large fs:0, esp
.text:0042CD85                 sub     esp, 20h
.text:0042CD88                 push    esi
.text:0042CD89                 push    edi
.text:0042CD8A                 mov     edi, [esp+34h+arg_0]
.text:0042CD8E                 lea     eax, [edi+0Ah]  ; 取假注册码第11到16位
.text:0042CD91                 push    eax             ; char *
.text:0042CD92                 call    ds:atoi         ; 转成整数
.text:0042CD98                 add     esp, 4
.text:0042CD9B                 lea     ecx, [esp+34h+arg_0]
.text:0042CD9F                 push    eax             ; 转换后的整数
.text:0042CDA0                 push    ecx             ; 假注册码
.text:0042CDA1                 mov     ecx, offset unk_44AF10
.text:0042CDA6                 call    sub_419EB0      ; 生成注册码的CALL,要跟进
.text:0042CDAB                 mov     edx, [esp+34h+arg_0]
.text:0042CDAF                 push    edi             ; char *  真注册码
.text:0042CDB0                 push    edx             ; char *  假注册码
.text:0042CDB1                 mov     [esp+3Ch+var_4], 0
.text:0042CDB9                 call    ds:_stricmp     ; 经典比较 ^_^
.text:0042CDBF                 add     esp, 8
.text:0042CDC2                 test    eax, eax
.text:0042CDC4                 jnz     loc_42CEAC      ; 不等则跳走
.text:0042CDCA                 mov     [esp+34h+Data], al
.text:0042CDCE                 mov     [esp+15h], eax
.text:0042CDD2                 mov     [esp+34h+var_1B], eax
.text:0042CDD6                 mov     esi, edi
.text:0042CDD8                 mov     [esp+34h+var_17], eax
.text:0042CDDC                 lea     ecx, [esp+34h+Data]
.text:0042CDE0                 mov     [esp+34h+var_13], eax
.text:0042CDE4                 sub     esi, ecx
.text:0042CDE6 loc_42CDE6:                             ; 下面这些是验证通过后加密保存到注册表里,略过
.text:0042CDE6                 lea     ecx, [esp+eax+34h+Data]

      继续跟进下面的CALL,看看注册码怎么生成:
      
.text:00419EB0 sub_419EB0      proc nea             
.text:00419EB0
.text:00419EB0 var_14          = dword ptr -14h
.text:00419EB0 var_10          = dword ptr -10h
.text:00419EB0 var_C           = dword ptr -0Ch
.text:00419EB0 var_4           = dword ptr -4
.text:00419EB0 arg_0           = dword ptr  4
.text:00419EB0 arg_4           = dword ptr  8
.text:00419EB0
.text:00419EB0                 push    0FFFFFFFFh
.text:00419EB2                 push    offset loc_438A9F
.text:00419EB7                 mov     eax, large fs:0
.text:00419EBD                 push    eax
.text:00419EBE                 mov     large fs:0, esp
.text:00419EC5                 sub     esp, 8
.text:00419EC8                 push    esi
.text:00419EC9                 lea     ecx, [esp+18h+var_14]
.text:00419ECD                 mov     [esp+18h+var_10], 0
.text:00419ED5                 call    CString::CString(void)
.text:00419EDA                 mov     ecx, [esp+18h+arg_4] ; 传进来的整数,设为i
.text:00419EDE                 mov     [esp+18h+var_4], 1
.text:00419EE6                 push    ecx
.text:00419EE7                 lea     eax, [ecx+ecx*8]
.text:00419EEA                 shl     eax, 5
.text:00419EED                 add     eax, ecx
.text:00419EEF                 lea     eax, [eax+eax*2]
.text:00419EF2                 lea     eax, [ecx+eax*4]
.text:00419EF5                 lea     ecx, [esp+1Ch+var_14]
.text:00419EF9                 shl     eax, 3
.text:00419EFC                 xor     eax, 6666h
.text:00419F01                 sub     eax, 1B08h
.text:00419F06                 xor     eax, 0FFFF805Bh
.text:00419F0B                 and     eax, 0FFA5h
.text:00419F10                 add     eax, 53h
.text:00419F13                 push    eax       ; (((i * 9 * 32 + i) * 3 * 4 + i) * 8 ^ 0x6666 - 0x1b08) ^ 0xffff805b & 0xffa5 + 53
.text:00419F14                 push    682
.text:00419F19                 push    0E5h
.text:00419F1E                 push    'S'
.text:00419F20                 push    offset aC0_2x0_3d0_4x0 ; "%c%0.2X%0.3d%0.4X%0.6d"
.text:00419F25                 push    ecx
.text:00419F26                 call    CString::Format(char const *,...)
.text:00419F2B                 mov     esi, [esp+34h+arg_0]
.text:00419F2F                 add     esp, 1Ch
.text:00419F32                 lea     edx, [esp+18h+var_14]
.text:00419F36                 mov     ecx, esi
.text:00419F38                 push    edx
.text:00419F39                 call    CString::CString(CString const &)
.text:00419F3E                 mov     [esp+18h+var_10], 1
.text:00419F46                 lea     ecx, [esp+18h+var_14]
.text:00419F4A                 mov     byte ptr [esp+18h+var_4], 0
.text:00419F4F                 call    CString::~CString(void)
.text:00419F54                 mov     ecx, [esp+18h+var_C]
.text:00419F58                 mov     eax, esi
.text:00419F5A                 pop     esi
.text:00419F5B                 mov     large fs:0, ecx
.text:00419F62                 add     esp, 14h
.text:00419F65                 retn    8
.text:00419F65 sub_419EB0      endp

      呵呵。是不是很简单哦。
      总结一下:注册码去掉空格和'-'后长度为16位。取后6位转换成整数,设为i(无符号型),则
由下面的公式生成一个整数:
      (((i * 9 * 32 + i) * 3 * 4 + i) * 8 ^ 0x6666 - 0x1b08) ^ 0xffff805b & 0xffa5 + 53
      
      这个整数的16进制形式就是注册码的7-10位。
      注册码1-6位固定是 SE5682
      注册码后6位为一个整数的10进制形式。
      
      【全文完】