【标题】【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进制形式。
【全文完】