本帖最后由 海天一色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寄存器中,应该是从用户名计算注册码的一部分吧:[Asm] 纯文本查看 复制代码 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:[ebp-0x6C]
0040213D . 8D45 DC lea eax,dword ptr ss:[ebp-0x24]
00402140 . 52 push edx
00402141 . 50 push eax
00402142 . C745 9C 01000>mov dword ptr ss:[ebp-0x64],0x1
00402149 . 895D 94 mov dword ptr ss:[ebp-0x6C],ebx
0040214C . FF15 90414000 call dword ptr ds:[<&MSVBVM50.__vbaI4Var>] ; msvbvm50.__vbaI4Var
00402152 . 8D4D BC lea ecx,dword ptr ss:[ebp-0x44] ; |
00402155 . 50 push eax ; |Start = 0x2
00402156 . 8D55 84 lea edx,dword ptr ss:[ebp-0x7C] ; |
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:[ebp-0x7C]
00402164 . 8D4D A8 lea ecx,dword ptr ss:[ebp-0x58]
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:[ebp-0xB4],ax
0040217D . 8D55 CC lea edx,dword ptr ss:[ebp-0x34]
00402180 . 8D85 44FFFFFF lea eax,dword ptr ss:[ebp-0xBC]
00402186 . 52 push edx ; /var18 = 0012F464
00402187 . 8D8D 74FFFFFF lea ecx,dword ptr ss:[ebp-0x8C] ; |
0040218D . 50 push eax ; |var28 = 00000002
0040218E . 51 push ecx ; |saveto8 = 0012F49C
0040218F . 899D 44FFFFFF mov dword ptr ss:[ebp-0xBC],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:[ebp-0x34]
004021A0 . FFD6 call esi ; msvbvm50.__vbaVarMove
004021A2 . 8D4D A8 lea ecx,dword ptr ss:[ebp-0x58]
004021A5 . FF15 B8414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeStr>] ; msvbvm50.__vbaFreeStr
004021AB . 8D55 84 lea edx,dword ptr ss:[ebp-0x7C]
004021AE . 8D45 94 lea eax,dword ptr ss:[ebp-0x6C]
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:[ebp-0x118]
004021BF . 8D95 F8FEFFFF lea edx,dword ptr ss:[ebp-0x108]
004021C5 . 8D45 DC lea eax,dword ptr ss:[ebp-0x24]
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:再往下,又是如下代码:[Asm] 纯文本查看 复制代码 004021D6 > \8D4D CC lea ecx,dword ptr ss:[ebp-0x34]
004021D9 . 8D95 54FFFFFF lea edx,dword ptr ss:[ebp-0xAC]
004021DF . 51 push ecx ; /var18 = 0012F49C
004021E0 . 8D45 94 lea eax,dword ptr ss:[ebp-0x6C] ; |
004021E3 . 52 push edx ; |var28 = 0012F464
004021E4 . 50 push eax ; |SaveTo8 = 00000002
004021E5 . C785 5CFFFFFF>mov dword ptr ss:[ebp-0xA4],0x499602D2 ; |10进制数1234567890入栈ss:[ebp-0xA4]
004021EF . C785 54FFFFFF>mov dword ptr ss:[ebp-0xAC],0x3 ; |3进ss:[ebp-0xAC]
004021F9 . FF15 5C414000 call dword ptr ds:[<&MSVBVM50.__vbaVarMul>] ; \__vbaVarMul
004021FF . 8BD0 mov edx,eax __vbaVarMul函数的作用是两数相乘,但是它的参数是什么还不清楚,花了很长时间,在004021E4和004021FF处分别下断点,在反复在这里计算,查看寄存器内容,还是没弄明白这个函数的参数是谁,只知道是返回到eax中,可是eax中的值也令人摸不清头脑,没有什么用处啊!继续向下,又看到了“__vbaVarMove”、“ __vbaMidStmtVar”之类的函数,太头疼了!多少能猜测一点儿它们的用途,可是找不到具体的东西来。[Asm] 纯文本查看 复制代码 00402206 . 8B1D A0414000 mov ebx,dword ptr ds:[<&MSVBVM50.__vbaMidStmtVar>; msvbvm50.__vbaMidStmtVar
0040220C . 8D4D CC lea ecx,dword ptr ss:[ebp-0x34]
0040220F . 51 push ecx
00402210 . 6A 04 push 0x4
00402212 . 8D95 54FFFFFF lea edx,dword ptr ss:[ebp-0xAC]
00402218 . 6A 01 push 0x1
0040221A . 52 push edx
0040221B . C785 5CFFFFFF>mov dword ptr ss:[ebp-0xA4],CM009.00401C34 ; -
00402225 . C785 54FFFFFF>mov dword ptr ss:[ebp-0xAC],0x8
0040222F . FFD3 call ebx ; <&MSVBVM50.__vbaMidStmtVar>
00402231 . 8D45 CC lea eax,dword ptr ss:[ebp-0x34]
00402234 . 8D8D 54FFFFFF lea ecx,dword ptr ss:[ebp-0xAC]
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:[ebp-0xA4],CM009.00401C34 ; -
0040224A . C785 54FFFFFF>mov dword ptr ss:[ebp-0xAC],0x8
00402254 . FFD3 call ebx
00402256 . 8B45 08 mov eax,dword ptr ss:[ebp+0x8] 运行到00402231处时,堆栈中出现了可疑的注册码数字!!!!!!
继续单步至00402256处时,堆栈中显示如下图,那么“110-4691-5770”很可能就是注册码了!
把110-4691-5770填入注册码编辑框中,点OK按钮,运行成功了!
再用“海天一色”作为用户名,在OD中追码,出来了一个这样的字符串:UNICODE "-69-4444-811590"!输入编辑框中,注册也成功了!
出现这样的字符是调用了两次msvbvm50.__vbaMidStmtVar函数运行后的结果,猜测这个函数参数可能是__vbaMidStmtVar(字符串,开始替换的位置,要替换的长度,要替换的字符),最终把一串数字中的第4位和第9位用“-”代替,形成了一个新的字符串。虽然注册码找出来了,可是怎么算出来的呢?一头雾水!
下面的代码基本上应该对注册码算法没什么作用了,到00402292处取假码进行处理,一直到004022AE处用MSVBVM50.__vbaVarTstEq函数对真假码比较,
[Asm] 纯文本查看 复制代码 004022AE . FF15 48414000 call dword ptr ds:[<&MSVBVM50.__vbaVarTs>; \__vbaVarTstEq
004022B4 . 8D4D A4 lea ecx,dword ptr ss:[ebp-0x5C]
004022B7 . 8BD8 mov ebx,eax
004022B9 . FF15 B4414000 call dword ptr ds:[<&MSVBVM50.__vbaFreeO>; msvbvm50.__vbaFreeObj
004022BF . 8D4D 94 lea ecx,dword ptr ss:[ebp-0x6C]
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,在右侧反编译器窗口中出现了如下代码:
[Visual Basic] 纯文本查看 复制代码 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反编译的代码修改一下,再加上字符替换就行了。
附件
009.rar
(17.8 KB, 下载次数: 8)
含原程序、汉化程序CM009、爆破程序CM009_nop及009的注册机。
百度链接是:http://pan.baidu.com/s/1skMkJY9密码: 86pm,160个CM、个人学习过的前9个crackme程序都在里面。 |