莫拉克crackme的注册机
又到中秋。岁岁年年人不同。。。。。。
好像没见人写过这个的注册机,似乎这个crackme现在也没人玩了,炒个冷饭。高手都懒的写文章,
抛个砖,等大家的指点。
1、crackme算法分析
虽有海风和spark的源码,不过算法还是没看懂。只是简单拆分和猜测一下。
1.1 name经过变换得到4个DWORD. name=>hash[1..4]。
1.2 keystr(共48个字符)经过字符转hex, keystr=>ddd[0..5];
1.3
如果
1)Crc32((BYTE*)(&ddd[0]),24)=0x0;//事实上,可以设定为任何值,均有解。但为0的话,最简单。
则在同时满足以下几个条件后(用类c代码表示),可以注册成功
1)f0(*(float*)&ddd[0])==*(float *)(&hash[1]);
2)f1(*(float*)&ddd[1])==*(float *)(&hash[2]);
3)f2(*(float*)&ddd[2])==*(float *)(&hash[3]);
4)f3((WORD*)&ddd[4],4)==*(float *)(&hash[4]);
f0,f1,f2,f3分别为4个函数。crc32为crc32校验算法。
大致拆分出来的几个算法近似如下(未验证)
float f0(float x1)
{
y1 = 0.0;
x0 = 1.0;
x4 = x1;
for(i = 1; i <100000; i++)
{
sign = (x4 < 0);
x4 = fabs(x4);
n = (int) ((x4 * INVSPI) + 0.5);
xn = (float) n;
sign ^= n % 2;
f = (x4 - xn * C1) - xn * C2;
g = f * f;
rg = (((R4 * g + R3) * g + R2) * g + R1) * g;
result = f + f * rg;
result = sign ? -result : result;
y1 += result / i;
x4 += x1;
}
return y1;
}
float f1(float x2)
{
x0 = 1.0;
y2 = x0;
for(i = 1; i <100000; i++)
{
x0 =x0* x2;
y2 = y2+x0;
}
return y2;
}
float f2(float x3)
{
x0 = 1.0;
y3 = 0.0;
x4 = x1;
for(i = 1; i < 8000; i++)
{
x4 = (x4 > 0)?(x4):(-x4);
n = (int) (((x4 + HALFPI) * INVSPI) + 0.5);
xn = (float)n - 0.5;
sign = n % 2;
f = (x4 - xn * C1) - xn * C2;
g = f * f;
rg = (((R4 * g + R3) * g + R2) * g + R1) * g;
result = f + f * rg;
result = sign ? -result : result;
y3 += x0 * result / (i * i);
x0 = -x0;
x4 += x1;
}
y3 = y3 * 4 + PI * PI / 3 * 2;
return y3;
}
DWORD f3((WORD *)d,int len)
{
k = 0;
lpData = (BYTE*)&k;
d = (WORD*)&ddd[4];
for(i = 0; i < len; i++)
{
B = (int)d[i];
if(B >= MCU_CODE)
{
B = (B * 2) & 0xFFFF;
C = B + 1;
}
else
C = B + 2;
rem = 0;
root = 0;
divisor = 0;
a = C * C - B * B;
for(j = 0; j < 16; j++)
{
root <<= 1;
rem = ((rem << 2) + (a >> 30));
a <<= 2;
divisor = (root << 1) + 1;
if(divisor <= rem)
{
rem -= divisor;
root ++;
}
}
lpData[i] = (unsigned char)(root - 3);
}
return k;
}
DWORD Crc32(BYTE *lpData,int len)
{
for( i = 0; i < 256; i ++ )
{
crc32 = i;
for( j = 0; j < 8; j ++ )
{
if(crc32 & 1)
crc32 = (crc32 >> 1) ^ 0xEDB88320UL;
else
crc32 >>= 1;
}
crcTable[i] = crc32;
}
crc32 = ~hash4;
for(i = 0; i < len; i ++)
{
crc32 = (crc32 >> 8) ^ crcTable[ (crc32 ^ lpData[i]) & 0xFF ];
}
}
crc32 = ~crc32;
return crc32;
}
2.获得注册码
这要先膜拜一下老婆,如果不是她指点我逼近法和crc可逆破解,我还在穷举的苦海里挣扎。
2.1 获得ddd[0]
使用2分法逼近
float x1_0=-4.72;
float x1_1=-1.57;
x1=x1_0;
do
{
y1 = 0.0;
x0 = 1.0;
x1=(x1_0+x1_1)/2;
x4 = x1;
for(i = 1; i <100000; i++)
{
sign = (x4 < 0);
x4 = fabs(x4);
n = (int) ((x4 * INVSPI) + 0.5);
//xn = (double) n;
xn = (float) n;
sign ^= n % 2;
f = (x4 - xn * C1) - xn * C2;
g = f * f;
rg = (((R4 * g + R3) * g + R2) * g + R1) * g;
result = f + f * rg;
result = sign ? -result : result;
y1 += result / i;
x4 += x1;
}
if(y1>*(float*)&hash1)
x1_0=x1;
else
x1_1=x1;
}while(fabs(y1-*(float*)&hash1)>EPLISON);
2.2获得ddd[1]
//ddd[1]
float x2_0=-1.0;
float x2_1=1.0;
do
{
x0 = 1.0;
y2 = x0;
x2= (x2_0+x2_1)/2;
for(i = 1; i <100000; i++)
{
x0 =x0* x2;
y2 = y2+x0;
}
if(y2>*(float*)&hash2)
x2_1=x2;
else
x2_0=x2;
} while(fabs(y2-*(float*)&hash2)>EPLISON);
2.3获得ddd[2]
使用2分法逼近
x1_0=0.0;
x1_1=3.1415926;
x1=x1_0;
do
{
x0 = 1.0;
y3 = 0.0;
x1 =(x1_0+x1_1)/2;//
if(x1>x1_1)
break;
x4 = x1;
for(i = 1; i < 8000; i++)
{
x4 = (x4 > 0)?(x4):(-x4);
n = (int) (((x4 + HALFPI) * INVSPI) + 0.5);
//xn = (double)n - 0.5;
xn = (float)n - 0.5;
sign = n % 2;
f = (x4 - xn * C1) - xn * C2;
g = f * f;
rg = (((R4 * g + R3) * g + R2) * g + R1) * g;
result = f + f * rg;
result = sign ? -result : result;
y3 += x0 * result / (i * i);
x0 = -x0;
x4 += x1;
}
y3 = y3 * 4 + PI * PI / 3 * 2;
if(y3>*(float*)&hash3)
x1_0=x1;
else
x1_1=x1;
} while(fabs(y3-*x)>EPLISON);
2.4 求ddd[4]和ddd[5]
穷举,好在工作量不大,4个WORD,分别穷举。
lpData = (BYTE*)&k;
d = (WORD*)&ddd[4];
printf("ddd[4]:\t");
for(i = 0; i < 4; i++)
{
B=0x0000;
do
{
if(B >= MCU_CODE)
{
B = (B * 2) & 0xFFFF;
C = B + 1;
}
else
C = B + 2;
rem = 0;
root = 0;
divisor = 0;
a = C * C - B * B;
for(j = 0; j < 16; j++)
{
root <<= 1;
rem = ((rem << 2) + (a >> 30));
a <<= 2;
divisor = (root << 1) + 1;
if(divisor <= rem)
{
rem -= divisor;
root ++;
}
}
lpData[i] = (unsigned char)(root - 3);
B++;
}while(lpData[i]!=*((unsigned char *)&hash4+i));
B=B-1;
printf("%04x",B);
*((WORD*)&ddd[4]+i)=B;
}
printf("\n");
5.求ddd[3]
这个,我觉得是最难的,搞了2个晚上,硬着头皮把一篇crc破解的英文文章看完,才搞定。
//...get crcBefore
crc32 = ~hash4;
lpData =(BYTE *) &ddd[0];
for(tmpi = 0; tmpi < 12; tmpi ++)
{
crc32 = (crc32 >> 8) ^ crcTable[ (crc32 ^ lpData[tmpi]) & 0xFF ];
}
DWORD crcBefore=crc32;
//...get crcEnd
DWORD crcEnd;
int index=0;
*(DWORD *)(&Crc32_1[0])=0xFFFFFFFF;
for(tmpj=23;tmpj>=16;tmpj--)
{
//step1 find ct
for(tmpi=0;tmpi<256;tmpi++)
{
if(BYTE(crcTable[tmpi],3)==Crc32_1[3])
{
index=tmpi;
break;
}
}
if(index==256)
{
printf("Error!");
break;
}
//step2 cal crc32
Crc32_1[3]=Crc32_1[2]^BYTE(crcTable[index],2);
Crc32_1[2]=Crc32_1[1]^BYTE(crcTable[index],1);
Crc32_1[1]=Crc32_1[0]^BYTE(crcTable[index],0);
Crc32_1[0]=lpData[tmpj]^index;
}
crcEnd=*(DWORD *)(&Crc32_1[0]);
//...get ddd[3]
BYTE buffer[8];
*(DWORD *)(&buffer[0])=crcBefore;
*(DWORD *)(&buffer[4])=crcEnd;
for(tmpj=4;tmpj>0;tmpj--)
{
for(tmpi=0;tmpi<256;tmpi++)
{
if(BYTE(crcTable[tmpi],3)==buffer[tmpj+3])
{
index=tmpi;
break;
}
}
*(DWORD *)(&buffer[tmpj])^=crcTable[index];
*(DWORD *)(&buffer[tmpj-1])^=index;
}
ddd[3]=*(DWORD *)(&buffer[0]);
3.其它
f0,f1,f2,f3我没看懂是什么函数
不过,用它们的数据生成了几个图形,供参考。
总结:
1、学会了2分逼近法,真是爽,跳几次就能定位数据。
2、原来crc32是可逆的。
膜拜一下ccfer,fengyue,spark和老婆。顺祝大家中秋快乐。怎么fg好像失踪了?
参考CRC破解的文章:http://www.woodmann.com/fravia/crctut1.htm
[培训]二进制漏洞攻防(第3期);满10人开班;模糊测试与工具使用二次开发;网络协议漏洞挖掘;Linux内核漏洞挖掘与利用;AOSP漏洞挖掘与利用;代码审计。