KeyGen FileSplit 2.34.424R
某群某人发了个软件说搞不定求破解,接着ZeNiX就放了个注册成功的图片.
对于这种好玩的必然是要紧随大牛,OLLYDBG调试起。
改个返回值,秒杀,but…没显示注册给谁,唔,不好玩,直接上IDA。
我们主要关注的是411C70这个函数,函数比较简单,直接上伪码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29int CheckKey(char *user_name, const char *key_code)
{
int name_len = 0,tmp = 0;
int j = 0,i = 4;
int r_key1_value = 0,g_key3 = 0;
int key1 = 0,key2 = 0, key3 = 0, key4 = 0;
if ( sscanf(key_code, "%d-%d-%d-%d", &key1, &key2, &key3, &key4) < 4 )
return 0;
key2 = (BYTE)key2;
if ( key1 == 3535 && key2 == 35)
return 0;
if ( key1 == 453 && key2 == 6272 && key3 == 7043 && key4 == 4 )
return 0;
name_len = strlen(user_name) - 1;
do
{
tmp = (user_name[j] + user_name[name_len - j]) << 7;
tmp = tmp | 1;
j = (j + 1) % (signed int)(name_len + 1);
r_key1_value = tmp % 10 + 10 * r_key1_value;
--i;
}
while ( i );
if ( key1 != r_key1_value
|| (g_key3 = vm_decfuc((int)&vm_data, key1, key2, (int)user_name), g_key3 != key3)
|| (key2 + key3 + key1) % 0xAu != key4 )
return 0;
return 1;
}
通过这个函数我们知道:key2是随机的,只有8位参与计算,(key1+key2+key3)%10 = key4.
仔细看到我注释的一个函数名vm_decfuc,这个是一个小型的虚拟机.
弄个IDA的函数图:
虚拟机的Dispatcher:1
2
3
4
5
600411985 lea eax,dword ptr ds:[esi+esi\*2] ; EAX=00000003
00411988 mov edx,dword ptr ds:[edi+eax\*4] ; EDX=0000000E
0041198B lea eax,dword ptr ds:[edi+eax\*4] ; EAX=004312A4
0041198E cmp edx,0x1D ; FL=CS
00411991 ja FSplit.00411BDD
00411997 jmp dword ptr ds:[edx*4+0x411BF0] ;VMDispatcher
看一个Handler Vm_Add:1
2
3
4
5
6
7
8
9
1000411ADA mov ecx,dword ptr ds:[eax+0x4] ; ECX=00000000
00411ADD mov edx,dword ptr ds:[eax+0x8] ; EDX=00000003
00411AE0 mov eax,dword ptr ss:[esp+edx*4+0x8] ; EAX=00000FAC
00411AE4 mov edx,dword ptr ss:[esp+ecx*4+0x8] ; EDX=000016A1
00411AE8 lea ecx,dword ptr ss:[esp+ecx*4+0x8] ; ECX=0012F290
00411AEC add edx,eax ; FL=P, EDX=0000264D
00411AEE inc esi ; FL=0, ESI=00000002
00411AEF mov dword ptr ds:[ecx],edx
00411AF1 mov ecx,edx ; ECX=0000264D
00411AF3 jmp FSplit.00411985
截取的vm_data数据:1
2
3
4
5
6
7
800 00 00 00 03 00 00 00 AC 0F 00 00
0E 00 00 00 00 00 00 00 03 00 00 00
05 00 00 00 03 00 00 00 02 00 00 00
1D 00 00 00 00 00 00 00 00 00 00 00
0D 00 00 00 02 00 00 00 01 00 00 00
13 00 00 00 00 00 00 00 00 40 00 00
16 00 00 00 03 00 00 00 00 00 00 00
......
结构很简单,一个Handler使用了3个DWORD数据:00000000、00000003、00000FAC.
00000000为操作码,00000003、00000FAC为操作数。
其中1B操作码是用于判断跳转的,还原出代码为:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26int getkey3(int key1,int bkey2,char* user_name)
{
BYTE bN = 0;
int i= 0,flg = 0;
int nl = strlen(user_name);
key1 = key1 + 0xfac;
while(i < nl)
{
bN = user_name[i];
flg = key1 & 0x4000;
if(flg)
{
key1 = key1 & 0x3FFF;
key1 = key1 << 1;
key1 = key1 | 1;
}
else
{
key1 = key1 << 1;
}
bN ^= bkey2;
key1 ^= bN;
i++;
}
return key1;
}
(我们可以看到,取个合适长度的用户名是很重要的,^_^)
最后,我们的keygen就完成了:
注册的效果:
PS:cpp已上传。