CCDebug有一篇文章:OllyDBG 入门系列(五)-消息断点及 RUN 跟踪(http://bbs.pediy.com/showthread.php?t=21532),
讲解了怎么设置消息断点,研究了一下那个CycleCrack,写了一个注册机。虽然学习这么多年了,这还是我写的第一个注册机,非常惭愧。
先来看看序列号的主要的认证流程:如果输入的名字不足16字节,就扩展成16字节,序列号必须为16字节。
名字和序列号的字符的取值范围为[0x30, 0x7E]。
判断序列号的汇编代码如下:
00401105 |. |E8 E7000000 call 004011F1 ;比较序列号算法
0040110A |. |B9 01FF0000 mov ecx, 0FF01
0040110F |. |51 push ecx
00401110 |. E8 7B000000 call 00401190 ;比较序列号算法
00401115 |. 83F9 01 cmp ecx, 1 ;ecx必须要等于1
00401118 |. 74 06 je short 00401120
0040111A |> E8 47000000 call 00401166 ;register failed
0040111F |> C3 retn
00401120 |> A1 68214000 mov eax, dword ptr [402168] ;name的第8字节
00401125 |. 8B1D 6C214000 mov ebx, dword ptr [40216C] ;name的第12字节
0040112B |. 33C3 xor eax, ebx
0040112D |. 3305 82214000 xor eax, dword ptr [402182] ;一个DWORD变量,由00401190生成
00401133 |. 0D 40404040 or eax, 40404040
00401138 |. 25 77777777 and eax, 77777777
0040113D |. 3305 79214000 xor eax, dword ptr [402179] ;code的第8字节
00401143 |. 3305 7D214000 xor eax, dword ptr [40217D] ;code的第12字节
00401149 |.^ 75 CF jnz short 0040111A ;如果eax为0,表示注册码正确
0040114B |. E8 2B000000 call 0040117B ;register ok
00401150 \. C3 retn
以上汇编代码改成c语言代码为:
typedef unsigned int DWORD;
typedef unsigned short WORD;
typedef unsigned char BYTE;
DWORD dwName[4];
DWORD dwCode[4];
dwName[0] = *((DWORD *)name);
dwName[1] = *((DWORD *)&name[4]);
dwName[2] = *((DWORD *)&name[8]);
dwName[3] = *((DWORD *)&name[12]);
dwCode[0] = *((DWORD *)code);
dwCode[1] = *((DWORD *)&code[4]);
dwCode[2] = *((DWORD *)&code[8]);
dwCode[3] = *((DWORD *)&code[12]);
count_402182 = 0xFEDCBA98;
function4011F1();
unsigned int ecx = 0xff01;
ecx = function401190(ecx);
if (ecx == 1)
{
unsigned int eax = dwName[2] ^ dwName[3];
eax ^= count_402182;
eax |= 0x40404040;
eax &= 0x77777777;
eax ^= dwCode[2];
eax ^= dwCode[3];
if (eax == 0)
{
printf("register ok");
}
}
序列号的算法主要在函数004011F1和函数00401190中。
004011F1 /$ A1 60214000 mov eax, dword ptr [402160]
004011F6 |. 8B1D 64214000 mov ebx, dword ptr [402164]
004011FC |. 3305 71214000 xor eax, dword ptr [402171]
00401202 |. 331D 75214000 xor ebx, dword ptr [402175]
00401208 |. 25 0F1F3F7F and eax, 7F3F1F0F
0040120D |. 81E3 00010307 and ebx, 7030100
00401213 |. 33C9 xor ecx, ecx
00401215 |> 8BF0 /mov esi, eax
00401217 |. 8BFB |mov edi, ebx
00401219 |. D3E6 |shl esi, cl
0040121B |. D3E7 |shl edi, cl
0040121D |. 81E6 80808080 |and esi, 80808080
00401223 |. 81E7 80808080 |and edi, 80808080
00401229 |. 8BD6 |mov edx, esi
0040122B |. C0EE 07 |shr dh, 7
0040122E |. 66:C1E2 07 |shl dx, 7
00401232 |. C1EA 08 |shr edx, 8
00401235 |. C0EE 07 |shr dh, 7
00401238 |. 66:C1E2 07 |shl dx, 7
0040123C |. C1EA 08 |shr edx, 8
0040123F |. C0EE 07 |shr dh, 7
00401242 |. 66:D1EA |shr dx, 1
00401245 |. 8BF2 |mov esi, edx
00401247 |. 8BD7 |mov edx, edi
00401249 |. C0EE 07 |shr dh, 7
0040124C |. 66:C1E2 07 |shl dx, 7
00401250 |. C1EA 08 |shr edx, 8
00401253 |. C0EE 07 |shr dh, 7
00401256 |. 66:C1E2 07 |shl dx, 7
0040125A |. C1EA 08 |shr edx, 8
0040125D |. C0EE 07 |shr dh, 7
00401260 |. 66:C1EA 05 |shr dx, 5
00401264 |. 8BFA |mov edi, edx
00401266 |. 33FE |xor edi, esi
00401268 |. 8BD7 |mov edx, edi
0040126A |. 81E2 FF000000 |and edx, 0FF
00401270 |. 51 |push ecx
00401271 |. 52 |push edx
00401272 |. BA 08000000 |mov edx, 8
00401277 |. 91 |xchg eax, ecx
00401278 |. 83F8 03 |cmp eax, 3
0040127B |. 7F 0F |jg short 0040128C
0040127D |. F6E2 |mul dl
0040127F |. 5A |pop edx
00401280 |. 83C0 08 |add eax, 8
00401283 |. 91 |xchg eax, ecx
00401284 |. D3C0 |rol eax, cl
00401286 |. 33C2 |xor eax, edx
00401288 |. D3C8 |ror eax, cl
0040128A |. EB 0D |jmp short 00401299
0040128C |> 83E8 03 |sub eax, 3
0040128F |. F6E2 |mul dl
00401291 |. 5A |pop edx
00401292 |. 91 |xchg eax, ecx
00401293 |. D3C3 |rol ebx, cl
00401295 |. 33DA |xor ebx, edx
00401297 |. D3CB |ror ebx, cl
00401299 |> 59 |pop ecx
0040129A |. 41 |inc ecx
0040129B |. 83F9 08 |cmp ecx, 8
0040129E |.^ 0F85 71FFFFFF \jnz 00401215
004012A4 \. C3 retn
这个函数主要是通过一系列算法,生成新的dwName[0]和dwName[1]。
以上汇编代码改成c语言代码为:
void function4011F1()
{
dwName[0] ^= dwCode[0];
dwName[1] ^= dwCode[1];
dwName[0] &= 0x7f3f1f0f;
dwName[1] &= 0x07030100;
for (int i=0; i<8; i++)
{
DWORD name0 = dwName[0];
DWORD name1 = dwName[1];
name0 <<= i;
name1 <<= i;
name0 &= 0x80808080;
name1 &= 0x80808080;
DWORD temp1 = name0;
BYTE dh;
WORD dx;
for (int j=0; j<2; j++)
{
dh = (temp1 >> 8) & 0XFF;
dh >>= 7;
temp1 &= 0xffff00ff;
temp1 |= (dh << 8);
dx = temp1 & 0xffff;
dx <<= 7;
temp1 &= 0xffff0000;
temp1 |= dx;
temp1 >>= 8;
}
dh = (temp1 >> 8) & 0XFF;
dh >>= 7;
temp1 &= 0xffff00ff;
temp1 |= (dh << 8);
dx = temp1 & 0xffff;
dx >>= 1;
temp1 &= 0xffff0000;
temp1 |= dx;
name0 = temp1;
temp1 = name1;
for (j=0; j<2; j++)
{
dh = (temp1 >> 8) & 0XFF;
dh >>= 7;
temp1 &= 0xffff00ff;
temp1 |= (dh << 8);
dx = temp1 & 0xffff;
dx <<= 7;
temp1 &= 0xffff0000;
temp1 |= dx;
temp1 >>= 8;
}
dh = (temp1 >> 8) & 0XFF;
dh >>= 7;
temp1 &= 0xffff00ff;
temp1 |= (dh << 8);
dx = temp1 & 0xffff;
dx >>= 5;
temp1 &= 0xffff0000;
temp1 |= dx;
name1 = temp1;
name1 ^= name0;
DWORD edx = name1 & 0xff;
int k = i;
if (k <= 3)
{
k *= 8;
k += 8;
unsigned int hi = dwName[0]>>(32-k);
dwName[0] <<= k;
dwName[0] |= hi;
dwName[0] ^= edx;
hi = dwName[0]<<(32-k);
dwName[0] >>= k;
dwName[0] |= hi;
}
else
{
k -= 3;
k *= 8;
unsigned int hi = dwName[1]>>(32-k);
dwName[1] <<= k;
dwName[1] |= hi;
dwName[1] ^= edx;
hi = dwName[1]<<(32-k);
dwName[1] >>= k;
dwName[1] |= hi;
}
}
}
00401190 /$ 5F pop edi
00401191 |. 59 pop ecx
00401192 |. 57 push edi
00401193 |. 81F9 80000000 cmp ecx, 80
00401199 |. 7E 55 jle short 004011F0
0040119B |. 51 push ecx
0040119C |. 8BF1 mov esi, ecx
0040119E |. 81E1 FF000000 and ecx, 0FF
004011A4 |. 8BF8 mov edi, eax
004011A6 |. 83F9 08 cmp ecx, 8
004011A9 |. 7E 05 jle short 004011B0
004011AB |. 8BFB mov edi, ebx
004011AD |. C1E9 04 shr ecx, 4
004011B0 |> C1C7 08 /rol edi, 8
004011B3 |. D1E9 |shr ecx, 1
004011B5 |.^ 75 F9 \jnz short 004011B0
004011B7 |. C1EE 08 shr esi, 8
004011BA |. 23FE and edi, esi
004011BC |. 81E7 FF000000 and edi, 0FF
004011C2 |. 59 pop ecx
004011C3 |> BE 80000000 mov esi, 80
004011C8 |> 85FE /test esi, edi
004011CA |. 74 20 |je short 004011EC
004011CC |. 33FE |xor edi, esi
004011CE |. 57 |push edi
004011CF |. 81E1 00FF0000 |and ecx, 0FF00
004011D5 |. 87CE |xchg esi, ecx
004011D7 |. 32E9 |xor ch, cl
004011D9 |. 33F1 |xor esi, ecx
004011DB |. 87F1 |xchg ecx, esi
004011DD |. 51 |push ecx
004011DE |. FF05 82214000 |inc dword ptr [402182]
004011E4 |. E8 A7FFFFFF |call 00401190
004011E9 |. 5F |pop edi
004011EA |.^ EB D7 |jmp short 004011C3
004011EC |> D1EE |shr esi, 1
004011EE |.^ 75 D8 \jnz short 004011C8
004011F0 \> C3 retn
这个函数主要是产生count_402182供后面运算,同时ecx必须为1。
以上汇编代码改成c语言代码为:
unsigned int count_402182 = 0xFEDCBA98;
unsigned int function401190(unsigned int ecx)
{
if (ecx <= 0x80)
return ecx;
unsigned int saveecx = ecx;
unsigned int esi = ecx;
ecx &= 0xff;
unsigned int edi = dwName[0];
if (ecx > 8)
{
edi = dwName[1];
ecx >>= 4;
}
while (ecx != 0)
{
unsigned int hi = edi>>24;
edi <<= 8;
edi |= hi;
ecx >>= 1;
}
esi >>= 8;
edi &= esi;
edi &= 0xff;
ecx = saveecx;
esi = 0x80;
while(1)
{
int ret = esi & edi;
if (ret == 0)
{
esi >>= 1;
if (esi == 0)
return ecx;
else
continue;
}
edi ^= esi;
unsigned int saveedi = edi;
ecx &= 0xff00;
unsigned char esi_h = (esi >> 8) & 0xff;
unsigned char esi_l = (esi ) & 0xff;
esi_h ^= esi_l;
esi = (esi & 0xffff00ff ) | (esi_h<<8);
ecx ^= esi;
count_402182++;
ecx = function401190(ecx);
edi = saveedi;
esi = 0x80;
}
return ecx;
}
从上面的代码可以看到,我们可以固定dwCode[0],找到一个使ecx=1的dwCode[1]。
同样也可以固定dwCode[2],找到满足条件的dwCode[3],从而得到16字节的序列号。
计算序列号代码为:
void PrintCode(unsigned int dwCode)
{
int i;
for(i=0; i<4; i++)
{
printf("%c", dwCode&0xff);
dwCode >>= 8;
}
}
void GetCode(unsigned int nName2, unsigned int nName3)
{
unsigned int dwCode2;
char *pCode2 = "1234";
dwCode2 = *((unsigned int *)pCode2);
unsigned int eax = nName2 ^ nName3;
eax ^= count_402182;
eax |= 0x40404040;
eax &= 0x77777777;
eax ^= dwCode2;
printf("%s", pCode2);
PrintCode(eax);
printf("\n");
}
void GetSeiralNumber(char *pName)
{
char name[32];
memset(name, 0, sizeof(name));
int nLen = strlen(pName);
if (nLen > 16)
nLen = 16;
//填充为16 byte
strcpy(name, pName);
for (int i=0; i<16-nLen; i++)
{
name[nLen+i] = name[i];
}
dwCode[0] = 0x30303030;
int k1,k2,k3,k4;
for(k1=0x30; k1<=0x7e; k1++)
{
unsigned int code1 = (k1<<24);
for(k2=0x30; k2<=0x7e; k2++)
{
unsigned int code2 = (k1<<16);
for(k3=0x30; k3<=0x7e; k3++)
{
unsigned int code3 = (k1<<8);
for(k4=0x30; k4<=0x7e; k4++)
{
dwCode[1] = code1 | code2 | code3 | k4;;
count_402182 = 0xFEDCBA98;
dwName[0] = *((DWORD *)name);
dwName[1] = *((DWORD *)&name[4]);
dwName[2] = *((DWORD *)&name[8]);
dwName[3] = *((DWORD *)&name[12]);
function4011F1();
unsigned int ecx = 0xff01;
ecx = function401190(ecx);
if (ecx == 1)
{
printf("serial num:");
PrintCode(dwCode[0]);
PrintCode(dwCode[1]);
GetCode(dwName[2] , dwName[3]);
return;
}
}
}
}
}
}
int main(int argc, char* argv[])
{
char name[128];
printf("input name:\n");
scanf("%s", name);
GetSeiralNumber(name);
getchar();
return 0;
}
给出一组序列号:
name = "afeiwangafeiwang";
code = "000000001234UGdD";
- 标 题:CycleCrack注册机
- 作 者:szwyf
- 时 间:2009-05-06 20:44
- 链 接:http://bbs.pediy.com/showthread.php?t=88139