[反汇编练习] 160个CrackMe之004.
本系列文章的目的是从一个没有任何经验的新手的角度(其实就是我自己),一步步尝试将160个CrackMe全部破解,如果可以,通过任何方式写出一个类似于注册机的东西。
其中,文章中按照如下逻辑编排(解决如下问题):
1、使用什么环境和工具
2、程序分析
3、思路分析和破解流程
4、注册机的探索
----------------------------------
提醒各位看客: 如果文章中的逻辑看不明白,那你一定是没有亲手操刀!OD中的跳转提示很强大,只要你跟踪了,不用怎么看代码就理解了!
----------------------------------
1、工具和环境:
WinXP SP3 + 52Pojie六周年纪念版OD + PEID + 汇编金手指。
160个CrackMe的打包文件。
下载地址: http://pan.baidu.com/s/1xUWOY 密码: jbnq
注:
1、Win7系统对于模块和程序开启了随机初始地址的功能,会给分析带来很大的负担,所以不建议使用Win7进行分析。
2、以上工具都是在52PoJie论坛下的原版程序,NOD32不报毒,个人承诺绝对不会进行任何和木马病毒相关内容。
2、程序分析:
想要破解一个程序,必须先了解这个程序。所以,在破解过程中,对最初程序的分析很重要,他可以帮助我们理解作者的目的和意图,特别是对于注册码的处理细节,从而方便我们反向跟踪和推导。
和上一节一样,打开CHM,选择第4个ajj,保存下来。运行程序,程序界面如下:
这似乎是一个标准的Name/Serial注册码方式,二话不说,来个伪码测试:
Name: 3333 Serial: 44445555
但是,但是什么提示也没有,只有一个鼠标提示,我点,我点,编辑框,灰色的小框框,我单击,我双击,KAO,啥提示也没有。
还是看看说明书吧:
前两天我和[CCG]的大哥Sun Bird兄闲聊时引出一个话题,
我要想想办法难为一下Sun Bird兄。
因此就用了两个半天的时间,作了一个小东东。
这个CKme与一般的软件注册过程不一样,它没有"确定"键,
当然CK这样的软件其实一点也不麻烦,没遇到过的朋友可要动动脑子了。 8)
另外这个CKme还作了一点别的手脚,不多说了,自己看着办吧。
这个软件是用Delphi编的,由于我刚学了一星期的Delphi,
有很多想法在这个小程序里没有实现,因此这个CKme应该算是比较简单的了。
如果你成功的注册了,请给我来封信好吗?谢谢!!!
还有你千万不要告诉我你只用了2分钟就搞定了,如果是这样我就。。8~~~(
ajj
2000/08/30
好吧,这位大哥再给我们玩猜谜呢!
3、思路分析和破解流程:
这个程序就像作者说的,诡异的不知道到底是那里出发判断,无论点什么地方都没有任何提示。查一下壳:Delphi的,没有加壳。对Delphi不了解,没关系,我们先尝试熟悉的程序的方式看看是否能行。
个人比较擅长VC,先按照VC思路思考一下程序可能会通过什么方式触发检测序列号动作:
1、要进行序列号检测,必须的获取Name/Serial的文本,在VC中WM_GETTEXT消息用来获取文本使用,我们可以通过对Edit控件下消息断点,然后看看是否能得到一些信息。操作:菜单->View->Windows,很容易就看到了标题,Class名称为TForm1,右键Message Breakpoint on callproc,找到WM_GetText消息,确定。这时无论我们怎么尝试都无法断下。没办法,对delphi不了解,再试试别的。
2、在第一个的基础上尝试WM_KEYDOWN/WM_KEYUP消息,API断点(GetWindowTextW/A),发现都无法获得任何信息。
尝试到这里,只说明了一个问题,Delphi并不是简单地封装了API函数,所以我们无法通过这方面来进行筛选和拦截。
退一步,我们的目的是破解这个程序,所以只要能够找到和关键跳转相关的东西就行。进论坛,搜了一大桶,原来除了堆栈找法,还有很多看起来很小白的方法,比如最碰运气的【字符串查找】,如果程序中有很多和流程相关的字符串,我们就可以根据字符串的意思猜测程序的流程。Ctrl+E(E图标),选中CKme.exe模块,右键->Follow entry,这样我们就在主程序模块,然后右键->中文搜索引擎->智能搜索,哈哈哈,终于露出狐狸的小尾巴了!我们发现有一个很明显的中文字符串【恭喜恭喜!注册成功】,二话不说,跟进去。
0045803B /75 76 jnz short 004580B3 ; // 关键跳,爆破这里就可以了 0045803D |. |33DB xor ebx,ebx 0045803F |> |8D55 E4 /lea edx,[local.7] 00458042 |. |8B86 D4020000 |mov eax,dword ptr ds:[esi+0x2D4] 00458048 |. |E8 FBB2FCFF |call 00423348 0045804D |. |8B45 E4 |mov eax,[local.7] 00458050 |. |E8 27BBFAFF |call 00403B7C 00458055 |. |83C0 03 |add eax,0x3 00458058 |. |8D55 E8 |lea edx,[local.6] 0045805B |. |E8 A4FAFAFF |call 00407B04 00458060 |. |FF75 E8 |push [local.6] 00458063 |. |8D55 E0 |lea edx,[local.8] 00458066 |. |8B86 D4020000 |mov eax,dword ptr ds:[esi+0x2D4] 0045806C |. |E8 D7B2FCFF |call 00423348 00458071 |. |FF75 E0 |push [local.8] 00458074 |. |8D55 DC |lea edx,[local.9] 00458077 |. |8BC3 |mov eax,ebx 00458079 |. |E8 86FAFAFF |call 00407B04 0045807E |. |FF75 DC |push [local.9] 00458081 |. |8D45 FC |lea eax,[local.1] 00458084 |. |BA 03000000 |mov edx,0x3 00458089 |. |E8 AEBBFAFF |call 00403C3C 0045808E |. |43 |inc ebx 0045808F |. |83FB 13 |cmp ebx,0x13 00458092 |.^|75 AB \jnz short 0045803F 00458094 |. |33D2 xor edx,edx 00458096 |. |8B86 F0020000 mov eax,dword ptr ds:[esi+0x2F0] 0045809C |. |E8 BFB1FCFF call 00423260 004580A1 |. |A1 20B84500 mov eax,dword ptr ds:[0x45B820] 004580A6 |. |83C0 70 add eax,0x70 004580A9 |. |BA 14814500 mov edx,00458114 ; 恭喜恭喜!注册成功 004580AE |. |E8 9DB8FAFF call 00403950
到CALL的地方后,向上查看代码,很容易就找到了两个JNZ,最近的那个一直在循环,不会跳过中文的提示,而最上面的那个jnz short 004580B3 一眼就能看到它会跳出正确提示,SO,爆破很easy啦!选中这个JNZ,右键->Binary->Fill with NOPs. 随意输入Name/Serial试试,OK,非常完美,收工!
4、注册机的探索:
我们的目的不单单是爆破他,尽量算出注册码,SO,找到代码头,输入伪码:
Name: 112233 Serial: 44445555
下断,F8分析:
00457FB8 /. 55 push ebp ; 00A053D8 00457FB9 |. 8BEC mov ebp,esp 00457FBB |. B9 04000000 mov ecx,0x4 00457FC0 |> 6A 00 /push 0x0 00457FC2 |. 6A 00 |push 0x0 00457FC4 |. 49 |dec ecx 00457FC5 |.^ 75 F9 \jnz short 00457FC0 ; // 毫无意义地循环了4次 00457FC7 |. 51 push ecx 00457FC8 |. 53 push ebx 00457FC9 |. 56 push esi ; //00A053D8 00457FCA |. 8BF0 mov esi,eax ; // esi=00A019CC=纹E 00457FCC |. 33C0 xor eax,eax 00457FCE |. 55 push ebp 00457FCF |. 68 FD804500 push 004580FD 00457FD4 |. 64:FF30 push dword ptr fs:[eax] 00457FD7 |. 64:8920 mov dword ptr fs:[eax],esp 00457FDA |. 33DB xor ebx,ebx 00457FDC |> 8D55 F4 /lea edx,[local.3] 00457FDF |. 8B86 D4020000 |mov eax,dword ptr ds:[esi+0x2D4] 00457FE5 |. E8 5EB3FCFF |call 00423348 00457FEA |. 8B45 F4 |mov eax,[local.3] ; // eax=112233 字符串地址 00457FED |. E8 8ABBFAFF |call 00403B7C 00457FF2 |. 83C0 1E |add eax,0x1E ; // eax=6+1E=0x24 00457FF5 |. 8D55 F8 |lea edx,[local.2] 00457FF8 |. E8 07FBFAFF |call 00407B04 ; // 修改了edx地址处的值为36 00457FFD |. FF75 F8 |push [local.2] ; // ecx=0x24 00458000 |. 8D55 F0 |lea edx,[local.4] 00458003 |. 8B86 D4020000 |mov eax,dword ptr ds:[esi+0x2D4] 00458009 |. E8 3AB3FCFF |call 00423348 0045800E |. FF75 F0 |push [local.4] ; // ss=112233 00458011 |. 8D55 EC |lea edx,[local.5] 00458014 |. 8BC3 |mov eax,ebx 00458016 |. E8 E9FAFAFF |call 00407B04 0045801B |. FF75 EC |push [local.5] 0045801E |. 8D45 FC |lea eax,[local.1] 00458021 |. BA 03000000 |mov edx,0x3 00458026 |. E8 11BCFAFF |call 00403C3C 0045802B |. 43 |inc ebx ; ebx=0++ 0045802C |. 83FB 13 |cmp ebx,0x13 ; // 不知道为什么比较了0x13次 0045802F |.^ 75 AB \jnz short 00457FDC ; // 这个形成了一个xxName18的字符串,3611223318 00458031 |. 81BE 0C030000>cmp dword ptr ds:[esi+0x30C],0x85 ; // esi是关键点 0045803B 75 76 jnz short 004580B3 ; // 关键跳,爆破这里就可以了 0045803D |. 33DB xor ebx,ebx 0045803F |> 8D55 E4 /lea edx,[local.7] 00458042 |. 8B86 D4020000 |mov eax,dword ptr ds:[esi+0x2D4] 00458048 |. E8 FBB2FCFF |call 00423348 0045804D |. 8B45 E4 |mov eax,[local.7] 00458050 |. E8 27BBFAFF |call 00403B7C 00458055 |. 83C0 03 |add eax,0x3 00458058 |. 8D55 E8 |lea edx,[local.6] 0045805B |. E8 A4FAFAFF |call 00407B04 00458060 |. FF75 E8 |push [local.6] 00458063 |. 8D55 E0 |lea edx,[local.8] 00458066 |. 8B86 D4020000 |mov eax,dword ptr ds:[esi+0x2D4] 0045806C |. E8 D7B2FCFF |call 00423348 00458071 |. FF75 E0 |push [local.8] 00458074 |. 8D55 DC |lea edx,[local.9] 00458077 |. 8BC3 |mov eax,ebx 00458079 |. E8 86FAFAFF |call 00407B04 0045807E |. FF75 DC |push [local.9] 00458081 |. 8D45 FC |lea eax,[local.1] 00458084 |. BA 03000000 |mov edx,0x3 00458089 |. E8 AEBBFAFF |call 00403C3C 0045808E |. 43 |inc ebx 0045808F |. 83FB 13 |cmp ebx,0x13 00458092 |.^ 75 AB \jnz short 0045803F 00458094 |. 33D2 xor edx,edx 00458096 |. 8B86 F0020000 mov eax,dword ptr ds:[esi+0x2F0] 0045809C |. E8 BFB1FCFF call 00423260 004580A1 |. A1 20B84500 mov eax,dword ptr ds:[0x45B820] 004580A6 |. 83C0 70 add eax,0x70 004580A9 |. BA 14814500 mov edx,00458114 ; 恭喜恭喜!注册成功 004580AE |. E8 9DB8FAFF call 00403950 004580B3 |> 33C0 xor eax,eax
这段代码对Name进行了处理,在堆栈中得到了一个类似3611223318的字符串,但是比较的时候使用的是cmp dword ptr ds:[esi+0x30C],0x85,esi+0x30C地址处的值才是真正影响结果的,翻看代码发现,没有任何地方修改了这个值,没办法,重新断在循环头部,db [esi+0x30C],对内容下内容写入断点,取消其他断点,F9运行,尝试。。。
悲剧了,什么也找不到。
多次尝试此代码段的上层代码和跟踪内部CALL代码,无法找到有用的信息。实在没办法了,继续求救大神吧!
搜索发现了两点有用的信息:
1、看雪论坛找到了一个正确的Name/Serial。Name: findlakes Serial: 黑头Sun Bird14dseloffc-012-OKfindlakes
2、OD对于Delphi程序确实有些乏力,反汇编Delphi有更好的软件Dede。
下面我们尝试使用Dede反编译它(工具下载链接里有):
如图,在窗体选项中发现注册码编辑框TEdit2有OnKeyUp事件chkcode。
在过程选项中,双击chkcode查看代码:
代码如下:
00457C40 55 push ebp 00457C41 8BEC mov ebp, esp 00457C43 51 push ecx 00457C44 B905000000 mov ecx, $00000005 00457C49 6A00 push $00 00457C4B 6A00 push $00 00457C4D 49 dec ecx 00457C4E 75F9 jnz 00457C49 00457C50 51 push ecx 00457C51 874DFC xchg [ebp-$04], ecx 00457C54 53 push ebx 00457C55 56 push esi 00457C56 8BD8 mov ebx, eax 00457C58 33C0 xor eax, eax 00457C5A 55 push ebp 00457C5B 683D7E4500 push $00457E3D ...
OK,关闭Dede,我们在OD中加载它:
Ctrl+G 转到开头地址: 00457C40,向上找到段头,开始F8分析:
00457C1C . 53 75 6E 20 4>ascii "Sun Bird",0 00457C25 00 db 00 00457C26 00 db 00 00457C27 00 db 00 00457C28 . FFFFFFFF dd FFFFFFFF 00457C2C . 0F000000 dd 0000000F 00457C30 . 64 73 65 6C 6>ascii "dseloffc-012-OK",0 00457C40 /. 55 push ebp ; // 这里是头部,下断 00457C41 |. 8BEC mov ebp,esp 00457C43 |. 51 push ecx 00457C44 |. B9 05000000 mov ecx,0x5 00457C49 |> 6A 00 /push 0x0 00457C4B |. 6A 00 |push 0x0 00457C4D |. 49 |dec ecx 00457C4E |.^ 75 F9 \jnz short 00457C49 ; // 无意义的循环 00457C50 |. 51 push ecx 00457C51 |. 874D FC xchg [local.1],ecx 00457C54 |. 53 push ebx 00457C55 |. 56 push esi 00457C56 |. 8BD8 mov ebx,eax 00457C58 |. 33C0 xor eax,eax 00457C5A |. 55 push ebp 00457C5B |. 68 3D7E4500 push 00457E3D 00457C60 |. 64:FF30 push dword ptr fs:[eax] 00457C63 |. 64:8920 mov dword ptr fs:[eax],esp 00457C66 |. 8BB3 F8020000 mov esi,dword ptr ds:[ebx+0x2F8] 00457C6C |. 83C6 05 add esi,0x5 00457C6F |. FFB3 10030000 push dword ptr ds:[ebx+0x310] ; // (ASCII "黑头Sun Bird") 00457C75 |. 8D55 F8 lea edx,[local.2] 00457C78 |. 8BC6 mov eax,esi 00457C7A |. E8 85FEFAFF call 00407B04 00457C7F |. FF75 F8 push [local.2] ; // 10 00457C82 |. FFB3 14030000 push dword ptr ds:[ebx+0x314] ; // (ASCII "dseloffc-012-OK") 00457C88 |. 8D55 F4 lea edx,[local.3] 00457C8B |. 8B83 D4020000 mov eax,dword ptr ds:[ebx+0x2D4] 00457C91 |. E8 B2B6FCFF call 00423348 00457C96 |. FF75 F4 push [local.3] ; // ASCII bbdxf 00457C99 |. 8D83 18030000 lea eax,dword ptr ds:[ebx+0x318] 00457C9F |. BA 04000000 mov edx,0x4 00457CA4 |. E8 93BFFAFF call 00403C3C 00457CA9 |. 33D2 xor edx,edx 00457CAB |. 8B83 F4020000 mov eax,dword ptr ds:[ebx+0x2F4] 00457CB1 |. E8 AAB5FCFF call 00423260 00457CB6 |. 8B93 18030000 mov edx,dword ptr ds:[ebx+0x318] ; //(ASCII "黑头Sun Bird10dseloffc-012-OKbbdxf") 00457CBC |. 8B83 F4020000 mov eax,dword ptr ds:[ebx+0x2F4] 00457CC2 |. E8 B1B6FCFF call 00423378 ; // 根据我们之前查找的资料,上面的字符串其实就是注册码了 00457CC7 |. 33F6 xor esi,esi 00457CC9 |> 8D55 EC /lea edx,[local.5] ; // 0x13 次不知道干什么的循环 00457CCC |. 8B83 D4020000 |mov eax,dword ptr ds:[ebx+0x2D4] 00457CD2 |. E8 71B6FCFF |call 00423348 00457CD7 |. 8B45 EC |mov eax,[local.5] 00457CDA |. E8 9DBEFAFF |call 00403B7C 00457CDF |. 83C0 03 |add eax,0x3 00457CE2 |. 8D55 F0 |lea edx,[local.4] 00457CE5 |. E8 1AFEFAFF |call 00407B04 00457CEA |. FF75 F0 |push [local.4] 00457CED |. 8D55 E8 |lea edx,[local.6] 00457CF0 |. 8B83 D4020000 |mov eax,dword ptr ds:[ebx+0x2D4] 00457CF6 |. E8 4DB6FCFF |call 00423348 00457CFB |. FF75 E8 |push [local.6] 00457CFE |. 8D55 E4 |lea edx,[local.7] 00457D01 |. 8BC6 |mov eax,esi 00457D03 |. E8 FCFDFAFF |call 00407B04 00457D08 |. FF75 E4 |push [local.7] 00457D0B |. 8D45 FC |lea eax,[local.1] 00457D0E |. BA 03000000 |mov edx,0x3 00457D13 |. E8 24BFFAFF |call 00403C3C 00457D18 |. 46 |inc esi 00457D19 |. 83FE 13 |cmp esi,0x13 00457D1C |.^ 75 AB \jnz short 00457CC9 00457D1E |. 8D55 E0 lea edx,[local.8] 00457D21 |. 8B83 D8020000 mov eax,dword ptr ds:[ebx+0x2D8] 00457D27 |. E8 1CB6FCFF call 00423348
实在是被Delphi折磨的不能行了,注册码很简单,特别是根据开头的几个ANSI能够看出来,他就是固定的字符串加上我们的Name,即"黑头Sun Bird10dseloffc-012-OK"+Name。随便怎么搞都没问题。
总结一下:这个CrackMe就像作者说的,更多的算是一个小游戏,再加上Delphi不熟,做完之后实在感到有些鸡肋,不过,相信,所有的付出都会有收获的,只是时间的问题。加油!
BY 笨笨D幸福
[反汇编练习] 160个CrackMe之004