【文章标题】: 再探 CrackMe001 By飘云[PYG](二)
【文章作者】: petnt
【作者邮箱】: petnt@sohu.com
【软件名称】: CrackMe001 By飘云[PYG]
【下载地址】: 自己搜索下载
【加壳方式】: FSG2.0
【保护方式】: 壳\注册码
【使用工具】: OD\UltraEdit-32\ImportREC.exe
【操作平台】: XpSp2
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
书接上回:
【正 文】
第三幕 Kill Timer
此CrackMe要求去除启动时的延时,就是干掉那个在数秒的计时器。bp SetTimer,断下后返回程序领空,我们来看看整个函数的样子。
00428770 55 push ebp
00428771 |. 8BEC mov ebp, esp
00428773 |. 6A 00 push 0
00428775 |. 53 push ebx
00428776 |. 56 push esi
00428777 |. 8BD8 mov ebx, eax
00428779 |. 33C0 xor eax, eax
0042877B |. 55 push ebp
0042877C |. 68 EF874200 push 004287EF
00428781 |. 64:FF30 push dword ptr fs:[eax]
00428784 |. 64:8920 mov dword ptr fs:[eax], esp
00428787 |. 6A 01 push 1 ; /TimerID = 1
00428789 |. 8B43 34 mov eax, dword ptr [ebx+34] ; |
0042878C |. 50 push eax ; |hWnd
0042878D |. E8 EEDDFDFF call <jmp.&user32.KillTimer> ; \KillTimer
00428792 |. 8B73 30 mov esi, dword ptr [ebx+30]
00428795 |. 85F6 test esi, esi
00428797 |. 74 40 je short 004287D9
00428799 |. 807B 40 00 cmp byte ptr [ebx+40], 0
0042879D |. 74 3A je short 004287D9
0042879F |. 66:837B 3A 00 cmp word ptr [ebx+3A], 0
004287A4 74 33 je short 004287D9
004287A6 |. 6A 00 push 0 ; /Timerproc = NULL
004287A8 |. 56 push esi ; |Timeout
004287A9 6A 01 push 1
004287AB |. 8B43 34 mov eax, dword ptr [ebx+34] ; |
004287AE |. 50 push eax ; |hWnd
004287AF |. E8 24DFFDFF call <jmp.&user32.SetTimer> ; \SetTimer
004287B4 |. 85C0 test eax, eax
004287B6 |. 75 21 jnz short 004287D9
004287B8 |. 8D55 FC lea edx, dword ptr [ebp-4]
004287BB |. A1 D0AA4600 mov eax, dword ptr [46AAD0]
004287C0 |. E8 E3D1FDFF call 004059A8
004287C5 |. 8B4D FC mov ecx, dword ptr [ebp-4]
004287C8 |. B2 01 mov dl, 1
004287CA |. A1 F4154100 mov eax, dword ptr [4115F4]
004287CF |. E8 7C2BFEFF call 0040B350
004287D4 |. E8 AFB0FDFF call 00403888
004287D9 |> 33C0 xor eax, eax
004287DB |. 5A pop edx
004287DC |. 59 pop ecx
004287DD |. 59 pop ecx
004287DE |. 64:8910 mov dword ptr fs:[eax], edx
004287E1 |. 68 F6874200 push 004287F6
004287E6 |> 8D45 FC lea eax, dword ptr [ebp-4]
004287E9 |. E8 5EB6FDFF call 00403E4C
004287EE \. C3 retn
004287EF .^ E9 5CB0FDFF jmp 00403850
004287F4 .^ EB F0 jmp short 004287E6
004287F6 . 5E pop esi
004287F7 . 5B pop ebx
004287F8 . 59 pop ecx
004287F9 . 5D pop ebp
004287FA . C3 retn
这个函数居然先进行了KillTimer,估计KillTimer时也是调用这个函数了。我没有仔细跟踪程序,估计就是不管3721先KillTimer,然后判断一些标志,还没有Set过Timer就SetTimer,设置一些标志等等一些事情,我们关心的是Timer的处理程序,Timerproc = NULL,MSDN上说这样就会定时向程序的消息队列送WM_TIMER(113h)消息。好了,我们试试运气,查找->常量 113,嘿嘿,居然被我们发现了,典型的消息处理函数。
004286FC . 55 push ebp
004286FD . 8BEC mov ebp, esp
004286FF . 51 push ecx
00428700 . 53 push ebx
00428701 . 56 push esi
00428702 . 57 push edi
00428703 . 8BDA mov ebx, edx
00428705 . 8945 FC mov dword ptr [ebp-4], eax
00428708 . 8B33 mov esi, dword ptr [ebx]
0042870A . 81FE 13010000 cmp esi, 113 ; 被我们发现的位置
00428710 . 75 3F jnz short 00428751 ; 不是WM_TIMER就跳走,默认处理
00428712 . 33C0 xor eax, eax
00428714 . 55 push ebp
00428715 . 68 36874200 push 00428736
0042871A . 64:FF30 push dword ptr fs:[eax]
0042871D . 64:8920 mov dword ptr fs:[eax], esp
00428720 . 8B45 FC mov eax, dword ptr [ebp-4]
00428723 . 66:BE EFFF mov si, 0FFEF
00428727 . E8 CCABFDFF call 004032F8 ; 做坏事的函数
0042872C . 33C0 xor eax, eax
0042872E . 5A pop edx
0042872F . 59 pop ecx
00428730 . 59 pop ecx
00428731 . 64:8910 mov dword ptr fs:[eax], edx
00428734 . EB 33 jmp short 00428769
00428736 .^ E9 61AEFDFF jmp 0040359C
0042873B . A1 90A94600 mov eax, dword ptr [46A990]
00428740 . 8B00 mov eax, dword ptr [eax]
00428742 . 8B55 FC mov edx, dword ptr [ebp-4]
00428745 . E8 FEAE0200 call 00453648
0042874A . E8 B5B1FDFF call 00403904
0042874F . EB 18 jmp short 00428769
00428751 > 8B43 08 mov eax, dword ptr [ebx+8]
00428754 . 50 push eax ; /lParam
00428755 . 8B43 04 mov eax, dword ptr [ebx+4] ; |
00428758 . 50 push eax ; |wParam
00428759 . 56 push esi ; |Message
0042875A . 8B45 FC mov eax, dword ptr [ebp-4] ; |
0042875D . 8B40 34 mov eax, dword ptr [eax+34] ; |
00428760 . 50 push eax ; |hWnd
00428761 . E8 82DBFDFF call <jmp.&user32.DefWindowProcA> ; \DefWindowProcA
00428766 . 8943 0C mov dword ptr [ebx+C], eax
00428769 > 5F pop edi
0042876A . 5E pop esi
0042876B . 5B pop ebx
0042876C . 59 pop ecx
0042876D . 5D pop ebp
0042876E . C3 retn
我们跟进那个做坏事的Call,几次跋山涉水之后,发现做实事的是下面的函数。
0046868C /. 55 push ebp
0046868D |. 8BEC mov ebp, esp
0046868F |. 6A 00 push 0
00468691 |. 53 push ebx
00468692 |. 8BD8 mov ebx, eax
00468694 |. 33C0 xor eax, eax
00468696 |. 55 push ebp
00468697 |. 68 0C874600 push 0046870C
0046869C |. 64:FF30 push dword ptr fs:[eax]
0046869F |. 64:8920 mov dword ptr fs:[eax], esp
004686A2 |. FF0D 14BC4600 dec dword ptr [46BC14] ; 公共计数-1
004686A8 |. 8D55 FC lea edx, dword ptr [ebp-4]
004686AB |. A1 14BC4600 mov eax, dword ptr [46BC14]
004686B0 |. E8 AFF6F9FF call 00407D64 ; 计数转换成字符
004686B5 |. 8B55 FC mov edx, dword ptr [ebp-4]
004686B8 |. 8B83 00030000 mov eax, dword ptr [ebx+300]
004686BE |. E8 19B7FCFF call 00433DDC ; 设置按钮标题
004686C3 |. 833D 14BC4600>cmp dword ptr [46BC14], 0 ; 计数结束了吗?
004686CA 75 2A jnz short 004686F6 ; 没有就跳走返回
004686CC |. 33D2 xor edx, edx ; 计时结束继续向下
004686CE |. 8B83 1C030000 mov eax, dword ptr [ebx+31C]
004686D4 |. E8 2301FCFF call 004287FC ; 干掉计数器
004686D9 |. B2 01 mov dl, 1
004686DB |. 8B83 00030000 mov eax, dword ptr [ebx+300]
004686E1 |. 8B08 mov ecx, dword ptr [eax]
004686E3 |. FF51 64 call dword ptr [ecx+64] ; 恢复按钮可用
004686E6 |. BA 20874600 mov edx, 00468720
004686EB |. 8B83 00030000 mov eax, dword ptr [ebx+300]
004686F1 |. E8 E6B6FCFF call 00433DDC ; 设置按钮标题
004686F6 |> 33C0 xor eax, eax
004686F8 |. 5A pop edx
004686F9 |. 59 pop ecx
004686FA |. 59 pop ecx
004686FB |. 64:8910 mov dword ptr fs:[eax], edx
004686FE |. 68 13874600 push 00468713
00468703 |> 8D45 FC lea eax, dword ptr [ebp-4]
00468706 |. E8 41B7F9FF call 00403E4C
0046870B \. C3 retn
0046870C .^ E9 3FB1F9FF jmp 00403850
00468711 .^ EB F0 jmp short 00468703
00468713 . 5B pop ebx
00468714 . 59 pop ecx
00468715 . 5D pop ebp
00468716 . C3 retn
分析到这里,我们整理下如何干掉计数器的思路。第一种方案,在调用KillTimer和SetTimer函数(上面第一个)里直接调用 恢复按钮可用和设置按钮标题的函数,替换掉Timer。第二种方案,更改关键跳转,让其只要执行到Timer的消息处理函数,就恢复按钮可用。我想第一种方案应该比较简单适用,但是小菜我对delphi的 先 mov eax,dword ptr [ebx+XXX]再进行Call的方式不太了解,所以不得不转而求其次,使用第二种方案。
关键跳转通过分析很容易确定在:004686CA| 75 2A| jnz short 004686F6。将其Nop 或改成je均可。保存,看看效果。
可恶的是效果并不怎么样,我们还有1秒钟的延时。原因可以想到,就是触发WM_TIMER时间需要1秒钟。怎么办,同样两种方案,第一,将延时缩短为1毫秒,估计可能感觉不出延时。第二,可以在SetTimer之后,截获其他消息,让其处理,不再等到WM_TIMER触发。
由于第一种方案有种治标不治本的感觉,所以选择第二种方案,我们先看看他可不可行。下断00428770 和004286FC,重新载入程序。
我们首先断在了 00428770 处,F9,断在了004286FC处,观察堆栈,传来的是代号为1C的消息,F9,又一个1C,F9,113终于传来了。看来我们的第二种方案可行,动手。
0042870A 83FE 1C cmp esi, 1C ; ******原来的113改为1C
0042870D 90 nop
0042870E 90 nop
0042870F 90 nop
00428710 . 75 3F jnz short 00428751
00428712 . 33C0 xor eax, eax
00428714 . 55 push ebp
00428715 . 68 36874200 push 00428736
0042871A . 64:FF30 push dword ptr fs:[eax]
0042871D . 64:8920 mov dword ptr fs:[eax], esp
00428720 . 8B45 FC mov eax, dword ptr [ebp-4]
00428723 . 66:BE EFFF mov si, 0FFEF
00428727 . E8 CCABFDFF call 004032F8
0042872C . 33C0 xor eax, eax
0042872E . 5A pop edx
0042872F . 59 pop ecx
00428730 . 59 pop ecx
00428731 . 64:8910 mov dword ptr fs:[eax], edx
00428734 EB 1B jmp short 00428751 ; *******送回默认处理程序
00428736 .^ E9 61AEFDFF jmp 0040359C
0042873B . A1 90A94600 mov eax, dword ptr [46A990]
00428740 . 8B00 mov eax, dword ptr [eax]
00428742 . 8B55 FC mov edx, dword ptr [ebp-4]
00428745 . E8 FEAE0200 call 00453648
0042874A . E8 B5B1FDFF call 00403904
0042874F . EB 18 jmp short 00428769
00428751 > 8B43 08 mov eax, dword ptr [ebx+8]
00428754 . 50 push eax ; /lParam
00428755 . 8B43 04 mov eax, dword ptr [ebx+4] ; |
00428758 . 50 push eax ; |wParam
00428759 . 56 push esi ; |Message
0042875A . 8B45 FC mov eax, dword ptr [ebp-4] ; |
0042875D . 8B40 34 mov eax, dword ptr [eax+34] ; |
00428760 . 50 push eax ; |hWnd
00428761 . E8 82DBFDFF call <jmp.&user32.DefWindowProcA> ; \DefWindowProcA
保存,再运行。嗯,效果不错。代号1C的消息为WM_ACTIVATEAPP,可怜我的菜机了,每次要多执行一段代码了。看来有得必有失啊。
第四幕 Remove NAG
其实,这个做起来也有点复杂,因为NAG虽然只是个简单的MessageBox显示,却不是通过简单调用API来实现的。好像是自己写了个全新的MessageBox(只是猜测),所以定位到这段数据花了我很长一段时间。用翻山越岭,跋山涉水来形容绝对不过分。我无法用代码和文字来描述完整的过程,只大概说一下思路:
再按钮的消息处理函数中下断,然后一步一步的跟踪,看见Call就在Call的上下都下上断,防止跑飞,直至发现哪个Call产生这个MessageBox,再跟进跟踪。最终发现如下代码:
004501C5 8B45 FC mov eax, dword ptr [ebp-4]
004501C8 |. 33D2 xor edx, edx
004501CA |. 8990 4C020000 mov dword ptr [eax+24C], edx
004501D0 |> A1 DCBB4600 /mov eax, dword ptr [46BBDC]
004501D5 |. E8 DA310000 |call 004533B4
004501DA |. A1 DCBB4600 |mov eax, dword ptr [46BBDC]
004501DF |. 80B8 9C000000 00 |cmp byte ptr [eax+9C], 0
004501E6 |. 74 0F |je short 004501F7
004501E8 |. 8B45 FC |mov eax, dword ptr [ebp-4]
004501EB |. C780 4C020000 0200>|mov dword ptr [eax+24C], 2
004501F5 |. EB 14 |jmp short 0045020B
004501F7 |> 8B45 FC |mov eax, dword ptr [ebp-4]
004501FA |. 83B8 4C020000 00 |cmp dword ptr [eax+24C], 0
00450201 |. 74 08 |je short 0045020B
00450203 |. 8B45 FC |mov eax, dword ptr [ebp-4]
00450206 |. E8 1DFDFFFF |call 0044FF28
0045020B |> 8B45 FC |mov eax, dword ptr [ebp-4]
0045020E |. 8B80 4C020000 |mov eax, dword ptr [eax+24C]
00450214 |. 85C0 |test eax, eax
00450216 |.^ 74 B8 \je short 004501D0
00450218 |. 8945 F8 mov dword ptr [ebp-8], eax
0045021B |. 6A 00 push 0
就是上面这段代码产生了MessageBox的效果,原理我没能力发现。只要跳过这段代码就能过NAG了。更改后如下:
004501C5 /EB 54 jmp short 0045021B ;直接跳过即可
004501C7 |90 nop
004501C8 |. |33D2 xor edx, edx
至于程序的算法分析,busheler大侠已经分析得很透彻了,有兴趣地可以参考 http://bbs.pediy.com/showthread.php?threadid=20473 ,再此就不再分析了。
时间过得真快,又过了0点了,就到这里吧,附件中有原程序和我修改过的程序,有时间我会跟帖附上注册机。
另有分析不当之处,欢迎指出,谢谢。
--------------------------------------------------------------------------------
【版权声明】: 本文原创于看雪技术论坛, 转载请注明作者并保持文章的完整, 谢谢!
2008年01月19日 00:17:10
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!