好友
阅读权限30
听众
最后登录1970-1-1
|
红绡枫叶
发表于 2014-12-21 23:02
本帖最后由 红绡枫叶 于 2015-1-8 20:16 编辑
这款600K大小的3D屏保软件的注册算法挺有意思的,就把它的算法彻底分析了一遍.
VC6.0编译,MFC.找到MFC派发CMD消息的函数_AfxDispatchCmdMsg(CCmdTarget *,uint,int,void (CCmdTarget::*)(void),void *,uint,AFX_CMDHANDLERINFO *)
快速定位到注册按钮单击后的事件处理地址:
[Asm] 纯文本查看 复制代码 CPU Disasm
Address Hex dump Command Comments
00406940 r /. 64:A1 000 mov eax, dword ptr fs:[0]
00406946 |. 6A FF push -1
00406948 |. 68 436044 push unknown_libname_605
0040694D |. 50 push eax
0040694E |. 64:8925 0 mov dword ptr fs:[0], esp ; Installs SE handler unknown_libname_605
00406955 |. 81EC B400 sub esp, 0B4
0040695B |. 53 push ebx
0040695C |. 55 push ebp
0040695D |. 56 push esi
0040695E |. 57 push edi
0040695F |. 8BF1 mov esi, ecx
00406961 |. 6A 01 push 1 ; /Arg1 = 1
00406963 |. E8 665A03 call CWnd::UpdateData(int) ; \Galaxy3D.CWnd::UpdateData(int)
00406968 |. 68 2C0100 push 12C ; /Time = 300. ms
0040696D |. FF15 7092 call dword ptr ds:[<&KERNEL32.Sleep>] ; \KERNEL32.Sleep
00406973 |. 8DBE A000 lea edi, [esi+0A0]
00406979 |. 8DAE 9C00 lea ebp, [esi+9C]
0040697F |. 8D9E 9800 lea ebx, [esi+98]
00406985 |. 57 push edi
00406986 |. 55 push ebp
00406987 |. 53 push ebx
00406988 |. FF15 9882 call dword ptr ds:[off_458298] ;算法所在地
0040698E |. 83C4 0C add esp, 0C
00406991 |. 85C0 test eax, eax ;关键跳转
00406993 |. 0F84 9700 jz loc_406A30
00406999 |. 8D4C24 10 lea ecx, [arg.4]
0040699D |. E8 BE7400 call sub_40DE60 ; [Galaxy3D.sub_40DE60
004069A2 |. 6A 00 push 0 ; /Arg1 = 0
004069A4 |. 8D4C24 14 lea ecx, [arg.5] ; |
004069A8 |. C78424 D0 mov dword ptr ss:[arg.52], 0 ; |
004069B3 |. E8 187A00 call sub_40E3D0 ; \Galaxy3D.sub_40E3D0
004069B8 |. 53 push ebx ; /Arg1
004069B9 |. 8D4C24 50 lea ecx, [arg.20] ; |
004069BD |. E8 292403 call CString::operator=(CString const ; \Galaxy3D.CString::operator=
004069C2 |. 55 push ebp ; /Arg1
004069C3 |. 8D4C24 54 lea ecx, [arg.21] ; |
004069C7 |. E8 1F2403 call CString::operator=(CString const ; \Galaxy3D.CString::operator=
004069CC |. 57 push edi ; /Arg1
004069CD |. 8D4C24 4C lea ecx, [arg.19] ; |
004069D1 |. E8 152403 call CString::operator=(CString const ; \Galaxy3D.CString::operator=
004069D6 |. 6A 00 push 0 ; /Arg1 = 0
004069D8 |. 8D4C24 14 lea ecx, [arg.5] ; |
004069DC |. E8 9F7700 call sub_40E180 ; \Galaxy3D.sub_40E180
004069E1 |. 6A 00 push 0 ; /Arg2 = 0
004069E3 |. 68 970000 push 97 ; |Arg1 = 97
004069E8 |. 8D4C24 70 lea ecx, [arg.28] ; |
004069EC |. E8 C43203 call CDialog::CDialog(uint,CWnd *) ; \Galaxy3D.CDialog::CDialog
004069F1 |. 8D4C24 68 lea ecx, [arg.26]
004069F5 |. C68424 CC mov byte ptr ss:[arg.51], 1
004069FD |. E8 683303 call CDialog::DoModal(void) ; [Galaxy3D.CDialog::DoModal(void)
00406A02 |. 8BCE mov ecx, esi
00406A04 |. E8 4C3603 call CDialog::OnOK(void) ; [Galaxy3D.CDialog::OnOK(void)
00406A09 |. 8D4C24 68 lea ecx, [arg.26]
00406A0D |. C68424 CC mov byte ptr ss:[arg.51], 0
00406A15 |. E8 862F03 call sub_4399A0 ; [Galaxy3D.CDialog::~CDialog
00406A1A |. 8D4C24 10 lea ecx, [arg.4]
00406A1E |. C78424 CC mov dword ptr ss:[arg.51], -1
00406A29 |. E8 427600 call sub_40E070 ; [Galaxy3D.sub_40E070
00406A2E |. EB 16 jmp short loc_406A46
00406A30 l |> 68 C80000 push 0C8 ; /Time = 200. ms
00406A35 |. FF15 7092 call dword ptr ds:[<&KERNEL32.Sleep>] ; \KERNEL32.Sleep
00406A3B |. 6A FF push -1 ; /Arg3 = -1
00406A3D |. 6A 00 push 0 ; |Arg2 = 0
00406A3F |. 6A 0E push 0E ; |Arg1 = 0E
00406A41 |. E8 5E9903 call AfxMessageBox(uint,uint,uint) ; \Galaxy3D.AfxMessageBox ;出错提示.
00406A46 l |> 8B8C24 C4 mov ecx, dword ptr ss:[arg.49]
00406A4D |. 5F pop edi
00406A4E |. 5E pop esi
00406A4F |. 5D pop ebp
00406A50 |. 5B pop ebx
00406A51 |. 64:890D 0 mov dword ptr fs:[0], ecx
00406A58 |. 81C4 C000 add esp, 0C0
00406A5E \. C3 retn
于是跟进算法CALL:
[Asm] 纯文本查看 复制代码 CPU Disasm
Address Hex dump Command Comments
00402F00 s /$ 8B4C24 04 mov ecx, dword ptr ss:[arg.1] ; ASCII "123456789abc",这是我输入的注册码
00402F04 |. 81EC 2C01 sub esp, 12C
00402F0A |. 8D4424 00 lea eax, [local.74]
00402F0E |. 6A 06 push 6
00402F10 |. 50 push eax
00402F11 |. 51 push ecx
00402F12 |. E8 A9FDFF call RegKeys2HexNum ;将输入的12个注册码转换成16进制数值,即0x123456789abc
00402F17 |. 83C4 0C add esp, 0C
00402F1A |. 83F8 06 cmp eax, 6 ;转化后的大小为6byte,其实也就是说,注册码只能是12位
00402F1D |. 74 0C je short loc_402F2B
00402F1F |. B8 12AE00 mov eax, 0AE12
00402F24 |. 81C4 2C01 add esp, 12C
00402F2A |. C3 retn
00402F2B l |> 6A 06 push 6
00402F2D |. 8D5424 04 lea edx, [local.74]
00402F31 |. 68 940000 push 94
00402F36 |. 52 push edx
00402F37 |. E8 34FCFF call regkey_check ;真正的算法验证的地方
00402F3C |. 83C4 0C add esp, 0C
00402F3F |. F7D8 neg eax ; If eax is not 0, sets it to 00003397
00402F41 |. 1BC0 sbb eax, eax
00402F43 |. 25 973300 and eax, 00003397
00402F48 |. 05 30AE00 add eax, 0AE30
00402F4D |. 81C4 2C01 add esp, 12C
00402F53 \. C3 retn
我们看看RegKeys2HexNum函数关键的内容:
[Asm] 纯文本查看 复制代码 CPU Disasm
Address Hex dump Command Comments
00402CFE |. C645 FC 0 mov byte ptr ss:[local.1], 1
00402D02 |. E8 824D03 call CString::TrimLeft(void) ; 清除空格
00402D07 |. 8D4D 08 lea ecx, [arg.1]
00402D0A |. E8 2E4D03 call CString::TrimRight(void) ; 清除空格
00402D0F |. 8975 E8 mov dword ptr ss:[local.6], esi
00402D12 l |> 8B4D 08 /mov ecx, dword ptr ss:[ebp+8]
00402D15 l |> 3B71 F8 |/cmp esi, dword ptr ds:[ecx-8]
00402D18 |. 7D 6F ||jge short loc_402D89
00402D1A |. 8A040E ||mov al, byte ptr ds:[ecx+esi]
00402D1D |. 3C 2D ||cmp al, 2D ;剔除'-'
00402D1F |. 74 26 ||je short loc_402D47
00402D21 |. 3C 41 ||cmp al, 41 ;
00402D23 |. 7C 04 ||jl short loc_402D29
00402D25 |. 3C 46 ||cmp al, 46 ;
00402D27 |. 7E 18 ||jle short loc_402D41
00402D29 l |> 3C 61 ||cmp al, 61
00402D2B |. 7C 04 ||jl short loc_402D31
00402D2D |. 3C 66 ||cmp al, 66
00402D2F |. 7E 10 ||jle short loc_402D41
00402D31 l |> 3C 30 ||cmp al, 30
00402D33 |. 0F8C FC00 ||jl loc_402E35 ;跳向失败
00402D39 |. 3C 39 ||cmp al, 39
00402D3B |. 0F8F F400 ||jg loc_402E35 ;跳向失败,综合上面的比较,可得出每一位注册码都必须在0123456789ABCDEFabcdef范围内
00402D41 l |> 46 ||inc esi
00402D42 |. 8975 E8 ||mov dword ptr ss:[ebp-18], esi
00402D45 |.^ EB CE |\jmp short loc_402D15
00402D47 l |> 8D4D DC |lea ecx, [ebp-24]
......
00402E0E |. 6A 10 |push 10 ; /Arg3 = 10
00402E10 |. 50 |push eax ; |Arg2
00402E11 |. 51 |push ecx ; |Arg1
00402E12 |. E8 C73F02 |call _strtoul ;将字符串转换成无符号长整型数
00402E17 |. 83C4 0C |add esp, 0C
00402E1A |. 88043E |mov byte ptr ds:[edi+esi], al
00402E1D |. 46 |inc esi
00402E1E \.^ EB 90 \jmp short loc_402DB0 ;循环将"123456789abc"转换成数值0x123456789abc
......
我们再看看regkey_check函数里面:
[Asm] 纯文本查看 复制代码 CPU Disasm
Address Hex dump Command Comments
00402B70 r /$ 81EC 0401 sub esp, 104
00402B76 |. 53 push ebx
00402B77 |. 55 push ebp
00402B78 |. 56 push esi
00402B79 |. 57 push edi
00402B7A |. E8 37FD03 call AfxGetModuleState(void) ; [Galaxy3D.AfxGetModuleState
00402B7F |. 8B8C24 1C mov ecx, dword ptr ss:[arg.2]
00402B86 |. 8B40 0C mov eax, dword ptr ds:[eax+0C]
00402B89 |. 68 688245 push offset Type ; /Type = "encdata"
00402B8E |. 51 push ecx ; |Name => [ARG.2]
00402B8F |. 50 push eax ; |hModule
00402B90 |. FF15 5492 call dword ptr ds:[<&KERNEL32.FindReso ; \KERNEL32.FindResourceA ;这是比较特别的地方,他要读取一个叫做"encdata"资源!
00402B96 |. 8BF0 mov esi, eax
00402B98 |. 85F6 test esi, esi
00402B9A |. 0F84 9400 jz loc_402C34
00402BA0 |. E8 11FD03 call AfxGetModuleState(void) ; [Galaxy3D.AfxGetModuleState
00402BA5 |. 8B40 0C mov eax, dword ptr ds:[eax+0C]
00402BA8 |. 56 push esi ; /hRes
00402BA9 |. 50 push eax ; |hModule
00402BAA |. FF15 5092 call dword ptr ds:[<&KERNEL32.SizeofRe ; \KERNEL32.SizeofResource
00402BB0 |. 8BC8 mov ecx, eax ;返回值是"encdata"的大小!
00402BB2 |. 85C9 test ecx, ecx
00402BB4 |. 74 7E jz short loc_402C34
00402BB6 |. 8B9C24 20 mov ebx, dword ptr ss:[arg.3] ;arg.3 =6,是常数
00402BBD |. 85DB test ebx, ebx
00402BBF |. 74 73 jz short loc_402C34
00402BC1 |. 33D2 xor edx, edx
00402BC3 |. F7F3 div ebx ; EDX:EAX / ebx ,即SizeofResource("encdata")/6
00402BC5 |. 85D2 test edx, edx ;不能被6整除就失败了!
00402BC7 |. 75 6B jnz short loc_402C34
00402BC9 |. 8BC1 mov eax, ecx
00402BCB |. F7F3 div ebx
00402BCD |. 8BF8 mov edi, eax ;同样,SizeofResource("encdata")/6的商给edi
00402BCF |. 83FF 01 cmp edi, 1
00402BD2 |. 897C24 10 mov dword ptr ss:[local.64], edi ;记住了,local.64=SizeofResource("encdata")/6的商
00402BD6 |. 72 5C jb short loc_402C34
00402BD8 |. E8 D9FC03 call AfxGetModuleState(void) ; [Galaxy3D.AfxGetModuleState
00402BDD |. 8B40 0C mov eax, dword ptr ds:[eax+0C]
00402BE0 |. 56 push esi ; /hResource
00402BE1 |. 50 push eax ; |hModule
00402BE2 |. FF15 4C92 call dword ptr ds:[KERNEL32.LoadResource]
00402BE8 |. 85C0 test eax, eax
00402BEA |. 74 48 jz short loc_402C34
00402BEC |. 50 push eax
00402BED |. FF15 4892 call dword ptr ds:[<&KERNEL32.LockResources]
00402BF3 |. 8BF0 mov esi, eax ;这个返回值很重要了,是"encdata"数据的地址!
00402BF5 |. 85F6 test esi, esi
00402BF7 |. 74 3B jz short loc_402C34
00402BF9 |. 8B9424 18 mov edx, dword ptr ss:[arg.70]
00402C00 |. 53 push ebx ; /Arg3
00402C01 |. 8D4424 18 lea eax, [arg.6]
00402C05 |. 52 push edx ; |Arg2
00402C06 |. 50 push eax ; |Arg1
00402C07 |. E8 A40300 call keyGenerator ;这是我自己添加的函数名字,不要误会了,生成最后变换后的注册码
00402C0C |. 83C4 0C add esp, 0C
00402C0F |. 85C0 test eax, eax
00402C11 |. 74 21 jz short loc_402C34
00402C13 |. 33C0 xor eax, eax
00402C15 |. 85FF test edi, edi
00402C17 |. 7E 1B jle short loc_402C34
00402C19 |. 8BD6 mov edx, esi
00402C1B l |> 8BCB /mov ecx, ebx
00402C1D |. 8D7C24 14 |lea edi, [arg.5] ;
00402C21 |. 8BF2 |mov esi, edx
00402C23 |. 33ED |xor ebp, ebp
00402C25 |. F3:A6 |repe cmps byte ptr ds:[esi], byte ptr es:[edi] ;这是连续比较,当遇到不相等的时候停止,ecx会在每次比较时候递减
00402C27 |. 74 18 |je short loc_402C41 ;esi是"encdata"的地址,edi是注册码已经变换后的数值
00402C29 |. 8B4C24 10 |mov ecx, dword ptr ss:[arg.4] ;其实arg.4=local.64=SizeofResource("encdata")/6的商...OD分析的有些问题,地址是一样的
00402C2D |. 40 |inc eax
00402C2E |. 03D3 |add edx, ebx
00402C30 |. 3BC1 |cmp eax, ecx ;可分析得到,他是把转化后的注册码与"encdata"每6位一次比较,失败了就跳向下一个6byte的数据再比较
00402C32 |.^ 7C E7 \jl short loc_402C1B
00402C34 l |> 5F pop edi
00402C35 |. 5E pop esi
00402C36 |. 5D pop ebp
00402C37 |. 33C0 xor eax, eax
00402C39 |. 5B pop ebx
00402C3A |. 81C4 0401 add esp, 104
00402C40 |. C3 retn
现在就是要看他是是怎么得到变换后的注册码的了,看keyGenerator函数:
[Asm] 纯文本查看 复制代码 CPU Disasm
Address Hex dump Command Comments
00402FB0 k /$ 51 push ecx ; Galaxy3D.keyGenerator(guessed Arg1,Arg2,Arg3)
00402FB1 |. 53 push ebx
00402FB2 |. 55 push ebp
00402FB3 |. 56 push esi
00402FB4 |. 57 push edi
00402FB5 |. 8D4C24 10 lea ecx, [local.0]
00402FB9 |. E8 A2FFFF call loadMagicNum ;其实没用
00402FBE |. 8B5C24 20 mov ebx, dword ptr ss:[arg3]
00402FC2 |. 8B6C24 18 mov ebp, dword ptr ss:[arg1]
00402FC6 |. 8B7424 1C mov esi, dword ptr ss:[arg2]
00402FCA |. 8BCB mov ecx, ebx
00402FCC |. 8BC1 mov eax, ecx
00402FCE |. 8BFD mov edi, ebp
00402FD0 |. C1E9 02 shr ecx, 2
00402FD3 |. F3:A5 rep movs dword ptr es:[edi], dword ptr ds:[esi]
00402FD5 |. 8BC8 mov ecx, eax
00402FD7 |. 83E1 03 and ecx, 00000003
00402FDA |. F3:A4 rep movs byte ptr es:[edi], byte ptr ds:[esi]
00402FDC |. 33FF xor edi, edi
00402FDE |. 85DB test ebx, ebx
00402FE0 |. 7E 45 jle short loc_403027
00402FE2 l |> 8B5424 1C /mov edx, dword ptr ss:[arg2]
00402FE6 |. 33C9 |xor ecx, ecx
00402FE8 |. 8A0C17 |mov cl, byte ptr ds:[edx+edi] ;我们转换了的注册码,0x123456789abc
00402FEB |. 51 |push ecx ; /Arg1
00402FEC |. 8D4C24 14 |lea ecx, [local.0] ; |
00402FF0 |. E8 ABFFFF |call copyDw ; \Galaxy3D.copyDw
00402FF5 |. 33F6 |xor esi, esi
00402FF7 l |> 8D4C24 10 |/lea ecx, [local.0]
00402FFB |. E8 70FFFF ||call numShift ;这个是简单的变换
00403000 |. 8BC8 ||mov ecx, eax
00403002 |. 8BD0 ||mov edx, eax
00403004 |. C1E9 18 ||shr ecx, 18
00403007 |. C1EA 10 ||shr edx, 10
0040300A |. 32CA ||xor cl, dl
0040300C |. 8BD0 ||mov edx, eax
0040300E |. C1EA 08 ||shr edx, 8
00403011 |. 32CA ||xor cl, dl
00403013 |. 8A142E ||mov dl, byte ptr ds:[ebp+esi]
00403016 |. 32CA ||xor cl, dl
00403018 |. 32C8 ||xor cl, al
0040301A |. 880C2E ||mov byte ptr ds:[ebp+esi], cl
0040301D |. 46 ||inc esi
0040301E |. 3BF3 ||cmp esi, ebx
00403020 |.^ 7C D5 |\jl short loc_402FF7
00403022 |. 47 |inc edi
00403023 |. 3BFB |cmp edi, ebx
00403025 |.^ 7C BB \jl short loc_402FE2
00403027 l |> 5F pop edi
00403028 |. 5E pop esi
00403029 |. 5D pop ebp
0040302A |. B8 010000 mov eax, 1
0040302F |. 5B pop ebx
00403030 |. 59 pop ecx
00403031 \. C3 retn
啊....很多移位指令,不分析了,很简单的.
最终我将完整的算法转成C语言后,是这样的:
[C] 纯文本查看 复制代码 #include <cstdlib>
#include <cstdio>
#include <cstring>
#include <map>
inline int numShift(unsigned int &num)
{
//num = num + ((((((num * 13) << 4) + num) << 8)) - num) * 4 + 0x269ec3; 原始翻译过来是这样的
num = 0x343FD * num + 0x269EC3;
return num & 0x7FFFFFFF;
}
bool keyGenerator(unsigned char *keyset, const unsigned char *reg_hex_num, unsigned int blockSize)
{
unsigned int counter;
unsigned int num_;
unsigned int num;
unsigned char n[4];
memcpy(keyset, reg_hex_num, blockSize);
for (int i = 0; i < (signed int)blockSize; ++i)
{
num = reg_hex_num[i];
counter = 0;
do
{
num_ = numShift(num);
memcpy(&n[0], &num_, 4);
keyset[counter] ^= n[2] ^ n[3];
++counter;
} while (counter < blockSize);
}
return true;
}
void str2hex(unsigned char *dest, unsigned char src[2])
{
if (src[0] <= '9' && src[0] >= '0')
{
*dest = src[0] - 0x30;
*dest <<= 4;
}
else if (src[0] <= 'F'&&src[0] >= 'A')
{
*dest = src[0] - 0x37;
*dest <<= 4;
}
else if (src[0] <= 'f'&&src[0] >= 'a')
{
*dest = src[0] - 0x57;
*dest <<= 4;
}
if (src[1] <= '9' && src[1] >= '0')
{
*dest += src[1] - 0x30;
}
else if (src[1] <= 'F'&&src[1] >= 'A')
{
*dest += src[1] - 0x37;
}
else if (src[1] <= 'f'&&src[1] >= 'a')
{
*dest += src[1] - 0x57;
}
}
int main()
{
unsigned char regkeys[] = { "D6DCD3F1C6BC" }; //输入的注册码
unsigned char keyset[32]{0};
unsigned char reg_hex_num[7];
for (int i = 0; i < 6; ++i)//注册码长度必须是12
{
str2hex(reg_hex_num[i], regkeys[i * 2]);
}
keyGenerator(keyset, reg_hex_num, 6);//注册码长度必须是12
for (size_t i = 0; i < 6; i++)
{
printf("%02X", keyset[i]);//输出变换后的注册码,,,,它是用来和"encdata"比较的,在"encdata"中找到对应的,就注册成功了!
}
}
encdata与变换后的注册码比较:
我希望谁能写出注册机,并给出完整的思路.
分析的不太好,请见谅.算法总结:将注册码经过一系列变换得到的结果与资源里面叫"encdata"的数据比较,
能在"encdata"找到变换后的注册码,那就注册成功了!
.看C代码很容易看懂的.顺便一提,软件是有自校验的.
当输入注册码"D6DCD3F1C6BC"时,可以验证:
|
免费评分
-
查看全部评分
|