其中CALL GNCRK10_.0042D4B8 ; 检查Unlock Code是否正确函数如下:
0042D4B8 55 PUSH EBP
0042D4B9 8BEC MOV EBP,ESP
0042D4BB 6A 00 PUSH 0
0042D4BD 53 PUSH EBX
0042D4BE 33C0 XOR EAX,EAX
0042D4C0 55 PUSH EBP
0042D4C1 68 46D54200 PUSH GNCRK10_.0042D546
0042D4C6 64:FF30 PUSH DWORD PTR FS:[EAX]
0042D4C9 64:8920 MOV DWORD PTR FS:[EAX],ESP
0042D4CC 8D55 FC LEA EDX,DWORD PTR SS:[EBP-4]
0042D4CF A1 0CF74200 MOV EAX,DWORD PTR DS:[42F70C]
0042D4D4 8B80 F0010000 MOV EAX,DWORD PTR DS:[EAX+1F0]
0042D4DA E8 9DC9FEFF CALL GNCRK10_.00419E7C
0042D4DF 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; 取得Unlock Code
0042D4E2 E8 5991FDFF CALL GNCRK10_.00406640 ; 计算Unlock Code的Hex
0042D4E7 8BD8 MOV EBX,EAX
0042D4E9 8D55 FC LEA EDX,DWORD PTR SS:[EBP-4]
0042D4EC A1 0CF74200 MOV EAX,DWORD PTR DS:[42F70C]
0042D4F1 8B80 F0010000 MOV EAX,DWORD PTR DS:[EAX+1F0]
0042D4F7 E8 80C9FEFF CALL GNCRK10_.00419E7C
0042D4FC 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] ; 取得Unlock Code
0042D4FF E8 BC62FDFF CALL GNCRK10_.004037C0 ; 取Unlock Code的长度
0042D504 84C0 TEST AL,AL
0042D506 76 10 JBE SHORT GNCRK10_.0042D518
0042D508 81F3 865E0100 XOR EBX,15E86 ; Unlock Code的Hex异或0x15E86
0042D50E 81E3 F01E0100 AND EBX,11EF0 ; Unlock Code的Hex与0x11EF0
0042D514 FEC8 DEC AL
0042D516 ^ 75 F0 JNZ SHORT GNCRK10_.0042D508 ; Unlock Code的长度循环次数
0042D518 81FB E00A0100 CMP EBX,10AE0 ; 结果必须与0x10AE0相等,否则非法.
0042D51E 75 09 JNZ SHORT GNCRK10_.0042D529
0042D520 C605 11F74200 0>MOV BYTE PTR DS:[42F711],1 ; 置Unlock Code合法标志位
0042D527 EB 07 JMP SHORT GNCRK10_.0042D530
0042D529 C605 11F74200 0>MOV BYTE PTR DS:[42F711],0 ; 置Unlock Code不合法标志位
0042D530 33C0 XOR EAX,EAX
0042D532 5A POP EDX
0042D533 59 POP ECX
0042D534 59 POP ECX
0042D535 64:8910 MOV DWORD PTR FS:[EAX],EDX
0042D538 68 4DD54200 PUSH GNCRK10_.0042D54D
0042D53D 8D45 FC LEA EAX,DWORD PTR SS:[EBP-4]
0042D540 E8 FF5FFDFF CALL GNCRK10_.00403544
0042D545 C3 RETN
0042D546 ^ E9 9D5AFDFF JMP GNCRK10_.00402FE8
0042D54B ^ EB F0 JMP SHORT GNCRK10_.0042D53D
0042D54D 5B POP EBX
0042D54E 59 POP ECX
0042D54F 5D POP EBP
0042D550 C3 RETN
计算正确Unlock Code的算法很简单,但要你一眼看出来估计也不是易事,我是菜鸟,差点就想爆破算了,但我还是忍了,决定一定要算出来了。参考了Cronos写的Tutorial,其中关于计算Unlock Code的说明如下:
“You can see the relevant parts of the above checking routine. This is all on the unlock code (string3 I called it at the time). It is obviously converted into a number and saved in ebx. We then get the length of it, loop around doing some maths and check it against an expected value before setting a flag.
There's actually an easy way to solve this problem and here is how. We loop based on the length of the number (call this unlock code X for now), and then check it against a 5 digit number, so let X have 5 digits, so we do 5 loops, ok. Now the problem is ((X xor 15e86) and 11ef0) etc etc = 10ae0. What do you notice about this ? Well for a start one digit in X has no effect on any others. Take the last digit of X. It is anded with 0 right ? On each iteration, so it will always be 0 at the end. So the last digit of X can be anything, we'll call it 0. You can actually solve the whole problem digit by digit. Or you could solve it bit by bit.....so this isnt so hard. The final code ? I used 1460h, or 5216 decimal. Ah but that has only 4 digits.......ok, input 05216......happy now ?
”
但这种办法需要你详细的用手计算了,如果你的数学功底不好的话,又不够细心,估计你看得都晕了。想如今电脑配置都这么好,不能浪费了,让它去算吧。穷举一下了。
根据上面算法,我们以5位数的Unlock Code计算为例说明,其求解正确的Unlock Code程序如下:
void computeUnlockCode()
{
int c[5];//说明c[5]代表穷举Unlock Code的Hex值的各位
int d[5];
int i,j;
long temp;
//c[0]代表Code的最高位,c[4]代表最低位。
//说明以5位Unlock Code为例说明,十进制的99999=0x1869F,所以我们只取c[0]=0,1,如果计算出来的
for(c[0]=0;c[0]<=0x1;c[0]++)
for(c[1]=0;c[1]<=0xF;c[1]++)
for(c[2]=0;c[2]<=0xF;c[2]++)
for(c[3]=0;c[3]<=0xF;c[3]++)
for(c[4]=0;c[4]<=0xF;c[4]++)
{
d[0]=c[0];
d[1]=c[1];
d[2]=c[2];
d[3]=c[3];
d[4]=c[4];
for(i=0;i<5;i++)
{
d[0]=d[0]^0x1;
d[0]=d[0]&0x1;
d[1]=d[1]^0x5;
d[1]=d[1]&0x1;
d[2]=d[2]^0xE;
d[2]=d[2]&0xE;
d[3]=d[3]^0x8;
d[3]=d[3]&0xF;
d[4]=d[4]^0x6;
d[4]=d[4]&0x0;
}
if(d[0]==0x1 && d[1]==0 && d[2]==0xA && d[3]==0xE && d[4]==0)
printf("The 0x%X%X%X%X%X is the correct unlock code\n",c[0],c[1],c[2],c[3],c[4]);
}
void main()
{
char name[20];
int length;
int temp;
int temp1;
int ediTemp=0x8991B;
int sn,i;
scanf("%s",name);
if((length=strlen(name))<5)
{
printf("The user name should at least 5 length\n");
return;
}
for(i=0;i<length;i++)
{
if(name[i]>=0x61 && name[i]<=0x7a)
name[i]-=0x20;
}
for(i=0;i<length/2;i++)
{
temp=name[2*i+1]%5;
temp1=temp*0xEFD5F;
ediTemp=temp1^ediTemp;
}
sn=ediTemp^0x8991B;
printf("The Serial is %d",sn);
computeUnlockCode();
}
【分析总结】要想得到所有正确的注册码,往往需要穷举了。为了给我这样的菜鸟一定的帮助,我拿《加密与解密》随书光盘习题GC Crackme 9GC Crackme 9和GC Crackme 10为例说明了。希望给菜鸟一定的帮助。