Pnmker 发表于 2015-5-24 03:01

160个CrackMe练手之005

本帖最后由 Pnmker 于 2015-5-24 03:39 编辑

       原本不想写这篇破文,没有多少兴奋点,也因为已经有道友发了相关的破文,但转念一想每个人都有是新手的时候,(当然我现在也是一个新手,160个才练到第5个呢),新手想找些资料或者大牛来帮忙解惑却怎么也解决不了的那种走投无路的感觉,我想每个成长起来的人都曾经有过,所以谨以此文献给那些奔走在志向成为大牛的新手们。大牛们如果觉得写得不好就直接无视吧。在我跟踪005这个CM的时候,我心里一直在默念一句话:“ajj是不是疯了,弄了这么一个操蛋的注册验证流程!”。当然如果只是爆破那非常简单,然而我们最终的目标是要Keygen It。尽管流程我弄明白了,但没有写keygen,就是因为那个操蛋的流程我觉得还是不要在Keygen It上浪费精力了。如果有谁有兴趣写,写出了可以分享下给我哦。       开始之前,我觉得还是有必要把一些相关的内容和链接留在这里。ajj的004和005这两个CM有某些地方可以相互借鉴一些,也都已经有破文发布,希望大家可以都学习一下:                         004破文链接:http://www.52pojie.cn/thread-264819-1-1.html                         005破文链接:http://www.52pojie.cn/thread-264914-1-1.html       44018723兄果然神通,160个CM大概都已经研究过了吧,很多也已经发了破文,有兴趣的话可以关注下44018723兄。上面两个链接就是44018723兄发表的关于ajj的两个CM的破文,其中004我在那篇文章的12楼又做了一些补充。这篇文章也算是对005的一个补充吧。下面进入正题.       首先,我先给出005注册验证的那个操蛋流程,真的是不费一番心思真不好搞出来。
第一步:新建一个路径为X:\ajj.126.c0m\j\o\j\o\ok.txt的文本文件,文件内容的二进制为             20 61 6A 6A D0 B4 B5 C4 43 4B 6D 65D5 E6 C0 C3 21 FF FF,给出二进制的原因主要是因为后面两个字符FF FF打文本打不出来,这句话的文本显示为“ajj写的CKme真烂!             这个文件的作用就是会在界面中多显示出一个输入框(下面记为Edit2),但是初始是禁用的,输不了东西。第二步:打开程序,初始化完成之后,鼠标右键点击“注册”按钮5次。记住一定是鼠标右键,而且必须是点击5次,如果点错不要找我哦;第三步:在显示图片的图片框中双击没有图片显示的地方;            这一步完成之后,输入框Edit2就可以输入内容了。第四步:输入注册名和Edit2,。这两个输入的内容也是有要求的,注册名长度必须是3的倍数,Edit2输入的内容长度必须为8,且第2个字符为’_’,第6个字符为’,’。             我在跟踪的时候分别输入的”trisinker”和”1_345,78” 第五步:输入完成之后,双击Edit2;第六步:在图片3(“性相近“)出现时,移动鼠标从界面的右下角外部进入程序界面;第七步:在图片2(“性本善“)出现时,移动鼠标从界面的左下角外部进入程序界面;第八步:在图片 4(“习相远“)出现时,鼠标左键点击1次图片4,右键点击8次图片4.             注意这是最后一步,可能每台机器的状况都不一样。请勿按照上面说的点击。            其实这一步中点击图片1(“人之初“),图片2、图片3、图片4哪些图片,鼠标左键和右键各点击多少次,这个是一个很复杂的算法。         决定点击方式的参数就是输入的两个字符串,以及程序所在磁盘的剩余磁盘空间,在第五步的双击Edit2时候会计算出一个值存储在ds:中,         根据这个值就可以知道如何点击图片。

好了,只要做完这八步,就可以成功完成注册了,这时候“注册“按钮的文本会变为”注册了“,至于ajj在程序附带的文档中说图片会有轻微变化,我眼小没看出来。怎么样,这个注册验证够变态了吧,下面我们就开始分析为什么要这样一步步地去操作,以及该如何去操作(主要指第八步)。建议大家先看一下上面列出来的44018723兄的005破文,有些操作在这里我就不再过多浪费时间了,比如脱壳。
先用OD加载程序后,使用中文搜索引擎搜索到下面这段代码(其实这段代码为定时器2的定时处理函数,下称Timer2Timer):004473E4   .53            push ebx                                 ;Timer2Timer
004473E5   .8BD8          mov ebx,eax
004473E7   .81BB 04030000>cmp dword ptr ds:,0xC34
004473F1   .0F84 88000000 je CKme002.0044747F
004473F7   .81BB 08030000>cmp dword ptr ds:,0x230D
00447401   .74 7C         je short CKme002.0044747F
00447403   .81BB 10030000>cmp dword ptr ds:,0xF94
0044740D   .75 70         jnz short CKme002.0044747F
0044740F   .8B83 18030000 mov eax,dword ptr ds:
00447415   .3B83 14030000 cmp eax,dword ptr ds:
0044741B   .75 62         jnz short CKme002.0044747F
0044741D   .81BB 1C030000>cmp dword ptr ds:,0x3E7
00447427   .74 56         je short CKme002.0044747F
00447429   .33D2          xor edx,edx                              ;ntdll.KiFastSystemCallRet
0044742B   .8B83 D8020000 mov eax,dword ptr ds:
00447431   .8B08          mov ecx,dword ptr ds:
00447433   .FF51 5C       call dword ptr ds:
00447436   .33D2          xor edx,edx                              ;ntdll.KiFastSystemCallRet
00447438   .8B83 DC020000 mov eax,dword ptr ds:
0044743E   .8B08          mov ecx,dword ptr ds:
00447440   .FF51 5C       call dword ptr ds:
00447443   .33D2          xor edx,edx                              ;ntdll.KiFastSystemCallRet
00447445   .8B83 E0020000 mov eax,dword ptr ds:
0044744B   .8B08          mov ecx,dword ptr ds:
0044744D   .FF51 5C       call dword ptr ds:
00447450   .33D2          xor edx,edx                              ;ntdll.KiFastSystemCallRet
00447452   .8B83 E4020000 mov eax,dword ptr ds:
00447458   .8B08          mov ecx,dword ptr ds:
0044745D   .A1 A8984400   mov eax,dword ptr ds:
00447462   .83C0 70       add eax,0x70
00447465   .BA 8C744400   mov edx,CKme002.0044748C               ;厉害厉害真厉害!佩服佩服真佩服!!
0044746A   .E8 EDC4FBFF   call CKme002.0040395C
0044746F   .BA B8744400   mov edx,CKme002.004474B8               ;注册了
00447474   .8B83 EC020000 mov eax,dword ptr ds:
0044747A   .E8 3DCCFDFF   call CKme002.004240BC
0044747F   >5B            pop ebx                                  ;kernel32.7C817077
00447480   .C3            retn      

正如44018723兄所说这段代码就是爆破的用武之地,但这里我们并不是要爆破,所以就要解决44018723兄所没能解决了的问题,就是如何找到这些ds:(第一步)、ds:(第二步、第三步)、ds:(第六步、第七步)、ds:(第8步)、ds:(第六步、第七步)内存地址是在哪里进行赋值的。处理这件事,我个人觉得没有什么好的办法,至少对于还是新手的我来说我没有找到什么好办法,考验的主要是耐心,没有技巧。唯一能做的一件事就是查看所有的反汇编代码把这些地址统统揪出来,然后仔细的分析在哪里可能会完成赋值操作,以及要完成所要的赋值操作要满足什么条件。在这里我再插入一段可能对于破Delphi程序比较适用的方法。我们从上面找到的那段爆破关键代码段的第一行地址004473E4,在OD中选中这一行然后右键à查看参考à选定命令,这时候就会出现下面的结果:                                                         双击00446BB5那一行,这时候就会看到这个地址附近都是类似的代码:00446AE2      0C            db 0C
00446AE3      00            db 00
00446AE4      11            db 11
00446AE5      00            db 00
00446AE6      1C6C4400      dd CKme002.00446C1C
00446AEA   .0A            db 0A
00446AEB   .46 6F 72 6D 4>ascii "FormCreate"
00446AF5      12            db 12
00446AF6      00            db 00
00446AF7      286E4400      dd CKme002.00446E28
00446AFB   .0B            db 0B
00446AFC   .54 69 6D 65 7>ascii "Timer1Timer"
00446B07      17            db 17
00446B08      00            db 00
00446B09      A46F4400      dd CKme002.00446FA4
00446B0D   .10            db 10
00446B0E   .42 75 74 74 6>ascii "Button1MouseDown"
00446B1E      15            db 15
00446B1F      00            db 00
00446B20      DC6F4400      dd CKme002.00446FDC
00446B24   .0E            db 0E
00446B25   .50 61 6E 65 6>ascii "Panel1DblClick"
00446B33      14            db 14
00446B34      00            db 00
00446B35      F86F4400      dd CKme002.00446FF8
00446B39   .0D            db 0D
00446B3A   .45 64 69 74 3>ascii "Edit2DblClick"
00446B47      14            db 14
00446B48      00            db 00
00446B49      EC704400      dd CKme002.004470EC
00446B4D   .0D            db 0D
00446B4E   .46 6F 72 6D 4>ascii "FormMouseMove"
00446B5B      16            db 16
00446B5C      00            db 00
00446B5D      34724400      dd CKme002.00447234
00446B61   .0F            db 0F
00446B62   .49 6D 61 67 6>ascii "Image1MouseDown"
00446B71      16            db 16
00446B72      00            db 00
00446B73      A0724400      dd CKme002.004472A0
00446B77   .0F            db 0F
00446B78   .49 6D 61 67 6>ascii "Image2MouseDown"
00446B87      16            db 16
00446B88      00            db 00
00446B89      0C734400      dd CKme002.0044730C
00446B8D   .0F            db 0F
00446B8E   .49 6D 61 67 6>ascii "Image3MouseDown"
00446B9D      16            db 16
00446B9E      00            db 00
00446B9F      78734400      dd CKme002.00447378
00446BA3   .0F            db 0F
00446BA4   .49 6D 61 67 6>ascii "Image4MouseDown"
00446BB3      12            db 12
00446BB4      00            db 00
00446BB5      E4734400      dd CKme002.004473E4
00446BB9   .0B            db 0B
00446BBA   .54 69 6D 65 7>ascii "Timer2Timer"
00446BC5      13            db 13
00446BC6      00            db 00
00446BC7      C0744400      dd CKme002.004474C0
00446BCB   .0C            db 0C
00446BCC   .42 75 74 74 6>ascii "Button1Click"

哈哈,虽然我没有写过Delphi程序,毕竟还是写过C++/C#程序的,我第一反应就是这肯定就是跟MFC中的消息映射具有相同的功能,这些都是在定义鼠标按下,鼠标移动,定时器等消息的处理过程,而dd CKme002.0044xxxx这个就是对应的消息处理函数,要知道上面列出的那些内存地址如何赋值,必定离不开对这些消息处理函数的跟踪,也就是要在这些地址上面下断点,但不要忙着把断点都下了,一次都下了也没什么好处,我们还是从上面列出的内存地址一个一个开始解决,用到时再下断点也不迟。       由于查上述内存地址在哪些地方有赋值操作要通读反汇编代码,所以可以选择任意一款静态反汇编工具来搜索,这里我选用的是W32DAsm。       用W32DAsm反汇编完成之后,我们首先搜索ebx+0x304这个内存地址,具体方法这里就不再叙述了。可以找到如下之处:                                                                 回到OD查找这两行地址所在的函数头,就会发现刚好是在窗台创建FormCreate的消息处理函数dd CKme002.00446C1C里面,果断下断点,重启程序、F9然后就进入了这个断点,下面的跟踪我就不讲了,关于ebx+0x304这个内存地址他所做的操作就是在文件X:\ajj.126.c0m\j\o\j\o\ok.txt存在并且文件内容为“ajj写的CKme真烂!“时赋值mov dwordptr ds:,0xC34,这个正是我们在爆破点处(其实就是定时器Timer2的定时处理函数)遇到的第一个cmp判断,解决!       赶紧新建好X:\ajj.126.c0m\j\o\j\o\ok.txt保存好内容,重启程序看一下吧。(什么?没有这个盘符,自己想办法吧!)是不是多出来一个输入框啊,这就是我们上面所说的第一步操作,哈哈!可惜不能输入,下面就要来解决这个问题了。       嗯,要怎么解决呢,好像是没有办法了。还是回头看看我们讲过的那一堆消息处理函数吧,文本框不能输入要变得能输入必须得经过事件触发消息处理函数来完成,看那里没有错!如果你醒目,那么在消息处理函数紧接着的上面你会看到这么一堆代码:00446A3A      D0            db D0
00446A3B      02            db 02
00446A3C      00            db 00
00446A3D      00            db 00
00446A3E      00            db 00
00446A3F      00            db 00
00446A40   .06            db 06
00446A41   .50 61 6E 65 6>ascii "Panel1"
00446A47      D4            db D4
00446A48      02            db 02
00446A49      00            db 00
00446A4A      00            db 00
00446A4B      01            db 01
00446A4C      00            db 00
00446A4D   .06            db 06
00446A4E   .54 69 6D 65 7>ascii "Timer1"
00446A54      D8            db D8
00446A55      02            db 02
00446A56      00            db 00
00446A57      00            db 00
00446A58      02            db 02
00446A59      00            db 00
00446A5A   .06            db 06
00446A5B   .49 6D 61 67 6>ascii "Image1"
00446A61      DC            db DC
00446A62      02            db 02
00446A63      00            db 00
00446A64      00            db 00
00446A65      02            db 02
00446A66      00            db 00
00446A67   .06            db 06
00446A68   .49 6D 61 67 6>ascii "Image2"
00446A6E      E0            db E0
00446A6F      02            db 02
00446A70      00            db 00
00446A71      00            db 00
00446A72      02            db 02
00446A73      00            db 00
00446A74   .06            db 06
00446A75   .49 6D 61 67 6>ascii "Image3"
00446A7B      E4            db E4
00446A7C      02            db 02
00446A7D      00            db 00
00446A7E      00            db 00
00446A7F      02            db 02
00446A80      00            db 00
00446A81   .06            db 06
00446A82   .49 6D 61 67 6>ascii "Image4"
00446A88      E8            db E8
00446A89      02            db 02
00446A8A      00            db 00
00446A8B      00            db 00
00446A8C      03            db 03
00446A8D      00            db 00
00446A8E   .05            db 05
00446A8F   .45 64 69 74 3>ascii "Edit1"
00446A94      EC            db EC
00446A95      02            db 02
00446A96      00            db 00
00446A97      00            db 00
00446A98      04            db 04
00446A99      00            db 00
00446A9A   .07            db 07
00446A9B   .42 75 74 74 6>ascii "Button1"
00446AA2      F0            db F0
00446AA3      02            db 02
00446AA4      00            db 00
00446AA5      00            db 00
00446AA6      03            db 03
00446AA7      00            db 00
00446AA8   .05            db 05
00446AA9   .45 64 69 74 3>ascii "Edit2"
00446AAE      F4            db F4
00446AAF      02            db 02
00446AB0      00            db 00
00446AB1      00            db 00
00446AB2      05            db 05
00446AB3      00            db 00
00446AB4   .06            db 06
00446AB5   .4C 61 62 65 6>ascii "Label1"
00446ABB      F8            db F8
00446ABC      02            db 02
00446ABD      00            db 00
00446ABE      00            db 00
00446ABF      05            db 05
00446AC0      00            db 00
00446AC1   .06            db 06
00446AC2   .4C 61 62 65 6>ascii "Label2"
00446AC8      FC            db FC
00446AC9      02            db 02
00446ACA      00            db 00
00446ACB      00            db 00
00446ACC      05            db 05
00446ACD      00            db 00
00446ACE   .06            db 06
00446ACF   .4C 61 62 65 6>ascii "Label3"
00446AD5      00            db 00
00446AD6      03            db 03
00446AD7      00            db 00
00446AD8      00            db 00
00446AD9      01            db 01
00446ADA      00            db 00
00446ADB   .06            db 06
00446ADC   .54 69 6D 65 7>ascii "Timer2"

这是什么?控件定义。不要问我怎么知道的,我不懂Delphi,但是我已经破了004,当我再次看到这一堆东西的时候,我立马做的一件事情就是返回到004去确定这件事情。004和005的这些相关代码对比之后,我就确定了,这一段代码就是控件定义的相关代码。而且也确定了两个输入框Edit1和Edit2的ID(暂且称为ID吧,我不知道Delphi如何称呼,但MFC里面叫ID)分别为0x2E8和0x2F0,但是与界面上的输入框如何对应我们还不确定。如果我们注意到与输入框相关的消息处理函数只有一个Edit2DblClick,对应函数地址为dd CKme002.00446FF8,那么这个对应关系也容易确定了。因为现在界面上,能输入的输入框只有一个,只要我们在00446FF8这个地址处下断,双击一下能不能断下来就可以了。经确定,界面中上面的是Edit1,下面的是Edit2。而Edit2现在是禁用的,要查找在哪里恢复可输入状态的,只需要在W32DAsm反汇编里搜索0x2F0这个ID就可以了。搜到了两处:                                                                                                                                                  这两处一处是在FormCreate消息处理函数里,一处是在Panel1DblClick消息处理函数里,可以猜测FormCreate是设置为禁用,Panel1DblClick则是设置为启用,如果注意到第一段代码里有xor edx, edx,而第二段代码里有mov dl,01那么就可以知道我们的猜想是正确的了。    好了,在Panel1DblClick的函数地址dd CKme002.00446FDC处下断,在图片框没有图片的地方双击。果然进来了,但cmp dword ptr ds:,0x29D后直接跳转了,无法启用Edit2,(可以先爆破确认是不是此处启用Edit2,不过这是肯定的)。那么现在就是要如何使eax+0x308的值变为0x29D了.       转到W32DAsm搜索0x308,找到如下代码:                                                                                                                                  不用说,很容易就可以确定,一个是在FormCreate消息处理函数里将其值初始化为0x28E;一个是在Button1MouseDown消息处理函数里的两处处理一个是加3,一个是设置为0x230D.现在就是要考虑让其尤初始值0x28E变为0x29D的,显然不能让其变为0x230D,那么只能是每次加3喽,那么(0x29D-0x28E)/3=5,对啦,就是要Button1MouseDown消息处理函数执行5次,界面上只有一个按钮(控件定义中也再也没有其他按钮了,这个一定要确定,万一还有隐藏按钮呢),那么就是要在注册按钮上点击鼠标5次了,而且必须是右键!这就是我们在第二步里面要求的操作,千万别点鼠标左键,不然就没法得到0x29D了。      ds:的值已经变为0x29D了,这时再在图片框没有图片的地方双击,就可以启用Edit2了,第三步也完成。       下面就可以按照第四步的要求输入注册名和Edit2的内容,至于要求是怎么得到的当然是在Edit2的双击处理函数Edit2DblClick的地址处下断得来的dd CKme002.00446FF8。这里只列举Edit2的要求,其他的自己跟踪代码。                                                               
          而且在这个函数里面还完成了给一个我们关注的内存地址赋值ebx+0x30C,这个虽然没有在Timer2Timer消息处理函数的程序爆破点处使用但在赋值ebx+0x314的时候用到了:                                                                     到现在为止我们还是只解决了ebx+0x304和ebx+0x308的赋值问题,ebx+0x310、ebx+0x314、ebx+0x318还要继续解决。先在W32DAsm中搜索0x310得到以下代码:                                                            
          这两处又同时出现在了FormMouseMove的消息处理函数里面,通过下断dd CKme002.004470EC这个地址跟踪就可以得出第六步和第七步所要进行的操作,同时在FormMouseMove的消息处理函数里面也可以找到对ebx+0x314的赋值:                                                            
          下面再分析ebx+0x318的赋值问题,从FormCreate消息处理函数中知道它被初始化为0,                                                            
            而在Timer2Timer定时器处理函数中最终判断是否注册通过时需要ebx+0x318的值和ebx+0x314的值相等,而ebx+0x314的值在第六步和第七步已经计算出来了。通过搜索反汇编代码可以得知ebx+0x318的赋值是通过对图片1(“人之初“)、图片2(”性本善“)、图片3(”性相近“),图片4(”习相远“)的鼠标点击来完成的:                                                                                                                                                                                                                              可以看出ebx+0x318(跟esi+0x318指向同一片内存)是通过点击4个图片加和得出来的,所以自己凑吧只要凑出来的点击加和ebx+0x318的值等于ebx+0x314的值就可以了!      至此,我们要得到的内存值都已经揭晓,要说最复杂的就算ebx+0x314的计算了,计算它首先要得到ebx+0x30C的值(取0,1,2,3),需要涉及到注册名和磁盘剩余空间等,是个工作量。下面是我写得一段不成熟的求ebx+0x30C代码:int GetEax(DWORD low, DWORD high)
{
      __asm
      {
                push ebx
                push esi
                push edi
                push edx
                push ecx

                mov ebx, 0x04
                mov ecx, 0x40
                xor esi, esi
                xor edi, edi

                mov edx, dword ptr ds:;
                mov eax, dword ptr ds:;
mylabel:
                shl eax, 1;
                rcl edx, 1;
                rcl esi, 1;
                rcl edi, 1;
                cmp edi, 0x00;
                jb _looppd;
                ja mylabel2;
                cmp esi, ebx;
                jb _looppd
mylabel2:
                sub esi, ebx;
                sbb edi, 0x00;
                inc eax
_looppd:
                loopmylabel;
                mov eax, esi;

                pop ecx
                pop edx
                pop edi
                pop esi
                pop ebx
      }
}
extern "C" __declspec(dllexport) char * keygen(const char* user)
{
      ULARGE_INTEGER FreeBytesAvailableToCaller,TotalNumberOfBytes,TotalNumberOfFreeBytes;
      int len =strlen(user);
      if(GetDiskFreeSpaceExA(NULL, &FreeBytesAvailableToCaller,&TotalNumberOfBytes,&TotalNumberOfFreeBytes))
      {
                int eax = GetEax(TotalNumberOfFreeBytes.LowPart+len+0x02, TotalNumberOfFreeBytes.HighPart);
                //eax的值就是ebx+0x30C的值
      }
      
      return NULL;
}

Pnmker 发表于 2015-5-25 16:36

本帖最后由 Pnmker 于 2015-5-25 16:42 编辑

简单的就没必要发了,而且我主要是看到44018723兄已经发了不少的CM过程,所以没必要重复。
我每过一个都会去44018723兄的帖子里看一下,比较下我们的思路有什么不同,如果感觉44018723兄
没有提到的地方我有回复他的帖子做补充,有兴趣可以去看看。他的链接是
http://www.52pojie.cn/home.php?m ... &view=me&from=space

PS: 我正在练CM011{:1_918:}

GNUBD 发表于 2017-2-6 17:28

新手请教一下:
楼主说这个“ebx+0x30C的值(取0,1,2,3),需要涉及到注册名和磁盘剩余空间”
但是我在虚拟机里面得出的操作方法和实机里面注册的方法是一样的,请问这个是为什么呢???

Pnmker 发表于 2015-5-24 03:12

本帖最后由 Pnmker 于 2015-5-24 03:37 编辑

终于可以松一口气了,不禁还要再嘀咕一次“ajj“!


PS:沙发被我占了不是故意的,帖子编辑了好多次,每次都丢掉后面一大堆东西,原本打算放不下就放2楼的。嘻嘻(*^__^*) 嘻嘻……

king8222 发表于 2015-5-24 04:51

160个,不是每个人都能坚持的下来的,比如我

灰色 发表于 2015-5-24 07:35

参考一下

Hmily 发表于 2015-5-25 15:00

这个算法够变态的。

灰色 发表于 2015-5-25 15:25

恭喜恭喜,帖子变精华了

q136802107 发表于 2015-5-25 15:28

{:1_921:}最好每破解一个就发一个思路,免得到时候我破解部出来的时候找不到人问{:1_918:}

蚯蚓翔龙 发表于 2015-5-25 16:28

{:1_907:}看看大牛会不会发第12个的CM学习学习

云中燕 发表于 2015-5-25 18:26

不是每个人都能坚持的下来的{:1_921:}
页: [1] 2 3 4 5 6
查看完整版本: 160个CrackMe练手之005