菜鸟也破易语言--小子的CM3的算法分析和注册机
此文已在UnPack首发!
【文章标题】: 菜鸟也破易语言--小子的CM3的算法分析和注册机
【文章作者】: 狼孩
【编写语言】: 易语言
【破解工具】: OllyDbg.V1.10.Final.聆风听雨汉化第三版(请到到UnPack下载)
【操作平台】: 真正盗版的xp pro sp2
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
呵呵,小子的CM3也挂了几天了,没有高手肯出手(肯定是嫌简单),昨天论坛开了虚拟股市,我在上面賠了不少,想赚点U用用(不知这张烂文能否赚得几个UB来用用?),于是,这个苦力还是由我来做了(写破文是苦力吗?无数牛人从四面八方杀过来,然后说:你说呢?我..我一身冷汗…然后..没有然后了)。
小子的CM3链接如下:
7d8K9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4g2F1M7r3q4U0K9#2)9J5k6h3y4F1i4K6u0r3N6r3S2J5k6h3q4V1i4K6u0V1x3e0b7^5x3e0u0Q4x3X3b7I4i4K6u0V1x3g2)9J5k6h3S2@1L8h3H3`.
好,开工!
用PEiD查看,提示是Microsoft Visual C++ 6.0 [Overlay],查看EP 区段,发现有.ecode ,可以肯定,该cm是用易语言编译的。上网找找资料,发现maomaoma大牛在UnPack 发过一篇关于易语言程序的破解《易语言程序的一种破解思路》,链接如下:
87fK9s2c8@1M7q4)9K6b7g2)9J5c8W2)9J5c8Y4N6%4N6#2)9J5k6i4g2F1M7r3q4U0K9#2)9J5k6h3y4F1i4K6u0r3N6X3W2W2N6%4c8Z5M7X3g2S2k6q4)9J5k6i4m8Z5M7q4)9K6c8Y4c8A6k6q4)9K6c8o6p5I4x3K6R3&6i4K6t1$3K9r3W2Y4K9r3I4A6k6$3S2@1i4K6y4p5i4K6t1#2c8o6u0Q4x3U0g2p5y4#2)9J5y4f1b7K6i4K6t1#2c8f1k6Q4x3U0g2p5x3g2)9J5y4f1b7@1
maomaoma大牛说易语言要在.ecode区段下断点,呵呵,我就照搬了,感谢maomaoma大牛!
好,废话少说,拿刀开工。用OD载入,按F9运行,Alt+M调出内存空间,在.ecode区段按F2下断,.ecode区段如下:
Memory map, 项目 26
地址=0040C000
大小=00002000 (8192.)
属主=CrAckMe
00400000
区段=.ecode
类型=映像 01001002
访问=R
初始访问=RWE
然后输入用户名和注册码,我输入的是lang和1234,按确定,OD立刻断下,
0040CC44 55 PUSH EBP //断在这里,下面有很多垃圾代码,我就不分析了,直接看有注释的就行!
0040CC45 8BEC MOV EBP,ESP
0040CC47 81EC 40000000 SUB ESP,40
0040CC4D C745 FC 0000000>MOV DWORD PTR SS:[EBP-4],0
0040CC54 C745 F8 0000000>MOV DWORD PTR SS:[EBP-8],0
0040CC5B C745 F4 0000000>MOV DWORD PTR SS:[EBP-C],0
0040CC62 C745 F0 0000000>MOV DWORD PTR SS:[EBP-10],0
0040CC69 C745 EC 0000000>MOV DWORD PTR SS:[EBP-14],0
0040CC70 C745 E4 0000000>MOV DWORD PTR SS:[EBP-1C],0
0040CC77 C745 E8 0000000>MOV DWORD PTR SS:[EBP-18],0
0040CC7E C745 E0 0000000>MOV DWORD PTR SS:[EBP-20],0
0040CC85 C745 DC 0000000>MOV DWORD PTR SS:[EBP-24],0
0040CC8C 6A FF PUSH -1
0040CC8E 6A 08 PUSH 8
0040CC90 68 02000116 PUSH 16010002
0040CC95 68 01000152 PUSH 52010001
0040CC9A E8 A5030000 CALL CrAckMe.0040D044
0040CC9F 83C4 10 ADD ESP,10
0040CCA2 8945 D8 MOV DWORD PTR SS:[EBP-28],EAX
0040CCA5 8B45 D8 MOV EAX,DWORD PTR SS:[EBP-28]
0040CCA8 50 PUSH EAX
0040CCA9 8B5D FC MOV EBX,DWORD PTR SS:[EBP-4]
0040CCAC 85DB TEST EBX,EBX
0040CCAE 74 09 JE SHORT CrAckMe.0040CCB9
0040CCB0 53 PUSH EBX
0040CCB1 E8 82030000 CALL CrAckMe.0040D038
0040CCB6 83C4 04 ADD ESP,4
0040CCB9 58 POP EAX
0040CCBA 8945 FC MOV DWORD PTR SS:[EBP-4],EAX
0040CCBD 6A FF PUSH -1
0040CCBF 6A 08 PUSH 8
0040CCC1 68 1B000116 PUSH 1601001B
0040CCC6 68 01000152 PUSH 52010001
0040CCCB E8 74030000 CALL CrAckMe.0040D044
0040CCD0 83C4 10 ADD ESP,10
0040CCD3 8945 D8 MOV DWORD PTR SS:[EBP-28],EAX
0040CCD6 8B45 D8 MOV EAX,DWORD PTR SS:[EBP-28]
0040CCD9 50 PUSH EAX
0040CCDA 8B5D F8 MOV EBX,DWORD PTR SS:[EBP-8]
0040CCDD 85DB TEST EBX,EBX
0040CCDF 74 09 JE SHORT CrAckMe.0040CCEA
0040CCE1 53 PUSH EBX
0040CCE2 E8 51030000 CALL CrAckMe.0040D038
0040CCE7 83C4 04 ADD ESP,4
0040CCEA 58 POP EAX
0040CCEB 8945 F8 MOV DWORD PTR SS:[EBP-8],EAX
0040CCEE 6A FF PUSH -1
0040CCF0 6A 08 PUSH 8
0040CCF2 68 02000116 PUSH 16010002
0040CCF7 68 01000152 PUSH 52010001
0040CCFC E8 43030000 CALL CrAckMe.0040D044
0040CD01 83C4 10 ADD ESP,10
0040CD04 8945 D8 MOV DWORD PTR SS:[EBP-28],EAX
0040CD07 68 04000080 PUSH 80000004
0040CD0C 6A 00 PUSH 0
0040CD0E 8B45 D8 MOV EAX,DWORD PTR SS:[EBP-28]
0040CD11 85C0 TEST EAX,EAX
0040CD13 75 05 JNZ SHORT CrAckMe.0040CD1A
0040CD15 B8 CBC04000 MOV EAX,CrAckMe.0040C0CB
0040CD1A 50 PUSH EAX
0040CD1B 68 01000000 PUSH 1
0040CD20 BB 30010000 MOV EBX,130
0040CD25 E8 14030000 CALL CrAckMe.0040D03E
0040CD2A 83C4 10 ADD ESP,10
0040CD2D 8945 D4 MOV DWORD PTR SS:[EBP-2C],EAX
0040CD30 8B5D D8 MOV EBX,DWORD PTR SS:[EBP-28]
0040CD33 85DB TEST EBX,EBX
0040CD35 74 09 JE SHORT CrAckMe.0040CD40
0040CD37 53 PUSH EBX
0040CD38 E8 FB020000 CALL CrAckMe.0040D038
0040CD3D 83C4 04 ADD ESP,4
0040CD40 8B45 D4 MOV EAX,DWORD PTR SS:[EBP-2C]
0040CD43 8945 F4 MOV DWORD PTR SS:[EBP-C],EAX
0040CD46 6A FF PUSH -1
0040CD48 6A 08 PUSH 8
0040CD4A 68 1B000116 PUSH 1601001B
0040CD4F 68 01000152 PUSH 52010001
0040CD54 E8 EB020000 CALL CrAckMe.0040D044
0040CD59 83C4 10 ADD ESP,10
0040CD5C 8945 D8 MOV DWORD PTR SS:[EBP-28],EAX
0040CD5F 68 04000080 PUSH 80000004
0040CD64 6A 00 PUSH 0
0040CD66 8B45 D8 MOV EAX,DWORD PTR SS:[EBP-28]
0040CD69 85C0 TEST EAX,EAX
0040CD6B 75 05 JNZ SHORT CrAckMe.0040CD72
0040CD6D B8 CBC04000 MOV EAX,CrAckMe.0040C0CB
0040CD72 50 PUSH EAX
0040CD73 68 01000000 PUSH 1
0040CD78 BB 30010000 MOV EBX,130
0040CD7D E8 BC020000 CALL CrAckMe.0040D03E
0040CD82 83C4 10 ADD ESP,10
0040CD85 8945 D4 MOV DWORD PTR SS:[EBP-2C],EAX
0040CD88 8B5D D8 MOV EBX,DWORD PTR SS:[EBP-28]
0040CD8B 85DB TEST EBX,EBX
0040CD8D 74 09 JE SHORT CrAckMe.0040CD98
0040CD8F 53 PUSH EBX
0040CD90 E8 A3020000 CALL CrAckMe.0040D038
0040CD95 83C4 04 ADD ESP,4
0040CD98 8B45 D4 MOV EAX,DWORD PTR SS:[EBP-2C]
0040CD9B 8945 F0 MOV DWORD PTR SS:[EBP-10],EAX
0040CD9E 837D F4 04 CMP DWORD PTR SS:[EBP-C],4 //将注册码的长度与4比较
0040CDA2 0F8C 0B020000 JL CrAckMe.0040CFB3 //小于4就跳,跳就Over,就是说,用户名可以为空,但注册码必须要大于4
0040CDA8 8B45 F4 MOV EAX,DWORD PTR SS:[EBP-C] //将注册码的长度放进EAX
0040CDAB 33C9 XOR ECX,ECX //将ECX置零,此时ECX=0
0040CDAD 50 PUSH EAX //将EAX压入堆栈
0040CDAE 8D45 EC LEA EAX,DWORD PTR SS:[EBP-14]
0040CDB1 8BD8 MOV EBX,EAX
0040CDB3 58 POP EAX //EAX出栈
注意,从下面开始程序就进入注册码的计算。
0040CDB4 41 INC ECX //ECX加1,此处就是注册码计算的循环的开始点
0040CDB5 51 PUSH ECX //ECX入栈
0040CDB6 53 PUSH EBX
0040CDB7 890B MOV DWORD PTR DS:[EBX],ECX
0040CDB9 50 PUSH EAX //EAX入栈,EAX为注册码的位数
0040CDBA 3BC8 CMP ECX,EAX //ECX与EAX比较
0040CDBC 0F8F 5B000000 JG CrAckMe.0040CE1D //若ECX大于EAX就跳,就是说,计算完所有的注册码后就跳出循环
0040CDC2 68 01030080 PUSH 80000301
0040CDC7 6A 00 PUSH 0
0040CDC9 FF75 EC PUSH DWORD PTR SS:[EBP-14]
0040CDCC 68 04000080 PUSH 80000004
0040CDD1 6A 00 PUSH 0
0040CDD3 8B45 FC MOV EAX,DWORD PTR SS:[EBP-4] //假码压进EAX
0040CDD6 85C0 TEST EAX,EAX
0040CDD8 75 05 JNZ SHORT CrAckMe.0040CDDF
0040CDDA B8 CBC04000 MOV EAX,CrAckMe.0040C0CB
0040CDDF 50 PUSH EAX
0040CDE0 68 02000000 PUSH 2
0040CDE5 BB 44010000 MOV EBX,144
0040CDEA E8 4F020000 CALL CrAckMe.0040D03E
//取注册码每一位ASCII代码压进EAX,由循环来完成
0040CDEF 83C4 1C ADD ESP,1C //ESP=ESP+1C
0040CDF2 8945 D8 MOV DWORD PTR SS:[EBP-28],EAX //将EAX放进SS:[EBP-28]备用
0040CDF5 DF6D E4 FILD QWORD PTR SS:[EBP-1C]
//典型的易语言计算,从内存中将整数转换成一个浮点数并压入FPU的浮点寄存器栈,开始时SS:[EBP-1C]处为零
0040CDF8 DD5D D0 FSTP QWORD PTR SS:[EBP-30]
//从FPU的浮点寄存器栈中弹出一个浮点数,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址,开始时SS:[EBP-30]为零,随着循环的进行,SS:[EBP-30]处就是上一次计算所得到的十六进制值转为的浮点值
0040CDFB DD45 D0 FLD QWORD PTR SS:[EBP-30]
//从内存将一个浮点数压入FPU的浮点寄存器栈,就是0040CDF5处所转换得到的浮点值
0040CDFE DB45 D8 FILD DWORD PTR SS:[EBP-28]
//将SS:[EBP-28] 的整数转换成一个浮点数并压入FPU的浮点寄存器栈,这里就是将每一位注册码的ASCII值的十六进制转为浮点值
0040CE01 DD5D C8 FSTP QWORD PTR SS:[EBP-38]
//从FPU的浮点寄存器栈中弹出一个浮点数,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址,就是上一条指令所转换得到的浮点数
0040CE04 DC45 C8 FADD QWORD PTR SS:[EBP-38]
//两个浮点数相加,SS:[EBP-38]堆栈为上一条指令所转换得到的浮点数;
此处的目的就是将每一位注册码的ASCII值的十进制相加,得到的值就放进浮点寄存器栈ST处。
0040CE07 DD5D C0 FSTP QWORD PTR SS:[EBP-40]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-40]处
0040CE0A DD45 C0 FLD QWORD PTR SS:[EBP-40]
//从内存将一个浮点数压入FPU的浮点寄存器栈,此值就是0040CE07处存入SS:[EBP-40]的浮点值
0040CE0D E8 0BFEFFFF CALL CrAckMe.0040CC1D //将以上所得的浮点值转为十六进制,并存进EAX
0040CE12 8945 E4 MOV DWORD PTR SS:[EBP-1C],EAX //将EAX压进SS:[EBP-1C]备用
0040CE15 8955 E8 MOV DWORD PTR SS:[EBP-18],EDX
0040CE18 58 POP EAX //出栈
0040CE19 5B POP EBX //出栈
0040CE1A 59 POP ECX //出栈
0040CE1B ^ EB 97 JMP SHORT CrAckMe.0040CDB4 //无条件的跳转,此处就是循环结束点,跳回开始点
0040CE1D 83C4 0C ADD ESP,0C //ESP=ESP+C
0040CE20 DF6D E4 FILD QWORD PTR SS:[EBP-1C]
//将SS:[EBP-1C] 的整数转换成一个浮点数并压入FPU的浮点寄存器栈,这里就是将刚才计算注册码所得到的十六进制值转为浮点
0040CE23 DD5D D4 FSTP QWORD PTR SS:[EBP-2C]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-2C]处
0040CE26 DD45 D4 FLD QWORD PTR SS:[EBP-2C]
//从内存将一个浮点数压入FPU的浮点寄存器栈,此值就是刚才计算注册码所得到的十六进制值转为浮点后的值存入SS:[EBP-2C]的浮点值
0040CE29 DB45 F4 FILD DWORD PTR SS:[EBP-C]
//将SS:[EBP-C] 的整数转换成一个浮点数并压入FPU的浮点寄存器栈,这里就是刚才得到的注册码的位数转为浮点值
0040CE2C DD5D CC FSTP QWORD PTR SS:[EBP-34]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-34]处
0040CE2F DC4D CC FMUL QWORD PTR SS:[EBP-34]
//浮点乘法运算,将浮点寄存器栈ST中的刚才计算注册码所得到的浮点值乘以注册码位数的浮点值
0040CE32 DD5D C4 FSTP QWORD PTR SS:[EBP-3C]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-3C]处
0040CE35 DD45 C4 FLD QWORD PTR SS:[EBP-3C]
//从内存将一个浮点数压入FPU的浮点寄存器栈,此值就是刚才所得到的浮点值存入SS:[EBP-3C]
0040CE38 E8 E0FDFFFF CALL CrAckMe.0040CC1D //将以上所得的浮点值转为十六进制,并存进EAX
0040CE3D 8945 E4 MOV DWORD PTR SS:[EBP-1C],EAX //将EAX压进SS:[EBP-1C]备用
0040CE40 8955 E8 MOV DWORD PTR SS:[EBP-18],EDX
0040CE43 DF6D E4 FILD QWORD PTR SS:[EBP-1C]
//将SS:[EBP-1C] 的整数转换成一个浮点数并压入FPU的浮点寄存器栈,这里就是将刚才所得到的十六进制值转为浮点值
0040CE46 DD5D D4 FSTP QWORD PTR SS:[EBP-2C]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-2C]处
0040CE49 DD45 D4 FLD QWORD PTR SS:[EBP-2C] //从内存将一个浮点数压入FPU的浮点寄存器栈,此值就是刚才所得到的浮点值存入SS:[EBP-2C]
0040CE4C DC35 CCC04000 FDIV QWORD PTR DS:[40C0CC]
//浮点除法运算,将浮点寄存器栈ST中的刚才计算注册码所得到的浮点值除以DS:[40C0CC]处的浮点值,DS:[40C0CC]处的浮点值是固定的,此数为5.000
0040CE52 DD5D CC FSTP QWORD PTR SS:[EBP-34]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-34]处
0040CE55 DD45 CC FLD QWORD PTR SS:[EBP-34]
//从内存将一个浮点数压入FPU的浮点寄存器栈,此值就是刚才所得到的浮点值存入SS:[EBP-34]
0040CE58 E8 C0FDFFFF CALL CrAckMe.0040CC1D //将以上所得的浮点值转为十六进制,并存进EAX
0040CE5D 8945 E4 MOV DWORD PTR SS:[EBP-1C],EAX //将EAX压进SS:[EBP-1C]备用
0040CE60 8955 E8 MOV DWORD PTR SS:[EBP-18],EDX
0040CE63 8145 E4 9514000>ADD DWORD PTR SS:[EBP-1C],1495
//将SS:[EBP-1C]处的值加上十六进制的1495,所得的值存回SS:[EBP-1C]处
0040CE6A 8355 E8 00 ADC DWORD PTR SS:[EBP-18],0
0040CE6E 8B45 F0 MOV EAX,DWORD PTR SS:[EBP-10]
0040CE71 33C9 XOR ECX,ECX
注册码计算到此为止!下面将是用户名的计算。
0040CE73 50 PUSH EAX //EAX入栈
0040CE74 8D45 E0 LEA EAX,DWORD PTR SS:[EBP-20]
0040CE77 8BD8 MOV EBX,EAX
0040CE79 58 POP EAX
0040CE7A 41 INC ECX //ECX加1,此处就是用户名的计算的循环的开始点
0040CE7B 51 PUSH ECX //ECX入栈
0040CE7C 53 PUSH EBX
0040CE7D 890B MOV DWORD PTR DS:[EBX],ECX
0040CE7F 50 PUSH EAX //EAX入栈,此时EAX为用户名的位数
0040CE80 3BC8 CMP ECX,EAX
0040CE82 0F8F 58000000 JG CrAckMe.0040CEE0 //若ECX大于EAX就跳,就是说,计算完所有的用户名后就跳出循环
0040CE88 68 01030080 PUSH 80000301
0040CE8D 6A 00 PUSH 0
0040CE8F FF75 E0 PUSH DWORD PTR SS:[EBP-20]
0040CE92 68 04000080 PUSH 80000004
0040CE97 6A 00 PUSH 0
0040CE99 8B45 F8 MOV EAX,DWORD PTR SS:[EBP-8] //将用户名压进EAX
0040CE9C 85C0 TEST EAX,EAX
0040CE9E 75 05 JNZ SHORT CrAckMe.0040CEA5
0040CEA0 B8 CBC04000 MOV EAX,CrAckMe.0040C0CB
0040CEA5 50 PUSH EAX //EAX入栈
0040CEA6 68 02000000 PUSH 2
0040CEAB BB 44010000 MOV EBX,144
0040CEB0 E8 89010000 CALL CrAckMe.0040D03E
//取用户名的每一位ASCII代码压进EAX,由循环来完成
0040CEB5 83C4 1C ADD ESP,1C
0040CEB8 8945 D8 MOV DWORD PTR SS:[EBP-28],EAX //将EAX放进SS:[EBP-28]备用
0040CEBB DB45 DC FILD DWORD PTR SS:[EBP-24]
//与上面注册码的计算一样,从内存中将整数转换成一个浮点数并压入FPU的浮点寄存器栈,开始时SS:[EBP-24]处为零
0040CEBE DD5D D0 FSTP QWORD PTR SS:[EBP-30]
//从FPU的浮点寄存器栈中弹出一个浮点数,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址,开始时SS:[EBP-30]为零,随着循环的进行,SS:[EBP-30]处就是上一次计算所得到的十六进制值转为的浮点值
0040CEC1 DD45 D0 FLD QWORD PTR SS:[EBP-30]
//从内存将一个浮点数压入FPU的浮点寄存器栈,就是0040CEBB处所转换得到的浮点值
0040CEC4 DB45 D8 FILD DWORD PTR SS:[EBP-28]
//将SS:[EBP-28] 的整数转换成一个浮点数并压入FPU的浮点寄存器栈,这里就是将每一位用户名的ASCII值的十六进制转为浮点值
0040CEC7 DD5D C8 FSTP QWORD PTR SS:[EBP-38]
//从FPU的浮点寄存器栈中弹出一个浮点数,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址,就是上一条指令所转换得到的浮点数
0040CECA DC45 C8 FADD QWORD PTR SS:[EBP-38]
//两个浮点数相加,SS:[EBP-38]堆栈为上一条指令所转换得到的浮点数;
此处的目的就是将每一位用户名的ASCII值的十进制相加,得到的值就放进浮点寄存器栈ST处。
0040CECD DD5D C0 FSTP QWORD PTR SS:[EBP-40]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-40]处
0040CED0 DD45 C0 FLD QWORD PTR SS:[EBP-40]
//从内存将一个浮点数压入FPU的浮点寄存器栈,此值就是0040CECD 处存入SS:[EBP-40]的浮点值
0040CED3 E8 45FDFFFF CALL CrAckMe.0040CC1D //将以上所得的浮点值转为十六进制,并存进EAX
0040CED8 8945 DC MOV DWORD PTR SS:[EBP-24],EAX //将EAX压进SS:[EBP-1C]备用
0040CEDB 58 POP EAX //出栈
0040CEDC 5B POP EBX //出栈
0040CEDD 59 POP ECX //出栈
0040CEDE ^ EB 9A JMP SHORT CrAckMe.0040CE7A //无条件的跳转,此处就是循环结束点,跳回开始点
0040CEE0 83C4 0C ADD ESP,0C
0040CEE3 DB45 DC FILD DWORD PTR SS:[EBP-24]
//将SS:[EBP-24] 的整数转换成一个浮点数并压入FPU的浮点寄存器栈,这里就是将刚才计算用户名所得到的十六进制值转为浮点值
0040CEE6 DD5D D4 FSTP QWORD PTR SS:[EBP-2C]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-2C]处
0040CEE9 DD45 D4 FLD QWORD PTR SS:[EBP-2C]
//从内存将一个浮点数压入FPU的浮点寄存器栈,此值就是刚才计算用户名所得到的十六进制值转为浮点后的值存入SS:[EBP-2C]的浮点值
0040CEEC DB45 F0 FILD DWORD PTR SS:[EBP-10]
//将SS:[EBP-10] 的整数转换成一个浮点数并压入FPU的浮点寄存器栈,这里就是刚才得到的用户名的位数转为浮点值
0040CEEF DD5D CC FSTP QWORD PTR SS:[EBP-34]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-34]处
0040CEF2 DC4D CC FMUL QWORD PTR SS:[EBP-34]
//浮点乘法运算,将浮点寄存器栈ST中的刚才计算用户名所得到的浮点值乘以用户名位数的浮点值
0040CEF5 DD5D C4 FSTP QWORD PTR SS:[EBP-3C]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-3C]处
0040CEF8 DD45 C4 FLD QWORD PTR SS:[EBP-3C]
//从内存将一个浮点数压入FPU的浮点寄存器栈,此值就是刚才所得到的浮点值存入SS:[EBP-3C]
0040CEFB E8 1DFDFFFF CALL CrAckMe.0040CC1D //将以上所得的浮点值转为十六进制,并存进EAX
0040CF00 8945 DC MOV DWORD PTR SS:[EBP-24],EAX //将EAX压进SS:[EBP-24]备用
0040CF03 8345 DC 05 ADD DWORD PTR SS:[EBP-24],5 //将以上所得的浮点值转为十六进制后的值加5,并存回SS:[EBP-24]处
0040CF07 DB45 DC FILD DWORD PTR SS:[EBP-24]
//将SS:[EBP-24] 的整数转换成一个浮点数并压入FPU的浮点寄存器栈,这里就是将刚才所得到的十六进制值转为浮点值
0040CF0A DD5D D4 FSTP QWORD PTR SS:[EBP-2C]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-2C]处
0040CF0D DD45 D4 FLD QWORD PTR SS:[EBP-2C]
//从内存将一个浮点数压入FPU的浮点寄存器栈,就是0040CF07 处所转换得到的浮点值
0040CF10 DC35 D4C04000 FDIV QWORD PTR DS:[40C0D4]
//浮点除法运算,将浮点寄存器栈ST中的刚才计算用户名所得到的浮点值除以DS:[40C0D4]处的浮点值,DS:[40C0D4]处的浮点值是固定的,此数为7.000
0040CF16 DD5D CC FSTP QWORD PTR SS:[EBP-34]
//从FPU的浮点寄存器栈中弹出一个浮点数,此时该浮点数就是上一条指令计算得到的值,依据目标内存空间的大小转换成对应的精度,存入指定的内存地址SS:[EBP-34]处
0040CF19 DD45 CC FLD QWORD PTR SS:[EBP-34]
//从内存将一个浮点数压入FPU的浮点寄存器栈,此值就是刚才所得到的浮点值存入SS:[EBP-34]
0040CF1C E8 FCFCFFFF CALL CrAckMe.0040CC1D //将以上所得的浮点值转为十六进制,并存进EAX
0040CF21 8945 DC MOV DWORD PTR SS:[EBP-24],EAX //将EAX压进SS:[EBP-24]备用
0040CF24 8145 DC 9514000>ADD DWORD PTR SS:[EBP-24],1495
//将SS:[EBP-24]处的值加上十六进制的1495,所得的值存回SS:[EBP-24]处
0040CF2B 8B45 DC MOV EAX,DWORD PTR SS:[EBP-24] //将SS:[EBP-24]处的值存进EAX备用
0040CF2E 99 CDQ //双字扩展. (把EAX中的字的符号扩展到EDX中去)
0040CF2F 3945 E4 CMP DWORD PTR SS:[EBP-1C],EAX
// SS:[EBP-1C]的值与EAX比较,还记得SS:[EBP-1C]这里吗?这里就是刚才计算注册码得到的十六进制值!将计算后的用户名与计算后的注册码比较,相同就成功,不同就Game Over。
0040CF32 75 03 JNZ SHORT CrAckMe.0040CF37 //不相等就跳,跳就Over。
0040CF34 3955 E8 CMP DWORD PTR SS:[EBP-18],EDX //这里是EDX与SS:[EBP-18]比较
0040CF37 0F85 3B000000 JNZ CrAckMe.0040CF78 //不同就跳,跳就Over
0040CF3D 68 04000080 PUSH 80000004
0040CF42 6A 00 PUSH 0
0040CF44 68 DCC04000 PUSH CrAckMe.0040C0DC
0040CF49 68 01030080 PUSH 80000301
0040CF4E 6A 00 PUSH 0
0040CF50 68 40000000 PUSH 40
0040CF55 68 04000080 PUSH 80000004
0040CF5A 6A 00 PUSH 0
0040CF5C 68 E5C04000 PUSH CrAckMe.0040C0E5
0040CF61 68 03000000 PUSH 3
0040CF66 BB 00030000 MOV EBX,300
0040CF6B E8 CE000000 CALL CrAckMe.0040D03E //弹出成功注册框,呵呵,成功了!
0040CF70 83C4 28 ADD ESP,28
0040CF73 E9 36000000 JMP CrAckMe.0040CFAE
0040CC44 55 PUSH EBP
算法到此结束,下面的就无需分析了!
________________________________________________________________________________________
【破解总结】
此CrackMe够厉害的,很有创新,它先计算用户输入的注册码(就是我们所说的假码),再计算用户名,将两者所得的值比较,相等的就注册成功,不等的就 Game Over ,这样的注册方式很不错,这样的注册机比较难写(相对于我等菜鸟而言),不过,这种注册方式会导致一个用户名有多个注册码,或者说一个注册码用多个用户名。
注册码计算方式如下:
将每一位假码的ASCII代码相加,然后乘以注册码的位数,又除以固定的十六进制数字5 ,最后加上固定的十六进制值1495 。
下面是我输入的注册码的计算:
注册码:1234
31+32+33+34=CA
CA*4=328
328/5=A1
A1+1495=1536
计算最后得到的值是1536
用户名计算方式如下:
计算方式大体上与注册码相同,将每一位用户名的ASCII代码相加,然后乘以用户名的位数,加上固定的十六进制数值5(呵呵,这里与注册码的不同),又除以固定的十六进制数字7 ,最后加上固定的十六进制值1495。
下面是我的用户名的计算:
用户名:lang
6C+61+6E+67=1A2
1A2*4=688
688+5=68D
68D/7=EF
EF+1495=1584
计算最后得到的值是1584
用户名的计算值与注册码计算的值不同,最后当然是Game Over啦。
一组可用注册信息:
======================
用户名:lang
注册码:zo!!
======================
成功注册的图片如下:
呵呵,终于到了注册机这一部分!
我觉得这部分时是整个破解最难,当然这是相对我等菜鸟来说的。对于这种比较方式来说,我认为要用暴力破解的方式来写注册机才行。就是说,先计算用户名,将得到的值用计算注册码的方式逆向推理,这种方式的最大缺点是计算时间很长,在这个注册机中,我只允许用户名为四位字符,注册码也将是四位。我只是计算一个四位的用户名lang,在我的配置(赛扬4 2.0 OC到2.8 ,384内存)就用了78.56201秒钟 !没办法,谁叫我是菜鸟?
注册机界面如下:
注意:本注册机只能计算用户名为四位字符的注册码,而且不能保证所有的用户名都能算出注册码
,算不出来的就换一个吧。由于本注册机使用了暴力破解的方式,所以,配置低的朋友慎用,死机就不要怪我啊!
注册机以及代码我都发上来了,由于时间紧,在注册机的代码中,我没有写注释,而且所使用的变量也很糊涂
,看不懂的也不要怪我哦 ,就怪我水平低吧
(注意,不是人品问题,是水平问题
)!
在附件中,
RegCrAckMe.rar 为注册机和注册机的源代码
CraCkmE.rar 为本文所破的CrackMe
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
上传的附件: