【文章标题】: 超菜的新手处女作--消息断点与算法分析
【文章作者】: wurunduo
【作者邮箱】: 82120633@qq.com
【作者主页】: http://hi.baidu.com/%CE%E2%C8%F3%EE%EC
【软件下载】: http://pickup.mofile.com/4170027703968521
【软件名称】: echap518.exe(只是供学习的crackme)
【加壳方式】: 无
【保护方式】: serial
【使用工具】: OllyICE
【文章日期】: 20080704
-----------------------------------------------------
哈哈,是我的处女作哈,学了那么久,才有了一个自己独立解决的原创作品,《加密与解密(第二版)》一书才刚刚看完,里面看来看去,很多都是方法的问题,算是可以照本宣科解决问题的,最难的就是算法的分析了,几乎就是看运气,运气差的遇到的几千条代码分析才能找到注册码的,就没辙了,只能爆破它。

今天静下心来,一定要自己把它的注册码给算出来,不再依靠教程,不再依靠答案,要自己实践,这样才能学到更多的东西,下面把我的思路整理出来给与大家共享一下。

1、拿到软件先运行,了解到它是以输入name和serial的方式进行保护的,输错有错误提示。
2、查壳,无壳。不是重点,就选了一个没壳的。
3、用OllyICE打开,点运行程序(弹出程序界面,不理它)--点查看菜单--窗口(点右键刷新一下)--单击“CHECK”那一行--点右键,选消息断点--选“202 WM_LBUTTONUP”--确定,如下图:





问1:为什么要操作这一步?
答:我现在的目的是要设断点,本来可以根据它的错误提示找到它的参考来设断,不过这种设断方式中断后,它是停在算法分析的后面,无法判断算法是从何处开始的,如果要爆破的话就可以用这种方式,但我们现在是要完整分析它的算法,所以我想,注册码的分析一定是在点了check,松开时开始的,而在弹出出错窗口结束,那么我就把它限定了这个范围,下面我们的任务就是要找出这个范围的开头。那么我设下了这个消息断点,意思就是一松开check键后就中断。

4、再程序中输入name:666666,serial:7777777(我喜欢这样输,6个6,7个7,数量不会太少,一看也知道输了几位)--点check,被断下了,如下图:



5、点查看菜单--内存--点击如下图那一行--按F2设断。



问2:操作一步是要干嘛?
答:我们刚刚断下的地方,不是程序的领空,是跑到user32的领空了,在最顶的标题上可以了解到,这个我们一定是不关心的,都是一些api函数,我们要了解的是我们的程序的代码,所以我们要想办法让它返回到程序的领空。

问3:为什么要选那一条设断?
答:你进到内存窗口后,发现是echap518这个属主只有五行,echap518就是我们的程序名了,我们要的就是返回到这,区段这里显示四种,因为我们是要分析它的执行代码,所以我们就选.text那一行设断了。那这样我们再点运行程序后,它就是断在echap518程序领空了。

6、返回echap518程序领空后,如下图:



7、在这个窗口任意点右键,选择如下图所示:



问4:这一步是干嘛用的?
答:现在我主要是想分析它运行了哪些主要函数代码,用这个可以跟踪,如运行过了会有红色显示出来,只要是红色显示出来的,那算法的代码一定在这里面了。

8、点运行程序,这样程序就运行完了,就可以开始分析了。首先还是找那个范围出来吧。
点查看菜单--run跟踪--选择一行echap518--点右键选“统计模块”,如下图:





问5:统计结果中的计数是什么意思?
答:这里每一行的意思是指它运行过的程序块,计数是运行这个程序块的次数。

9、双击每一行,都会跑到反汇编窗口,会出现被选择的块(如下图),在每一下块的块首按F2设断,统计窗口共有五行,就设五次。



问6:这个操作又是什么意思?
答:算法的分析就在这五个块里了,每个块可以理解为实现一个小功能,设这么多断点也是为了下面跟踪时好慢慢分析判断,你厉害的话不用像我一样麻烦也可以,设第一个就完事了。

10、我把关于算法的完整代码复制出来,就可以慢慢分析了,要分析一定要一步步跟踪,看数据信息窗口的提示,看堆栈和寄存器里的内容变化,慢慢理解。

004014B0 /. 55            push    ebp
004014B1 |. 8BEC          mov     ebp, esp
004014B3 |. 6A FF         push    -1
004014B5 |. 68 C21B4000   push    00401BC2                         ; SE 处理程序安装
004014BA |. 64:A1 0000000>mov     eax, dword ptr fs:[0]
004014C0 |. 50            push    eax
004014C1 |. 64:8925 00000>mov     dword ptr fs:[0], esp
004014C8 |. 83EC 14       sub     esp, 14
004014CB |. 53            push    ebx
004014CC |. 56            push    esi
004014CD |. 57            push    edi
004014CE |. 894D E0       mov     dword ptr [ebp-20], ecx
004014D1 |. 8D4D E4       lea     ecx, dword ptr [ebp-1C]
004014D4 |. E8 83030000   call    <jmp.&MFC42.#540>
004014D9 |. C745 FC 00000>mov     dword ptr [ebp-4], 0
004014E0 |. 8D4D F0       lea     ecx, dword ptr [ebp-10]
004014E3 |. E8 74030000   call    <jmp.&MFC42.#540>
004014E8 |. C645 FC 01    mov     byte ptr [ebp-4], 1
004014EC |. 8B4D E0       mov     ecx, dword ptr [ebp-20]
004014EF |. 81C1 A0000000 add     ecx, 0A0
004014F5 |. E8 AA030000   call    <jmp.&MFC42.#3876>
004014FA |. 8945 EC       mov     dword ptr [ebp-14], eax          ; 通过函数得到name的长度
004014FD |. 837D EC 05    cmp     dword ptr [ebp-14], 5
00401501 |. 7F 05         jg      short 00401508                   ; 长度小于等于5就死
00401503 |. E9 BB000000   jmp     004015C3
00401508 |> 8B4D E0       mov     ecx, dword ptr [ebp-20]
0040150B |. 83C1 60       add     ecx, 60
0040150E |. E8 91030000   call    <jmp.&MFC42.#3876>               ; 同上面的函数,得到serial长度
00401513 |. 8945 E8       mov     dword ptr [ebp-18], eax
00401516 |. 837D E8 05    cmp     dword ptr [ebp-18], 5
0040151A |. 7F 05         jg      short 00401521                   ; 同样要大于5位才行
0040151C |. E9 A2000000   jmp     004015C3
00401521 |> 8B45 E0       mov     eax, dword ptr [ebp-20]
00401524 |. 05 E0000000   add     eax, 0E0
00401529 |. 50            push    eax
0040152A |. 8B4D E0       mov     ecx, dword ptr [ebp-20]
0040152D |. 81C1 A0000000 add     ecx, 0A0
00401533 |. E8 66030000   call    <jmp.&MFC42.#3874>              
00401538 |. 8B4D E0       mov     ecx, dword ptr [ebp-20]
0040153B |. 81C1 E4000000 add     ecx, 0E4
00401541 |. 51            push    ecx
00401542 |. 8B4D E0       mov     ecx, dword ptr [ebp-20]
00401545 |. 83C1 60       add     ecx, 60
00401548 |. E8 51030000   call    <jmp.&MFC42.#3874>              
0040154D |. 8B55 E0       mov     edx, dword ptr [ebp-20]
00401550 |. 81C2 E0000000 add     edx, 0E0
00401556 |. 52            push    edx
00401557 |. 8D4D E4       lea     ecx, dword ptr [ebp-1C]
0040155A |. E8 39030000   call    <jmp.&MFC42.#858>
0040155F |. 8B45 E0       mov     eax, dword ptr [ebp-20]
00401562 |. 05 E4000000   add     eax, 0E4
00401567 |. 50            push    eax
00401568 |. 8D4D F0       lea     ecx, dword ptr [ebp-10]
0040156B |. E8 28030000   call    <jmp.&MFC42.#858>
00401570 |. 33C0          xor     eax, eax
00401572 |. 33DB          xor     ebx, ebx
00401574 |. 33C9          xor     ecx, ecx
00401576 |. B9 01000000   mov     ecx, 1
0040157B |. 33D2          xor     edx, edx
0040157D |. 8B45 E4       mov     eax, dword ptr [ebp-1C]
00401580 |> 8A18          /mov     bl, byte ptr [eax]              ; name每个字符从左到右与1,2,3,...异或
00401582 |. 32D9          |xor     bl, cl                          ; 再取低8位存入原位置
00401584 |. 8818          |mov     byte ptr [eax], bl
00401586 |. 41            |inc     ecx
00401587 |. 40            |inc     eax
00401588 |. 8038 00       |cmp     byte ptr [eax], 0
0040158B |.^ 75 F3         \jnz     short 00401580
0040158D |. 33C0          xor     eax, eax
0040158F |. 33DB          xor     ebx, ebx
00401591 |. 33C9          xor     ecx, ecx
00401593 |. B9 0A000000   mov     ecx, 0A
00401598 |. 33D2          xor     edx, edx
0040159A |. 8B45 F0       mov     eax, dword ptr [ebp-10]
0040159D |> 8A18          /mov     bl, byte ptr [eax]              ; 这个操作一样的,对serial操作,但是从A开始异或
0040159F |. 32D9          |xor     bl, cl
004015A1 |. 8818          |mov     byte ptr [eax], bl
004015A3 |. 41            |inc     ecx
004015A4 |. 40            |inc     eax
004015A5 |. 8038 00       |cmp     byte ptr [eax], 0
004015A8 |.^ 75 F3         \jnz     short 0040159D
004015AA |. 8B45 E4       mov     eax, dword ptr [ebp-1C]          ; name操作后的数据
004015AD |. 8B55 F0       mov     edx, dword ptr [ebp-10]          ; serial操作后的数据
004015B0 |> 33C9          /xor     ecx, ecx
004015B2 |. 8A18          |mov     bl, byte ptr [eax]
004015B4 |. 8A0A          |mov     cl, byte ptr [edx]
004015B6 |. 3AD9          |cmp     bl, cl
004015B8 |. 75 09         |jnz     short 004015C3                  ; 比较两个是不是相同
004015BA |. 40            |inc     eax
004015BB |. 42            |inc     edx
004015BC |. 8038 00       |cmp     byte ptr [eax], 0
004015BF |.^ 75 EF         \jnz     short 004015B0
004015C1 |. EB 16         jmp     short 004015D9
004015C3 |> 6A 00         push    0
004015C5 |. 68 6C304000   push    0040306C                         ; ASCII "ERROR"
004015CA |. 68 40304000   push    00403040                         ; ASCII "One of the Details you entered was wrong"
004015CF |. 8B4D E0       mov     ecx, dword ptr [ebp-20]
004015D2 |. E8 BB020000   call    <jmp.&MFC42.#4224>

问7:这个具体要怎么分析?
答:我一开始说难就是难在这里了,前面的操作只是方法,一教大家就会,而这个算法的分析就很难用语言来表示,表示出来就又臭又长,不太好懂。你不要在这里分析,看这些代码分析出结果很难的,一定要在OllyICE中跟踪分析才会有结果,我刚刚设的那五个断点,是五个小功能,比如有一个是判断name是不是大于5位,一个是判断serial是不是大于5位,这就去了两个了,这两个也不是算法的核心,这样分析的范围就又变小了,再一个是把name进行转换,一个是把serial进行转换,最后一个就是判断是否相等了,正好五个功能块,别的看不懂的也可以跳过,反正一个块的功能一般也就实现一个功能,能够分析出来就行了。


结果:
name:666666
用16进制表示:36 36 36 36 36 36
与1h,2h,3h,4h,5h,6h异或,有6位就递增地异或6次,结果:37 34 35 32 33 30(16进制的)

serial的操作也是一样的,只是不是与1h异或的,是与0Ah异或的,并以1递增,最后把两个结果一比,相等就成功了。

知道了这个算法,我们就来推出它的serial,首先我们要知道,xor它的逆操作也是xor,这就好办了,计算比较麻烦的事,我们可以用这个工具来帮我们“32bit Calculator”

现在我们把刚刚得到的结果37 34 35 32 33 30与0Ah 0Bh 0Ch 0Dh 0Eh 0Fh进行xor操作
结果:3D 3F 39 3F 3D 3F
转换为ASICC码,结果:=?9?=?

所以:
name:666666
serial:=?9?=?

上传的附件 echap518.rar