CD/DVD Data Recovery V1.0.01281的算法分析
查壳,无!OD载入,输入试炼码,有提示,查找参考字符………………
找到关键段的段首后,F8单步:
====================================================
0041A980/.55 push ebp
0041A981|.8BEC mov ebp, esp
0041A983|.83EC 20 sub esp, 20
………………
0041A999|.E8 F210FFFF call 0040BA90//取用户名的长度
0041A99E|.83F8 02 cmp eax, 2 ;用户名必须大于2位
0041A9A1|.7D 13 jge short 0041A9B6
0041A9A3|.6A 00 push 0
0041A9A5|.6A 00 push 0
0041A9A7|.68 F8E34400 push 0044E3F8 ;please input correct user name!
0041A9BC|.E8 CF10FFFF call 0040BA90//取注册码的长度
0041A9C1|.83F8 08 cmp eax, 8 ;注册码必须>=8位
0041A9C4|.7D 13 jge short 0041A9D9
0041A9C6|.6A 00 push 0
0041A9C8|.6A 00 push 0
0041A9CA|.68 18E44400 push 0044E418 ;please input correct registration code!
0041A9D9|> \6A 00 push 0 ; /Arg1 = 00000000
0041A9DB|.8B4D E0 mov ecx, dword ptr ; |
0041A9DE|.83C1 70 add ecx, 70 ; |
0041A9E1|.E8 0ACEFFFF call 004177F0 ; \F7进入,频繁调用,涉及算法
//下面一大堆都是调用这个函数,呵呵,调用的形式如:
int func1(int i,char* str)
作用:取指定字符串中的i位的字符
*****************************
子函数:CALL 004177F0:
*****************************
004177F3|.51 push ecx
//
004177F4|.894D FC mov dword ptr , ecx
004177F7|.837D 08 00 cmp dword ptr , 0
004177FB|.7C 0D jl short 0041780A
004177FD|.8B4D FC mov ecx, dword ptr
00417800|.E8 8B42FFFF call 0040BA90
00417805|.3945 08 cmp dword ptr , eax
00417808|.7E 0A jle short 00417814
0041780A|>68 57000780 push 80070057 ; /Arg1 = 80070057
0041780F|.E8 5C36FFFF call 0040AE70 ; \CDDVDDR.0040AE70
00417814|>8B45 FC mov eax, dword ptr
00417817|.8B08 mov ecx, dword ptr
00417819|.8B55 08 mov edx, dword ptr
0041781C|.8A0411 mov al, byte ptr
先是对用户名的前两位各取了两次:
0041A9D9|> \6A 00 push 0 ; /Arg1 = 00000000
0041A9DB|.8B4D E0 mov ecx, dword ptr ; |
0041A9DE|.83C1 70 add ecx, 70 ; |
0041A9E1|.E8 0ACEFFFF call 004177F0 ; \CDDVDDR.004177F0
0041A9E6|.8845 EF mov byte ptr , al ;取用户名的第1个字符
0041A9E9|.6A 01 push 1 ; /Arg1 = 00000001
0041A9EB|.8B4D E0 mov ecx, dword ptr ; |
0041A9EE|.83C1 70 add ecx, 70 ; |
0041A9F1|.E8 FACDFFFF call 004177F0 ; \CDDVDDR.004177F0
0041A9F6|.8845 F8 mov byte ptr , al ;取用户名第2位
0041A9F9|.6A 00 push 0 ; /Arg1 = 00000000
0041A9FB|.8B4D E0 mov ecx, dword ptr ; |
0041A9FE|.83C1 70 add ecx, 70 ; |
0041AA01|.E8 EACDFFFF call 004177F0 ; \CDDVDDR.004177F0
0041AA06|.8845 FF mov byte ptr , al
0041AA09|.6A 01 push 1 ; /Arg1 = 00000001
0041AA0B|.8B4D E0 mov ecx, dword ptr ; |
0041AA0E|.83C1 70 add ecx, 70 ; |
0041AA11|.E8 DACDFFFF call 004177F0 ; \CDDVDDR.004177F0
然后分别对取出的4位进行运算:
0041AA19|.0FB645 EF movzx eax, byte ptr
0041AA1D|.83C8 43 or eax, 43
0041AA20|.8845 EF mov byte ptr , al
只是其中的常量在改变,呵呵…………
换位表达如:
*******************************************************
第1位------->EAX------->EAX=EAX OR 43
AL------->
第2位------->ECX------->ECX=ECX OR 44
CL------->
第1位------->EDX------->EDX=EAX OR 52
DL------->
第2位------->EAX------->ECX=ECX OR 44
CL------->
继续对取出的4位计算,方式如:
0041AA41|.0FB645 EF movzx eax, byte ptr
0041AA45|.99 cdq
0041AA46|.B9 0A000000 mov ecx, 0A
0041AA4B|.F7F9 idiv ecx
0041AA4D|.8855 EF mov byte ptr , dl
其实也就是一个求余的运算,换位表达如下:
= MOD A
= MOD A
= MOD A
= MOD A
又是一个大循环:
0041AA7D|.C745 F0 00000>mov dword ptr , 0
0041AA84|.C745 E8 00000>mov dword ptr , 0 ;相当于计时器
0041AA8B|.EB 09 jmp short 0041AA96
0041AA8D|>8B55 E8 /mov edx, dword ptr
0041AA90|.83C2 01 |add edx, 1
0041AA93|.8955 E8 |mov dword ptr , edx
0041AA96|>8B4D E0 mov ecx, dword ptr
0041AA99|.83C1 70 |add ecx, 70
0041AA9C|.E8 EF0FFFFF |call 0040BA90 ;子函数,取用户名LEN
0041AAA1|.3945 E8 |cmp dword ptr , eax
0041AAA4|.7D 1E |jge short 0041AAC4
0041AAA6|.8B45 E8 |mov eax, dword ptr
0041AAA9|.50 |push eax ; /Arg1
0041AAAA|.8B4D E0 |mov ecx, dword ptr ; |
0041AAAD|.83C1 70 |add ecx, 70 ; |
0041AAB0|.E8 3BCDFFFF |call 004177F0 ; \CDDVDDR.004177F0
0041AAB5|.8845 E7 |mov byte ptr , al
0041AAB8|.0FB64D E7 |movzx ecx, byte ptr
0041AABC|.034D F0 |add ecx, dword ptr
0041AABF|.894D F0 |mov dword ptr , ecx
0041AAC2|.^ EB C9 \jmp short 0041AA8D ;用户名各位字符的ASCII累加到EBP-10
0041AAC4|>8B45 F0 mov eax, dword ptr ;将累加值送入EAX
这个更清晰了,就是累加用户名各位的字符的ASCII
换位表达如下:
total=0;
for(i=0;i<len(name);i++)
total+=name
然后将total MOD A求余,值送往
接下来就是对注册码的判断了,看完了就会发现,其实上面做的一切就是“白搭”,呵呵
先假设一下,我们输入的注册码为code
0041AAD2|.6A 00 push 0 ; /Arg1 = 00000000
0041AAD4|.8B4D E0 mov ecx, dword ptr ; |
0041AAD7|.83C1 74 add ecx, 74 ; |
0041AADA|.E8 11CDFFFF call 004177F0 ; \CDDVDDR.004177F0
0041AADF|.8845 FC mov byte ptr , al
……………………………………
0041AB42|.6A 07 push 7 ; /Arg1 = 00000007
0041AB44|.8B4D E0 mov ecx, dword ptr ; |
0041AB47|.83C1 74 add ecx, 74 ; |
0041AB4A|.E8 A1CCFFFF call 004177F0 ; \CDDVDDR.004177F0
0041AB4F|.8845 FB mov byte ptr , al
上面一段取码行为的结果就是:
=code
=code
=code
=code
=code
=code
=code
=code
看了一大堆,其实只需要这一段就OK了,
0041AB52|.0FB655 EF movzx edx, byte ptr
0041AB56|.0FB645 FC movzx eax, byte ptr
0041AB5A|.83E8 30 sub eax, 30
0041AB5D|.3BD0 cmp edx, eax
0041AB5F|.75 3C jnz short 0041AB9D
希望你没有那么不幸,刚好此处的跳转没跳,那样你可能要多走一段弯路,不过那样的机率很小,/:013 。
我很幸运,跳转实现了,直接来到了下面这段代码:
==========================================================
0041ABA1|.83F8 39 cmp eax, 39
0041ABA4|.0F85 A7000000 jnz 0041AC51
0041ABAA|.0FB64D FD movzx ecx, byte ptr
0041ABAE|.83F9 33 cmp ecx, 33
0041ABB1|.0F85 9A000000 jnz 0041AC51
0041ABB7|.0FB655 F6 movzx edx, byte ptr
0041ABBB|.83FA 30 cmp edx, 30
0041ABBE|.0F85 8D000000 jnz 0041AC51
0041ABC4|.0FB645 F5 movzx eax, byte ptr
0041ABC8|.83F8 31 cmp eax, 31
0041ABCB|.0F85 80000000 jnz 0041AC51
0041ABD1|.0FB64D F9 movzx ecx, byte ptr
0041ABD5|.83F9 36 cmp ecx, 36
0041ABD8|.75 77 jnz short 0041AC51
0041ABDA|.0FB655 F7 movzx edx, byte ptr
0041ABDE|.83FA 36 cmp edx, 36
0041ABE1|.75 6E jnz short 0041AC51
0041ABE3|.0FB645 FE movzx eax, byte ptr
0041ABE7|.83F8 36 cmp eax, 36
0041ABEA|.75 65 jnz short 0041AC51
0041ABEC|.0FB64D FB movzx ecx, byte ptr
0041ABF0|.83F9 36 cmp ecx, 36
0041ABF3|.75 5C jnz short 0041AC51
========对照如下,只要符合下面的条件就OK了,花了半多个小时看前面,
========哎,……
========现在明白没有,
code==39
code=33
code=30
code=31
code=36
code=36
code=36
code=36
只要注册码满足下面的条件,就OK了,就这么简单,都不知道作者绕那么多弯弯是为什么???
即:93016666****
另,注册码必须大于等于8位
程序运行界面如下:
附件为目标程序和算法跟踪过程:
[ 本帖最后由 iawen 于 2007-12-29 17:02 编辑 ] 学习学习!!!!!!!!! 先来研究一下软件 再来看楼主的破文 向楼主学习了
页:
[1]