44018723 发表于 2014-6-12 20:29

[反汇编练习] 160个CrackMe之004

本帖最后由 44018723 于 2014-6-12 22:53 编辑


[反汇编练习] 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,啥提示也没有。
还是看看说明书吧:
前两天我和的大哥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,
00458042|. |8B86 D4020000 |mov eax,dword ptr ds:
00458048|. |E8 FBB2FCFF   |call 00423348
0045804D|. |8B45 E4       |mov eax,
00458050|. |E8 27BBFAFF   |call 00403B7C
00458055|. |83C0 03       |add eax,0x3
00458058|. |8D55 E8       |lea edx,
0045805B|. |E8 A4FAFAFF   |call 00407B04
00458060|. |FF75 E8       |push
00458063|. |8D55 E0       |lea edx,
00458066|. |8B86 D4020000 |mov eax,dword ptr ds:
0045806C|. |E8 D7B2FCFF   |call 00423348
00458071|. |FF75 E0       |push
00458074|. |8D55 DC       |lea edx,
00458077|. |8BC3          |mov eax,ebx
00458079|. |E8 86FAFAFF   |call 00407B04
0045807E|. |FF75 DC       |push
00458081|. |8D45 FC       |lea eax,
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:
0045809C|. |E8 BFB1FCFF   call 00423260
004580A1|. |A1 20B84500   mov eax,dword ptr ds:
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:
00457FD7|.64:8920       mov dword ptr fs:,esp
00457FDA|.33DB          xor ebx,ebx
00457FDC|>8D55 F4       /lea edx,
00457FDF|.8B86 D4020000 |mov eax,dword ptr ds:
00457FE5|.E8 5EB3FCFF   |call 00423348
00457FEA|.8B45 F4       |mov eax,                         ;// eax=112233 字符串地址
00457FED|.E8 8ABBFAFF   |call 00403B7C
00457FF2|.83C0 1E       |add eax,0x1E                              ;// eax=6+1E=0x24
00457FF5|.8D55 F8       |lea edx,
00457FF8|.E8 07FBFAFF   |call 00407B04                           ;// 修改了edx地址处的值为36
00457FFD|.FF75 F8       |push                             ;// ecx=0x24
00458000|.8D55 F0       |lea edx,
00458003|.8B86 D4020000 |mov eax,dword ptr ds:
00458009|.E8 3AB3FCFF   |call 00423348
0045800E|.FF75 F0       |push                             ;// ss=112233
00458011|.8D55 EC       |lea edx,
00458014|.8BC3          |mov eax,ebx
00458016|.E8 E9FAFAFF   |call 00407B04
0045801B|.FF75 EC       |push
0045801E|.8D45 FC       |lea eax,
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:,0x85          ;// esi是关键点
0045803B      75 76         jnz short 004580B3                         ;// 关键跳,爆破这里就可以了
0045803D|.33DB          xor ebx,ebx
0045803F|>8D55 E4       /lea edx,
00458042|.8B86 D4020000 |mov eax,dword ptr ds:
00458048|.E8 FBB2FCFF   |call 00423348
0045804D|.8B45 E4       |mov eax,
00458050|.E8 27BBFAFF   |call 00403B7C
00458055|.83C0 03       |add eax,0x3
00458058|.8D55 E8       |lea edx,
0045805B|.E8 A4FAFAFF   |call 00407B04
00458060|.FF75 E8       |push
00458063|.8D55 E0       |lea edx,
00458066|.8B86 D4020000 |mov eax,dword ptr ds:
0045806C|.E8 D7B2FCFF   |call 00423348
00458071|.FF75 E0       |push
00458074|.8D55 DC       |lea edx,
00458077|.8BC3          |mov eax,ebx
00458079|.E8 86FAFAFF   |call 00407B04
0045807E|.FF75 DC       |push
00458081|.8D45 FC       |lea eax,
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:
0045809C|.E8 BFB1FCFF   call 00423260
004580A1|.A1 20B84500   mov eax,dword ptr ds:
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:,0x85,esi+0x30C地址处的值才是真正影响结果的,翻看代码发现,没有任何地方修改了这个值,没办法,重新断在循环头部,db ,对内容下内容写入断点,取消其他断点,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    , 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 ,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:
00457C63|.64:8920       mov dword ptr fs:,esp
00457C66|.8BB3 F8020000 mov esi,dword ptr ds:
00457C6C|.83C6 05       add esi,0x5
00457C6F|.FFB3 10030000 push dword ptr ds:            ;// (ASCII "黑头Sun Bird")
00457C75|.8D55 F8       lea edx,
00457C78|.8BC6          mov eax,esi
00457C7A|.E8 85FEFAFF   call 00407B04
00457C7F|.FF75 F8       push                            ;// 10
00457C82|.FFB3 14030000 push dword ptr ds:            ;//(ASCII "dseloffc-012-OK")
00457C88|.8D55 F4       lea edx,
00457C8B|.8B83 D4020000 mov eax,dword ptr ds:
00457C91|.E8 B2B6FCFF   call 00423348
00457C96|.FF75 F4       push                            ;// ASCII bbdxf
00457C99|.8D83 18030000 lea eax,dword ptr ds:
00457C9F|.BA 04000000   mov edx,0x4
00457CA4|.E8 93BFFAFF   call 00403C3C
00457CA9|.33D2          xor edx,edx
00457CAB|.8B83 F4020000 mov eax,dword ptr ds:
00457CB1|.E8 AAB5FCFF   call 00423260
00457CB6|.8B93 18030000 mov edx,dword ptr ds:         ;//(ASCII "黑头Sun Bird10dseloffc-012-OKbbdxf")
00457CBC|.8B83 F4020000 mov eax,dword ptr ds:
00457CC2|.E8 B1B6FCFF   call 00423378                            ;// 根据我们之前查找的资料,上面的字符串其实就是注册码了
00457CC7|.33F6          xor esi,esi
00457CC9|>8D55 EC       /lea edx,                     ;// 0x13 次不知道干什么的循环
00457CCC|.8B83 D4020000 |mov eax,dword ptr ds:
00457CD2|.E8 71B6FCFF   |call 00423348
00457CD7|.8B45 EC       |mov eax,
00457CDA|.E8 9DBEFAFF   |call 00403B7C
00457CDF|.83C0 03       |add eax,0x3
00457CE2|.8D55 F0       |lea edx,
00457CE5|.E8 1AFEFAFF   |call 00407B04
00457CEA|.FF75 F0       |push
00457CED|.8D55 E8       |lea edx,
00457CF0|.8B83 D4020000 |mov eax,dword ptr ds:
00457CF6|.E8 4DB6FCFF   |call 00423348
00457CFB|.FF75 E8       |push
00457CFE|.8D55 E4       |lea edx,
00457D01|.8BC6          |mov eax,esi
00457D03|.E8 FCFDFAFF   |call 00407B04
00457D08|.FF75 E4       |push
00457D0B|.8D45 FC       |lea eax,
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,
00457D21|.8B83 D8020000 mov eax,dword ptr ds:
00457D27|.E8 1CB6FCFF   call 00423348

实在是被Delphi折磨的不能行了,注册码很简单,特别是根据开头的几个ANSI能够看出来,他就是固定的字符串加上我们的Name,即"黑头Sun Bird10dseloffc-012-OK"+Name。随便怎么搞都没问题。
总结一下:这个CrackMe就像作者说的,更多的算是一个小游戏,再加上Delphi不熟,做完之后实在感到有些鸡肋,不过,相信,所有的付出都会有收获的,只是时间的问题。加油!

BY笨笨D幸福





Pnmker 发表于 2015-5-23 00:42

补充两句,楼主可能没有把程序的诡异之处说明白,就是如果不是爆破程序的话,那么必须得满足ds:的值为0x85,但是程序是在什么地方设置的呢?
                                       
要能真正理解ajj的意图,我觉得还是得必须把上述问题搞清楚!

经过我跟踪代码得出以下结果:(以下寄存器esi和ebx的值相等,均为009519A0)
首先在输入用户名的时候程序会同时计算出正确的注册码,注册码的计算如楼主所揭示;
(不过有一点小更正,位于"黑头SunBird"和"dseloffc-012-OK"间的数字不是固定为10,而是Name的长度+5,例如我的用户名pnmker,注册码就是 黑头Sun Bird11dseloffc-012-OKpnmker)
                                       
然后,在输入注册码的时候同时会将用户输入的注册码与正确的注册码进行比较,如果相同的话会将ds:的值设为0x3E
                                       
接着,用户输入完注册码后,点击图片框,会触发最终的验证,验证通过就可以一睹靓照了。其实这里点击图片框的时候也需要注意,首先要双击一次,然后再单击一次。
为什么要这样子呢?(这个问题,9楼的仁兄也发现了,点击一次图片是不行的,但也不需要点击很多次,只需双击一次,然后再单击一次。)
可能所谓的诡异之处就在这里吧!这是因为:
第一次双击,程序只是将输入验证码时设置的0x3E再次设置为0x85
                                       
第二次单击,此时就到了楼主提到的爆破点,此时如果是输入的是正确的验证码的话ds:的值已为0x85,不需爆破也可以一睹朱茵芳容。

manbajie 发表于 2014-6-12 20:45

反汇编要好学习一下的

刘宏伟大人丶 发表于 2014-6-12 20:32

44018723 发表于 2014-6-12 20:30

本帖最后由 44018723 于 2014-6-12 20:47 编辑

{:17_1055:}排版真难!!
版主,我只想说,不管是不是我的原因,这编辑器真烂,我都排版了4遍,还是这德行,你还想让我如何!!!!!!!!!!!

小意工作室 发表于 2014-6-13 08:42

keyrratuff 发表于 2014-6-18 02:31

我是一直跟随你的哦,楼主~

cdweng 发表于 2014-6-19 22:23

跟着楼主学破160

dych1688 发表于 2014-6-29 21:51

楼主厉害啊,底子很不错

shuguang 发表于 2014-6-29 23:37

搞不懂这个程序为什么输入正确的注册码都要点很多次才能出图片。

buhudu 发表于 2015-2-21 19:16

过来学习一下
页: [1] 2 3
查看完整版本: [反汇编练习] 160个CrackMe之004