本帖最后由 菜鸟中的菜鸟 于 2016-6-26 21:34 编辑
004010D0 |. B9 08000000 mov ecx,0x8
004010D5 |. BE 44304000 mov esi,Pusillus.00403044
004010DA |> 8036 32 /xor byte ptr ds:[esi],0x32
004010DD |. 46 |inc esi ; Pusillus.00403044
004010DE |.^ E2 FA \loopd short Pusillus.004010DA
把每个字符与0x32进行异或,循环次数为8
004010EA |> /8A06 /mov al,byte ptr ds:[esi]
004010EC |. |8A5E 01 |mov bl,byte ptr ds:[esi+0x1]
004010EF |. |32C3 |xor al,bl
004010F1 |. |8887 4C304000 |mov byte ptr ds:[edi+0x40304C],al
004010F7 |. |83C6 02 |add esi,0x2
004010FA |. |47 |inc edi
004010FB |.^\E2 ED \loopd short Pusillus.004010EA
取出相邻的两个字符进行异或,保存异或结果到0x40304C,循环次数为4
00401102 |. 8A06 mov al,byte ptr ds:[esi]
00401104 |. 8A5E 01 mov bl,byte ptr ds:[esi+0x1]
00401107 |. 32C3 xor al,bl
00401109 |. 8A5E 02 mov bl,byte ptr ds:[esi+0x2]
0040110C |. 8A4E 03 mov cl,byte ptr ds:[esi+0x3]
0040110F |. 32D9 xor bl,cl
00401111 |. 32C3 xor al,bl
把上一步计算出的四个字节进行异或,得到一个字节
00401113 |. B9 08000000 mov ecx,0x8
00401118 |. BE 44304000 mov esi,Pusillus.00403044
0040111D |> 3006 /xor byte ptr ds:[esi],al
0040111F |. 46 |inc esi ; Pusillus.00403044
00401120 |.^ E2 FB \loopd short Pusillus.0040111D
把code的每个字符与上一步计算出一个字节进行异或
00401122 |. B9 08000000 mov ecx,0x8
00401127 |. BE 44304000 mov esi,Pusillus.00403044
0040112C |. BF 08304000 mov edi,Pusillus.00403008
00401131 |> 8A06 /mov al,byte ptr ds:[esi]
00401133 |. 3A07 |cmp al,byte ptr ds:[edi]
00401135 |. 75 1D |jnz short Pusillus.00401154
00401137 |. 46 |inc esi ; Pusillus.00403044
00401138 |. 47 |inc edi ; Pusillus.00403008
00401139 |.^ E2 F6 \loopd short Pusillus.00401131
把处理后的code的每个字节与00403008起始的每个字节进行比较,全部相等则通过校验
00403008起始的每个字节内容如下:
00403008 1B591871 qY
0040300C 4C454279 yBEL
整个校验过程非常清楚,但是要从00403008起始的8个字节算出正确的注册码却要花一番心思。
作者在这里巧妙的利用大量的异或运算,异或运算最重要的就是交换律和结合律,以及a^a=0,a^0=a这四个性质
下面是keygen代码:
int main(int argc, char* argv[])
{
unsigned int i;
char szName[32] = { 0x71, 0x18, 0x59, 0x1B, 0x79, 0x42, 0x45, 0x4C,0x00 };//对应从00403008起始的8个字节
char szSerial[32] = { 0 };
unsigned char byResult=0;
for (i = 0; i < 8; i++)
{
byResult ^= szName;
}
for (i = 0; i < 8; i++)
{
szSerial = szName ^ byResult;
}
for (i = 0; i < 8; i++)
{
szSerial = szSerial ^ 0x32;
}
printf("Serial:%s\r\n", szSerial);
return 0;
} 正确的注册码是:Z3r0Ring
---------------------------------------------------------------------------------------------------
这是以上有别人分析出来的,在没看别人分析的文章前,也把算法分析了一下,也明白是怎么一回事,但是就感觉不太可能存在这样的注册码,
之后看了别人的分析,和别人的分析过程是一样的,就是不知道如何写注册机,这里说的不会写注册机,不是说,不会用C语言来
写,而是说,怎么写这个注册机,思路是什么,是思路的问题,而不是某种语言的语法实现,是感觉逻辑上行不通,不会存在这样的注册码能满足注册成功。
当输入一个序列号时,每个字符都^0x32后,再^这个序列号内部某种运算后的一个值,结果等于
char szName[32] = { 0x71, 0x18, 0x59, 0x1B, 0x79, 0x42, 0x45, 0x4C,0x00 }; 可能存在这种正确的序列号吗?
当在什么情况下,才会出现这种情况,,,想不明白。作者给出了a^a=0,a^0=a,这种解决方法,但是就是想不通,。。。。
所以想请高手给指点,卡在这里就是想不明白了。。上传下这个crackme.
Pusillus.zip
(1.32 KB, 下载次数: 64)
|