某Crackme算法分析的问题
本帖最后由 菜鸟中的菜鸟 于 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:,0x32
004010DD|.46 |inc esi ;Pusillus.00403044
004010DE|.^ E2 FA \loopd short Pusillus.004010DA
把每个字符与0x32进行异或,循环次数为8
004010EA|> /8A06 /mov al,byte ptr ds:
004010EC|. |8A5E 01 |mov bl,byte ptr ds:
004010EF|. |32C3 |xor al,bl
004010F1|. |8887 4C304000 |mov byte ptr ds:,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:
00401104|.8A5E 01 mov bl,byte ptr ds:
00401107|.32C3 xor al,bl
00401109|.8A5E 02 mov bl,byte ptr ds:
0040110C|.8A4E 03 mov cl,byte ptr ds:
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:,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:
00401133|.3A07 |cmp al,byte ptr ds:
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起始的每个字节内容如下:
004030081B591871qY
0040300C4C454279yBEL
整个校验过程非常清楚,但是要从00403008起始的8个字节算出正确的注册码却要花一番心思。
作者在这里巧妙的利用大量的异或运算,异或运算最重要的就是交换律和结合律,以及a^a=0,a^0=a这四个性质
下面是keygen代码:
int main(int argc, char* argv[])
{
unsigned int i;
char szName = { 0x71, 0x18, 0x59, 0x1B, 0x79, 0x42, 0x45, 0x4C,0x00 };//对应从00403008起始的8个字节
char szSerial = { 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 = { 0x71, 0x18, 0x59, 0x1B, 0x79, 0x42, 0x45, 0x4C,0x00 }; 可能存在这种正确的序列号吗?
当在什么情况下,才会出现这种情况,,,想不明白。作者给出了a^a=0,a^0=a,这种解决方法,但是就是想不通,。。。。
所以想请高手给指点,卡在这里就是想不明白了。。上传下这个crackme.
本帖最后由 梦游枪手 于 2016-6-27 00:13 编辑
这个CM思路很绕,不理解很正常,因为这篇文章讲的不够详细。看下分析:
CM先把长度为8的code和0x32逐字节进行异或,然后运算一个字节p,我们先来分析一下算出p的过程。
p=[(1xor2)xor (3xor4)]xor [(5xor6)xor (7xor8)]
1=code xor 32h,2=code xor 32h,其他同理。
根据异或的结合律和交换律,可以看出来,这个字节其实就是1xor2xor3xor4xor...
然后就是x xor p的部分了,我把存放00403008的字节集记为s,以1为例子:
s=1 xor p
那现在要怎么得到code呢?
我们先整理下得到code的思路:
我们从上面可以得到
s=1 xor p
s=2 xor p
...
s=x xor p
根据异或运算的可逆性,x=s xor p
code=x xor 32
那p又要怎么得到?
从前面可以知道,p是code所有字节异或后的结果。
而s=x xor p
举两个例子
s=1 xor p
s=2 xor p 根据a xor a=0,我们可以得到
s xor s=1 xor 2而1 xor 2=(code xor 32h) xor (code xor 32h)
=(code xor code) xor (32h xor 32h)
=code xor code
以此类推,可以得出p是s所有字节异或后的结果。
而s是存放00403008的字节集,也就是已知了。
所以得到code的算法就是:
p=s xor s xor...
t=s xor p
code=t xor 32h
也就是文章中注册机的代码。最后一句是为了让字节处于字符串代码值的区间,也是CM作者设计好了的。
口误多,请见谅。
最后膜拜下写出这个CM的人{:6_197:}
{:5_188:}解密专家都求助了 小白就看着 退隐猫九_ 发表于 2016-6-26 21:36
解密专家都求助了 小白就看着
专家?我只是打酱油的菜鸟而已。 异或是可逆的
A^B=C -> A^C=B B^C=A
页:
[1]