-
-
[旧帖] [原创]对于07金山软件逆向竞赛第一题的趣味解读 0.00雪花
-
发表于: 2014-3-2 11:43 1082
-
实验用户名为"abcde"
算法命名为"灭灯"问题
注:本文章计算以十进制表现
1、用户名计算一个关键数X:
初始A=13572468,B=3721273,C=24681357。
for(i=0;i<n;i++) //n为用户名字符数
{
A=
[(A+'第i个字符ascii')*3721273+2468135]*2^19 or
[(A+'第i个字符ascii')*3721273+2468135]/(2^7)
}
X=A
实验用户名最后所得X=A6962344
2、关键数获得要灭的灯的位置
for(i=0;i<9;i++)
{
X/[2^(i+1)]---->取al,al and 1--->[12EAB5+i]
//将运算结果放入12EAB5-12EABF中
//实验用户名的结果为00 01 00 00 00 01 00 01 01
}
3、注册码的生产和比较
00400383 |> /8B45 0C /MOV EAX,DWORD PTR SS:[EBP+C]
00400386 |. |8A0407 |MOV AL,BYTE PTR DS:[EDI+EAX]
00400389 |. |3C 30 |CMP AL,30
0040038B |. |8845 FF |MOV BYTE PTR SS:[EBP-1],AL
0040038E |. |0F8C 97000000 |JL CrackMe.0040042B
00400394 |. |3C 39 |CMP AL,39
00400396 |. |0F8F 8F000000 |JG CrackMe.0040042B
0040039C |. |8BC7 |MOV EAX,EDI
0040039E |. |6A 1F |PUSH 1F
004003A0 |. |99 |CDQ
004003A1 |. |59 |POP ECX
004003A2 |. |F7F9 |IDIV ECX
004003A4 |. |8B45 08 |MOV EAX,DWORD PTR SS:[EBP+8]
004003A7 |. |6A 0A |PUSH 0A
004003A9 |. |8BCA |MOV ECX,EDX
004003AB |. |33D2 |XOR EDX,EDX
004003AD |. |D3E8 |SHR EAX,CL
004003AF |. |59 |POP ECX
004003B0 |. |F7F1 |DIV ECX
004003B2 |. |0FBE45 FF |MOVSX EAX,BYTE PTR SS:[EBP-1]
004003B6 |. |8D4402 D0 |LEA EAX,DWORD PTR DS:[EDX+EAX-30]
004003BA |. |33D2 |XOR EDX,EDX
004003BC |. |F7F1 |DIV ECX
004003BE |. |3BD3 |CMP EDX,EBX
004003C0 |. |75 05 |JNZ SHORT CrackMe.004003C7
004003C2 |. |305D DD |XOR BYTE PTR SS:[EBP-23],BL
004003C5 |. |EB 22 |JMP SHORT CrackMe.004003E9
004003C7 |> |385C15 DB |CMP BYTE PTR SS:[EBP+EDX-25],BL
004003CB |. |75 5E |JNZ SHORT CrackMe.0040042B
004003CD |. |8D42 FE |LEA EAX,DWORD PTR DS:[EDX-2]
004003D0 |. |8BCB |MOV ECX,EBX
004003D2 |. |3BC3 |CMP EAX,EBX
004003D4 |. |7C 0B |JL SHORT CrackMe.004003E1
004003D6 |> |385C0D DC |/CMP BYTE PTR SS:[EBP+ECX-24],BL
004003DA |. |74 4F ||JE SHORT CrackMe.0040042B
004003DC |. |41 ||INC ECX
004003DD |. |3BC8 ||CMP ECX,EAX
004003DF |.^|7E F5 |\JLE SHORT CrackMe.004003D6
004003E1 |> |305C15 DC |XOR BYTE PTR SS:[EBP+EDX-24],BL
004003E5 |. |8D4415 DC |LEA EAX,DWORD PTR SS:[EBP+EDX-24]
004003E9 |> |47 |INC EDI
004003EA |. |3BFE |CMP EDI,ESI
004003EC |.^\7C 95 \JL SHORT CrackMe.00400383
进入最后一个关键call后我们在前面看到程序写入了一堆乱码,经过假码的尝试我们还看到了最后输出的Fail!是和这堆乱码有关的,由此可以判断出那个判断最终输出的循环。那
个循环不就是在判断我们上一个步骤生成的12EAB5-12EABF的值是否全部为0,如果有一个不为0则Fail!。
好了,知道关键点我们就来着眼于注册码(必须为数字)参与的运算循环:
for(i=0;i<?;i++)
{
X/[10*2^(i+1)]--->取余数为Y+'第i个注册码'的值---->/10取余数放入EDX //关于Y的解释在下面的注释中
if(EDX==1)
{
[12EAB5] xor 1; //这个操作即是改变[12EAB5]的值(0或1)
}
if(EDX==2)
{
如果[12EAB5]=1则[12EAB6] xor 1如果[12EAB5]=0,则fail;
}
if(EDX>2)
{
如果[12EAB5+EDX-2]=1,并且12EAB5+EDX-2之前地址中存放的数据全为0则[12EAB5+EDX-1] xor 1;
}
}
注:经过一定的实验之后会发现Y的值是一个32位数的循环,也就是说是一个32位的常数在不断的循环,我们的注册码就是根据这个循环和EDX要求的值来得出的。
附上实验用户名所得到的的32位数循环:42100052152689426310526363100524
我们仔细分析一下,结合注册码成功的要求我们能得出程序在干什么,首先看12EAB5-12EABF中保存的数据00 01 00 00 00 01 00 01 01 ,我们可以把01看做灯亮,把00看做灯灭
,游戏的目的是把这段数据全部改为0(灭掉所有的灯),游戏规则是想要灭掉标号为0-9的灯,第0盏灯的开关是EDX=1,第1盏灯开关的条件是第0盏灯是亮着的,第2-9盏灯开关的条件是前一盏
灯亮着,并且前一盏之前的灯全灭吗,一旦操作不满足条件就game over,回家找妈妈 TAT~~
待我灵光一闪(其实已经想了10分钟。。。),这个算法好像似曾相识,貌似在C语言课堂上睡觉时候被老师叫起来回答的那个坑爹问题有点像,这个问题不就是汉诺塔问题的翻版吗!
!!一层层的递归:想要灭掉一盏灯的必须开左边的灯,灭掉之前的灯,想要开左边的灯必须先开左左边的灯而且灭掉之前的灯,满足条件后灭掉这盏灯,然后再依次灭掉左边、左左边...的
灯,。相类似的汉诺塔问题:想要移动N个盘从A到C,得先移动N-1个盘从A到B,在移动最低(大)的盘到C,最后在移动N-1个盘到从B到C。
如果熟悉递归或者汉诺塔的朋友应该知道这个算法的奥妙了,最终我们的到的注册码数量是比较长的,想写注册机没头绪的可以去了解下递归~~
本人实属论坛新人,以上皆为本人意见,如果有出错的地方还请指出。
附上程序链接:http://http://bbs.pediy.com/showthread.php?t=50203
注册机地址:http://http://www.pediy.com/kssd/pediy09/pediy09-248/350243/crackmeonly-release.rar
算法命名为"灭灯"问题
注:本文章计算以十进制表现
1、用户名计算一个关键数X:
初始A=13572468,B=3721273,C=24681357。
for(i=0;i<n;i++) //n为用户名字符数
{
A=
[(A+'第i个字符ascii')*3721273+2468135]*2^19 or
[(A+'第i个字符ascii')*3721273+2468135]/(2^7)
}
X=A
实验用户名最后所得X=A6962344
2、关键数获得要灭的灯的位置
for(i=0;i<9;i++)
{
X/[2^(i+1)]---->取al,al and 1--->[12EAB5+i]
//将运算结果放入12EAB5-12EABF中
//实验用户名的结果为00 01 00 00 00 01 00 01 01
}
3、注册码的生产和比较
00400383 |> /8B45 0C /MOV EAX,DWORD PTR SS:[EBP+C]
00400386 |. |8A0407 |MOV AL,BYTE PTR DS:[EDI+EAX]
00400389 |. |3C 30 |CMP AL,30
0040038B |. |8845 FF |MOV BYTE PTR SS:[EBP-1],AL
0040038E |. |0F8C 97000000 |JL CrackMe.0040042B
00400394 |. |3C 39 |CMP AL,39
00400396 |. |0F8F 8F000000 |JG CrackMe.0040042B
0040039C |. |8BC7 |MOV EAX,EDI
0040039E |. |6A 1F |PUSH 1F
004003A0 |. |99 |CDQ
004003A1 |. |59 |POP ECX
004003A2 |. |F7F9 |IDIV ECX
004003A4 |. |8B45 08 |MOV EAX,DWORD PTR SS:[EBP+8]
004003A7 |. |6A 0A |PUSH 0A
004003A9 |. |8BCA |MOV ECX,EDX
004003AB |. |33D2 |XOR EDX,EDX
004003AD |. |D3E8 |SHR EAX,CL
004003AF |. |59 |POP ECX
004003B0 |. |F7F1 |DIV ECX
004003B2 |. |0FBE45 FF |MOVSX EAX,BYTE PTR SS:[EBP-1]
004003B6 |. |8D4402 D0 |LEA EAX,DWORD PTR DS:[EDX+EAX-30]
004003BA |. |33D2 |XOR EDX,EDX
004003BC |. |F7F1 |DIV ECX
004003BE |. |3BD3 |CMP EDX,EBX
004003C0 |. |75 05 |JNZ SHORT CrackMe.004003C7
004003C2 |. |305D DD |XOR BYTE PTR SS:[EBP-23],BL
004003C5 |. |EB 22 |JMP SHORT CrackMe.004003E9
004003C7 |> |385C15 DB |CMP BYTE PTR SS:[EBP+EDX-25],BL
004003CB |. |75 5E |JNZ SHORT CrackMe.0040042B
004003CD |. |8D42 FE |LEA EAX,DWORD PTR DS:[EDX-2]
004003D0 |. |8BCB |MOV ECX,EBX
004003D2 |. |3BC3 |CMP EAX,EBX
004003D4 |. |7C 0B |JL SHORT CrackMe.004003E1
004003D6 |> |385C0D DC |/CMP BYTE PTR SS:[EBP+ECX-24],BL
004003DA |. |74 4F ||JE SHORT CrackMe.0040042B
004003DC |. |41 ||INC ECX
004003DD |. |3BC8 ||CMP ECX,EAX
004003DF |.^|7E F5 |\JLE SHORT CrackMe.004003D6
004003E1 |> |305C15 DC |XOR BYTE PTR SS:[EBP+EDX-24],BL
004003E5 |. |8D4415 DC |LEA EAX,DWORD PTR SS:[EBP+EDX-24]
004003E9 |> |47 |INC EDI
004003EA |. |3BFE |CMP EDI,ESI
004003EC |.^\7C 95 \JL SHORT CrackMe.00400383
进入最后一个关键call后我们在前面看到程序写入了一堆乱码,经过假码的尝试我们还看到了最后输出的Fail!是和这堆乱码有关的,由此可以判断出那个判断最终输出的循环。那
个循环不就是在判断我们上一个步骤生成的12EAB5-12EABF的值是否全部为0,如果有一个不为0则Fail!。
好了,知道关键点我们就来着眼于注册码(必须为数字)参与的运算循环:
for(i=0;i<?;i++)
{
X/[10*2^(i+1)]--->取余数为Y+'第i个注册码'的值---->/10取余数放入EDX //关于Y的解释在下面的注释中
if(EDX==1)
{
[12EAB5] xor 1; //这个操作即是改变[12EAB5]的值(0或1)
}
if(EDX==2)
{
如果[12EAB5]=1则[12EAB6] xor 1如果[12EAB5]=0,则fail;
}
if(EDX>2)
{
如果[12EAB5+EDX-2]=1,并且12EAB5+EDX-2之前地址中存放的数据全为0则[12EAB5+EDX-1] xor 1;
}
}
注:经过一定的实验之后会发现Y的值是一个32位数的循环,也就是说是一个32位的常数在不断的循环,我们的注册码就是根据这个循环和EDX要求的值来得出的。
附上实验用户名所得到的的32位数循环:42100052152689426310526363100524
我们仔细分析一下,结合注册码成功的要求我们能得出程序在干什么,首先看12EAB5-12EABF中保存的数据00 01 00 00 00 01 00 01 01 ,我们可以把01看做灯亮,把00看做灯灭
,游戏的目的是把这段数据全部改为0(灭掉所有的灯),游戏规则是想要灭掉标号为0-9的灯,第0盏灯的开关是EDX=1,第1盏灯开关的条件是第0盏灯是亮着的,第2-9盏灯开关的条件是前一盏
灯亮着,并且前一盏之前的灯全灭吗,一旦操作不满足条件就game over,回家找妈妈 TAT~~
待我灵光一闪(其实已经想了10分钟。。。),这个算法好像似曾相识,貌似在C语言课堂上睡觉时候被老师叫起来回答的那个坑爹问题有点像,这个问题不就是汉诺塔问题的翻版吗!
!!一层层的递归:想要灭掉一盏灯的必须开左边的灯,灭掉之前的灯,想要开左边的灯必须先开左左边的灯而且灭掉之前的灯,满足条件后灭掉这盏灯,然后再依次灭掉左边、左左边...的
灯,。相类似的汉诺塔问题:想要移动N个盘从A到C,得先移动N-1个盘从A到B,在移动最低(大)的盘到C,最后在移动N-1个盘到从B到C。
如果熟悉递归或者汉诺塔的朋友应该知道这个算法的奥妙了,最终我们的到的注册码数量是比较长的,想写注册机没头绪的可以去了解下递归~~
本人实属论坛新人,以上皆为本人意见,如果有出错的地方还请指出。
附上程序链接:http://http://bbs.pediy.com/showthread.php?t=50203
注册机地址:http://http://www.pediy.com/kssd/pediy09/pediy09-248/350243/crackmeonly-release.rar
赞赏
赞赏
雪币:
留言: