海天一色001 发表于 2017-6-9 14:02

初练160个CrakeMe程序之009

本帖最后由 海天一色001 于 2017-6-9 14:11 编辑

第9个CM,这仍是一个VB程序,用的是用户名/注册码的保护方式,一星难度。

随意输入用户名时,OK按钮变得可用了;输入key,点击OK,弹出错误窗口:

PeiD检查后没壳;

第一步汉化:继续使用VB程序汉化专用工具VBExplorer,这仍是一个熟悉软件使用的过程。修改时,未完全按照原文翻译,使自己能够清楚作者的意图就行了。汉化后另存为CM009.exe。
汉化的地方为我用粉红色圈住的部分:在图中左下方的属性窗口修改程序的标题栏内容,我修改为“CM009 (海天一色汉化)”;在右侧字符串栏中点每个地址后的现字符串栏,修改成自己的内容。

修改后点上方工具栏中的三角形,运行修改后的程序,看是否合适,合适则另存为CM009.exe。汉化后程序界面如下:

第二步爆破:将CM009载入OD,查找字符串:

点击成功处的地址进入CPU窗口,来到地址00402308处,向上看了一下,在004022CB处 的“je CM009.00402391”指令跳过了成功。和上一个CM很相似,所以在这里nop掉就行了!



保存为CM009_nop.exe。

第三步追码:重新将CM009载入OD,查找字符串,然后点击成功处的地址进入CPU窗口,向上查找段首至00401FF0处下断,F9运行程序:

输入用户名“52pojie.cn”,密码“1234567890”,点击OK按钮,程序中断下来,F8单步向下,一堆堆的VB函数,很令人头疼!边单步走着,边看寄存器窗口、信息窗口、堆栈窗口的内容,唯恐错过了什么地方:很快来到下列代码处,从00402126-004021D1地址处是一个循环,作用是取用户名的每一字符的16进制ASCII值相加,存入ecx寄存器中,应该是从用户名计算注册码的一部分吧:00402126   .FF15 20414000 call dword ptr ds:[<&MSVBVM50.__vbaVarForInit>]; \执行初始化

0040212C   .8B3D 04414000 mov edi,dword ptr ds:[<&MSVBVM50.__vbaFreeVarLis>;将缓冲区释放了

00402132   >85C0          test eax,eax                                     ;循环开始

00402134   .0F84 9C000000 je CM009.004021D6

0040213A   .8D55 94       lea edx,dword ptr ss:

0040213D   .8D45 DC       lea eax,dword ptr ss:

00402140   .52            push edx

00402141   .50            push eax

00402142   .C745 9C 01000>mov dword ptr ss:,0x1

00402149   .895D 94       mov dword ptr ss:,ebx

0040214C   .FF15 90414000 call dword ptr ds:[<&MSVBVM50.__vbaI4Var>]       ;msvbvm50.__vbaI4Var

00402152   .8D4D BC       lea ecx,dword ptr ss:                  ; |

00402155   .50            push eax                                       ; |Start = 0x2

00402156   .8D55 84       lea edx,dword ptr ss:                  ; |

00402159   .51            push ecx                                       ; |dString8 = 0012F49C

0040215A   .52            push edx                                       ; |RetBUFFER = 0012F464

0040215B   .FF15 38414000 call dword ptr ds:[<&MSVBVM50.#rtcMidCharVar_632>; \rtcMidCharVar

00402161   .8D45 84       lea eax,dword ptr ss:

00402164   .8D4D A8       lea ecx,dword ptr ss:

00402167   .50            push eax                                       ; /String8 = 00000002

00402168   .51            push ecx                                       ; |ARG2 = 0012F49C

00402169   .FF15 70414000 call dword ptr ds:[<&MSVBVM50.__vbaStrVarVal>]   ; \__vbaStrVarVal

0040216F   .50            push eax                                       ; /String = 00000002 ???

00402170   .FF15 0C414000 call dword ptr ds:[<&MSVBVM50.#rtcAnsiValueBstr_>; \rtcAnsiValueBstr

00402176   .66:8985 4CFFF>mov word ptr ss:,ax

0040217D   .8D55 CC       lea edx,dword ptr ss:

00402180   .8D85 44FFFFFF lea eax,dword ptr ss:

00402186   .52            push edx                                       ; /var18 = 0012F464

00402187   .8D8D 74FFFFFF lea ecx,dword ptr ss:                  ; |

0040218D   .50            push eax                                       ; |var28 = 00000002

0040218E   .51            push ecx                                       ; |saveto8 = 0012F49C

0040218F   .899D 44FFFFFF mov dword ptr ss:,ebx                  ; |

00402195   .FF15 94414000 call dword ptr ds:[<&MSVBVM50.__vbaVarAdd>]      ; \__vbaVarAdd

0040219B   .8BD0          mov edx,eax                                 ;ecx=用户名每个字符ASCII值相加,跟eax没关系啊

0040219D   .8D4D CC       lea ecx,dword ptr ss:

004021A0   .FFD6          call esi                                       ;msvbvm50.__vbaVarMove

004021A2   .8D4D A8       lea ecx,dword ptr ss:

004021A5   .FF15 B8414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeStr>]   ;msvbvm50.__vbaFreeStr

004021AB   .8D55 84       lea edx,dword ptr ss:

004021AE   .8D45 94       lea eax,dword ptr ss:

004021B1   .52            push edx

004021B2   .50            push eax

004021B3   .53            push ebx

004021B4   .FFD7          call edi                                       ;msvbvm50.__vbaFreeVarList

004021B6   .83C4 0C       add esp,0xC

004021B9   .8D8D E8FEFFFF lea ecx,dword ptr ss:

004021BF   .8D95 F8FEFFFF lea edx,dword ptr ss:

004021C5   .8D45 DC       lea eax,dword ptr ss:

004021C8   .51            push ecx                                       ; /TMPend8 = 0012F49C

004021C9   .52            push edx                                       ; |TMPstep8 = 0012F464

004021CA   .50            push eax                                       ; |Counter8 = 00000002

004021CB   .FF15 AC414000 call dword ptr ds:[<&MSVBVM50.__vbaVarForNext>]; \__vbaVarForNext

004021D1   .^ E9 5CFFFFFF   jmp CM009.00402132                               ;循环作用是取用户名每个字符的16进制ASCII值相加,存入ecx中程序运行到循环结束的下一句004021D6处时,ecx=0x120003:再往下,又是如下代码:004021D6   > \8D4D CC       lea ecx,dword ptr ss:

004021D9   .8D95 54FFFFFF lea edx,dword ptr ss:

004021DF   .51            push ecx                                       ; /var18 = 0012F49C

004021E0   .8D45 94       lea eax,dword ptr ss:                  ; |

004021E3   .52            push edx                                       ; |var28 = 0012F464

004021E4   .50            push eax                                       ; |SaveTo8 = 00000002

004021E5   .C785 5CFFFFFF>mov dword ptr ss:,0x499602D2         ; |10进制数1234567890入栈ss:

004021EF   .C785 54FFFFFF>mov dword ptr ss:,0x3                  ; |3进ss:

004021F9   .FF15 5C414000 call dword ptr ds:[<&MSVBVM50.__vbaVarMul>]      ; \__vbaVarMul

004021FF   .8BD0          mov edx,eax__vbaVarMul函数的作用是两数相乘,但是它的参数是什么还不清楚,花了很长时间,在004021E4和004021FF处分别下断点,在反复在这里计算,查看寄存器内容,还是没弄明白这个函数的参数是谁,只知道是返回到eax中,可是eax中的值也令人摸不清头脑,没有什么用处啊!继续向下,又看到了“__vbaVarMove”、“ __vbaMidStmtVar”之类的函数,太头疼了!多少能猜测一点儿它们的用途,可是找不到具体的东西来。00402206   .8B1D A0414000 mov ebx,dword ptr ds:[<&MSVBVM50.__vbaMidStmtVar>;msvbvm50.__vbaMidStmtVar

0040220C   .8D4D CC       lea ecx,dword ptr ss:

0040220F   .51            push ecx

00402210   .6A 04         push 0x4

00402212   .8D95 54FFFFFF lea edx,dword ptr ss:

00402218   .6A 01         push 0x1

0040221A   .52            push edx

0040221B   .C785 5CFFFFFF>mov dword ptr ss:,CM009.00401C34       ;-

00402225   .C785 54FFFFFF>mov dword ptr ss:,0x8

0040222F   .FFD3          call ebx                                       ;<&MSVBVM50.__vbaMidStmtVar>

00402231   .8D45 CC       lea eax,dword ptr ss:

00402234   .8D8D 54FFFFFF lea ecx,dword ptr ss:

0040223A   .50            push eax

0040223B   .6A 09         push 0x9

0040223D   .6A 01         push 0x1

0040223F   .51            push ecx

00402240   .C785 5CFFFFFF>mov dword ptr ss:,CM009.00401C34       ;-

0040224A   .C785 54FFFFFF>mov dword ptr ss:,0x8

00402254   .FFD3          call ebx

00402256   .8B45 08       mov eax,dword ptr ss:运行到00402231处时,堆栈中出现了可疑的注册码数字!!!!!!



继续单步至00402256处时,堆栈中显示如下图,那么“110-4691-5770”很可能就是注册码了!

把110-4691-5770填入注册码编辑框中,点OK按钮,运行成功了!

再用“海天一色”作为用户名,在OD中追码,出来了一个这样的字符串:UNICODE "-69-4444-811590"!输入编辑框中,注册也成功了!

出现这样的字符是调用了两次msvbvm50.__vbaMidStmtVar函数运行后的结果,猜测这个函数参数可能是__vbaMidStmtVar(字符串,开始替换的位置,要替换的长度,要替换的字符),最终把一串数字中的第4位和第9位用“-”代替,形成了一个新的字符串。虽然注册码找出来了,可是怎么算出来的呢?一头雾水!
下面的代码基本上应该对注册码算法没什么作用了,到00402292处取假码进行处理,一直到004022AE处用MSVBVM50.__vbaVarTstEq函数对真假码比较,
004022AE   .FF15 48414000 call dword ptr ds:[<&MSVBVM50.__vbaVarTs>; \__vbaVarTstEq

004022B4   .8D4D A4       lea ecx,dword ptr ss:

004022B7   .8BD8          mov ebx,eax

004022B9   .FF15 B4414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeO>;msvbvm50.__vbaFreeObj

004022BF   .8D4D 94       lea ecx,dword ptr ss:

004022C2   .FF15 00414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeV>;msvbvm50.__vbaFreeVar

004022C8   .66:85DB       test bx,bx

004022CB      0F84 C0000000 je CM009.00402391                        ;关键跳
从网上找到此函数比较两个数,如两数相同eax=1;否则eax=0。因为输入的错码,eax当然是0;后面eax赋值给了ebx,所以到关键跳前的test bx,bx一句时,下一句就跳过成功了。想从OD中直接找到算法看样子很困难!所以再利用VB反编译利器VB Decompiler出场!



Text2_Change()的代码只有一个功能,输入字符,OK按钮可用!双击左侧窗口中Command1_Click_401FF0,在右侧反编译器窗口中出现了如下代码:
Private Sub Command1_Click() '401FF0

loc_00402092: var_58 = Text2.Text

loc_004020CA: var_44 = var_58

loc_00402126: For var_24 = 1 To Len(var_44) Step 1

loc_00402132:

loc_00402134: If var_108 = 0 Then GoTo loc_004021D6

loc_00402169: var_58 = CStr(Mid(var_44, CLng(var_24), 1))

loc_00402176: var_B4 = Asc(var_58)

loc_004021A0: var_34 = var_34 + Asc(var_58)

loc_004021CB: Next var_24

loc_004021D1: GoTo loc_00402132

loc_004021D6: 'Referenced from: 00402134

loc_00402204: var_34 = var_34 * 1234567890

loc_00402276: var_58 = Text1.Text

loc_00402298: var_64 = var_58

loc_004022CB: If (var_58 = var_34) = 0 Then GoTo loc_00402391

loc_004022D1: Beep

loc_00402308: var_B4 = "成功"

loc_00402327: var_A4 = "成功了,请继续下去!"

loc_00402374: var_54 = MsgBox("成功了,请继续下去!", 48, "成功", 10, 10)

loc_0040238C: GoTo loc_00402446

loc_00402391: 'Referenced from: 004022CB

loc_004023C2: var_B4 = "失败"

loc_004023E1: var_A4 = "不幸的错误!"

loc_0040242E: var_54 = MsgBox("不幸的错误!", 16, "失败", 10, 10)

loc_00402446: 'Referenced from: 0040238C

loc_00402459: GoTo loc_0040248F

loc_0040248E: Exit Sub

loc_0040248F: 'Referenced from: 00402459

loc_004024C0: GoTo loc_00esi

End Sub
这些代码很容易就看出来是精简过的代码,只抽取出了注册码的数学计算,将用户名每个字符的16进制ASCII值相加后的结果再乘以 1234567890得到的一个结果,所以用户名“52pojie.cn”算出的注册码是(893*1234567890=)1102469125770;此时对照OD中的注册码,整个注册算法出来了,是用户名每个字符的16进制ASCII值相加后的结果再乘以 1234567890得到的一个结果转成字符串形式,再将第4个、第9个字符替换成“-”即可。
注册机编写时基本上将VBDecompiler反编译的代码修改一下,再加上字符替换就行了。
附件含原程序、汉化程序CM009、爆破程序CM009_nop及009的注册机。
百度链接是:http://pan.baidu.com/s/1skMkJY9密码: 86pm,160个CM、个人学习过的前9个crackme程序都在里面。

肥牛 发表于 2017-6-9 14:36

楼主,对于009这个CM,我这周也做了一下,我觉得你的分析没有分析到这个CM的实质。这个CM是用VB写的,也不知道是VB的特性,还是这个CM的特性,数字在寄存器中的存储都很奇怪,好像是扩展了一下的样子。所以用OD去调试的时候,只看寄存器的值是看不出任何端倪的,需要把寄存器保存的值按照数据地址的方式查看,才能有一些眉目。在这个吾爱破解论坛,有人贴出来一个009的分析,我觉得那个分析还是写的挺到位的,你可以参考一下。帖子地址:http://www.52pojie.cn/forum.php?mod=viewthread&tid=265789
另外,用VB反编译出来的东西,把后面处理字符串的部分给丢掉了。这个我也很奇怪。考虑到VB的特性,操作数在EAX中,我甚至怀疑这个CM是用VB写好以后,又用二进制编辑工具把一些MOV LEA以及CALL交换位置而形成的,这样就导致VB反编译工具无法识别正确的代码了。

反正,对于VB的程序,我觉得实在是难以理解,今后我还是远离它们吧。

肥牛 发表于 2017-6-9 14:42

另外,我再说一下楼主有一个非常不好的习惯,就是在破解前先把软件汉化。比如软件运行时判断自身是否被修改,或者某个英文提示作为注册码生成的密钥等等,汉化都会把这些破坏掉。所以我建议破解前不要做汉化操作。

海盗小K 发表于 2017-6-9 15:35

我也认同肥牛兄的说法,这些CM本来就是用来练手破解的,汉化实在是没有必要的操作。如果LZ想练手汉化,不如找些其他的软件来练练。CM当中的字符串本来就只有那两个。

海天一色001 发表于 2017-6-9 16:03

肥牛 发表于 2017-6-9 14:36
楼主,对于009这个CM,我这周也做了一下,我觉得你的分析没有分析到这个CM的实质。这个CM是用VB写的,也不 ...

感谢肥牛的指导!我的本意是既练习了些破解知识,又顺便练习了汉化,目的是加深对程序和编程语言的理解,确实没有想到软件的自校验及其他方面!以后会注意这些问题的!
另外:http://www.52pojie.cn/forum.php?mod=viewthread&tid=265789这个帖子我也学习了,但对怎样把寄存器保存的值按照数据地址的方式查看还是一头雾水!手头有几本VB编程的书,但没有一本讲到VB对数据在寄存器中是如何处理的!VB编程是我接触的第一个编程语言,没想到这么令人难受!
不过作为CM练习,我还是要继续练下去,再次感谢!
在此也感谢海盗小K!

MisS 发表于 2017-6-9 19:52

大神,我有个不联网的小程序,换硬盘后就需要重新注册,能帮我看看么,500k的程序。

海天一色001 发表于 2017-6-9 20:17

18633304400 发表于 2017-6-9 19:52
大神,我有个不联网的小程序,换硬盘后就需要重新注册,能帮我看看么,500k的程序。

首先说明我不是大神!!!
只是刚学习逆向的新手!!!
你的这个程序从各种渠道了解到应该是利用硬盘的机器码来判断的,但怎么破我还真的不会!目前只在用户名/注册码这一块进行学习呢!

lxq007 发表于 2017-6-9 22:23

好复杂,一下子很难看的懂。但还是要顶

Three_fish 发表于 2017-6-10 10:48

感谢分享!
页: [1]
查看完整版本: 初练160个CrakeMe程序之009