标 题: 【原创】再度出击,完美破解飘云阁的某个CM
作 者: 不问年少
时 间: 2009-03-20,14:30
中午无聊,决定再来练习逆向,无奈近日看雪CM版块过于冷清,无从练手。高手们也都休养生息,决不露面,让我等小菜无所适从,只好自力更生,艰苦奋斗了。
在天草论坛中发现一CM(等等,怎么标题说是飘云阁的CM啊?呵呵,这是从破解软件以后才发现是飘云阁的),又是VB编写的,为克服自己对VB的畏惧感,于是操刀再向VB行!
点击此CM,冒出个扎眼的Make in H&Y的窗口,上书:NAG 我晕!点确定后来到主窗口,输入用户名密码后,发现“确定”按钮不让人点,这肯定又是作者给我们留下的第二个难题吧。(猜测的,要不然作者就是……了,呵呵),废话少说,下面来进行完破:
下断rtcMsgBox,返回后,将调用rtcMsg的CALL直接NOP掉,运行之,无碍,NAG已消失!
下断EnableWindow,返回后,将参数Push 0,改为Push 1,也就是改成EnableWindow(OkbuttonHandle, TRUE),这样,每二关就过了。
下断__vbaVarTstEq,点击运行,立即来到关键比较处:
00403C6D . 52 push edx ; 假码
00403C6E . 50 push eax ; 真码s
00403C6F . C745 A8 00000>mov dword ptr [ebp-58], >
00403C76 . C745 94 08800>mov dword ptr [ebp-6C], >
00403C7D . FF15 60104000 call dword ptr [<&MSVBVM6>; MSVBVM60.__vbaVarTstEq
00403C83 . 8D4D A4 lea ecx, dword ptr [ebp->; 将真假码比较
00403C86 . 8BF0 mov esi, eax
00403C88 . FF15 E4104000 call dword ptr [<&MSVBVM6>; MSVBVM60.__vbaFreeObj
00403C8E . 8D4D 94 lea ecx, dword ptr [ebp->
00403C91 . FF15 10104000 call dword ptr [<&MSVBVM6>; MSVBVM60.__vbaFreeVar
00403C97 . 66:85F6 test si, si ; 测试比较结果
00403C9A . 0F84 A3000000 je 00403D43 ; 跳走就完蛋了
输入403C6E处得到的真码,直接成功~!就这样过了三关,但是一点没有成就感啊,哎!要分析算法才能进步,不能只是简单暴破,于是乎,抖擞精神,再度出击 !
下面来分析算法,从关键点向上找到函数开始处:很明显是经典的VB函数开头, On Error ....,写过VB程序的人都知道。
00403730 > \55 push ebp
00403731 . 8BEC mov ebp, esp
00403733 . 83EC 0C sub esp, 0C
00403736 . 68 36114000 push <jmp.&MSVBVM60.__vbaExceptHandle>; SE 处理程序安装
0040373B . 64:A1 0000000>mov eax, dword ptr fs:[0]
00403741 . 50 push eax
00403742 . 64:8925 00000>mov dword ptr fs:[0], esp
00403749 . 81EC 68010000 sub esp, 168
0040374F . 53 push ebx
00403750 . 56 push esi
00403751 . 57 push edi
00403752 . 8965 F4 mov dword ptr [ebp-C], esp
00403755 . C745 F8 00114>mov dword ptr [ebp-8], 00401100
0040375C . 8B75 08 mov esi, dword ptr [ebp+8]
0040375F . 8BC6 mov eax, esi
00403761 . 83E0 01 and eax, 1
....
继续向下跑:嘿嘿,为什么要说跑呢,对于VB,你不跑都不行啊,太多垃圾代码了!~来到这里,这是第1个计算,它计算了m的值,m是什么,自己看吧:
0040386F . 51 push ecx ; 计算用户名长度n
00403870 . FF15 14104000 call dword ptr [<&MSVBVM60.__vbaLenBs>; MSVBVM60.__vbaLenBstr
00403876 . 6BC0 16 imul eax, eax, 16 ; eax=n*16h
00403879 . 0F80 3C060000 jo 00403EBB
0040387F . 05 29240000 add eax, 2429 ; eax+=2429h
00403884 . 8D4D A8 lea ecx, dword ptr [ebp-58]
00403887 . 0F80 2E060000 jo 00403EBB
0040388D . 2D E8030000 sub eax, 3E8 ; eax-=3E8h
00403892 . 0F80 23060000 jo 00403EBB
00403898 . 8985 84FEFFFF mov dword ptr [ebp-17C], eax ; 设Eax=m=len(username)*16h+2429h-3E8h
0040389E . DB85 84FEFFFF fild dword ptr [ebp-17C] ; 将eax转为整数载入
004038A4 . DD5D B4 fstp qword ptr [ebp-4C] ; 保存m
看来 m = strlen(UserName)*0x16+0x2429-0x3E8; //我用C语言描述,后面注册机用VB写, 这样更明了方便点。呵呵,再往后,过千山,涉万水,终于来到了计算注册码的第二部分:
004039E2 . FF15 34104000 call dword ptr [<&MSVBVM60.__vbaVarFo>; MSVBVM60.__vbaVarForInit
004039E8 . 8B1D 08104000 mov ebx, dword ptr [<&MSVBVM60.__vba>; MSVBVM60.__vbaVarMove
004039EE . 8B35 1C104000 mov esi, dword ptr [<&MSVBVM60.__vba>; MSVBVM60.__vbaVarIdiv
004039F4 > 85C0 test eax, eax
004039F6 . 0F84 7B010000 je 00403B77
004039FC . 8B45 B0 mov eax, dword ptr [ebp-50] ; 得到用户名数组指针
004039FF . 85C0 test eax, eax
00403A01 . 74 33 je short 00403A36
很明显,这是一个循环计算注册码开始处,经典的VB型 For... Next结构。再看:
00403A45 . 66:0FB60402 movzx ax, byte ptr [edx+eax] ; 取第i个用户名
00403A4A . 8D95 00FFFFFF lea edx, dword ptr [ebp-100]
00403A50 . 66:8985 08FFF>mov word ptr [ebp-F8], ax
00403A57 . 89BD 00FFFFFF mov dword ptr [ebp-100], edi
00403A5D . FFD3 call ebx
00403A5F . 8D4D BC lea ecx, dword ptr [ebp-44]
00403A62 . 8D95 00FFFFFF lea edx, dword ptr [ebp-100]
00403A68 . 51 push ecx
00403A69 . 8D45 94 lea eax, dword ptr [ebp-6C]
00403A6C . 52 push edx
00403A6D . 50 push eax
00403A6E . C785 08FFFFFF>mov dword ptr [ebp-F8], 6
00403A78 . 89BD 00FFFFFF mov dword ptr [ebp-100], edi
00403A7E . C785 F8FEFFFF>mov dword ptr [ebp-108], 4
00403A88 . 89BD F0FEFFFF mov dword ptr [ebp-110], edi
00403A8E . C785 E8FEFFFF>mov dword ptr [ebp-118], 0A
00403A98 . 89BD E0FEFFFF mov dword ptr [ebp-120], edi
00403A9E . FFD6 call esi ; x=usernmae[i]/6
00403AA0 . 8D4D BC lea ecx, dword ptr [ebp-44]
00403AA3 . 50 push eax ; x
00403AA4 . 8D95 F0FEFFFF lea edx, dword ptr [ebp-110]
00403AAA . 51 push ecx
00403AAB . 8D45 84 lea eax, dword ptr [ebp-7C]
00403AAE . 52 push edx
00403AAF . 50 push eax ; y=username[i]/4
00403AB0 . FFD6 call esi
00403AB2 . 8D8D 74FFFFFF lea ecx, dword ptr [ebp-8C]
00403AB8 . 50 push eax
00403AB9 . 51 push ecx ; y*=x
00403ABA . FF15 74104000 call dword ptr [<&MSVBVM60.__vbaVarMu>; MSVBVM60.__vbaVarMul
00403AC0 . 50 push eax ; y
00403AC1 . 8D55 BC lea edx, dword ptr [ebp-44]
00403AC4 . 8D85 E0FEFFFF lea eax, dword ptr [ebp-120]
00403ACA . 52 push edx
00403ACB . 8D8D 64FFFFFF lea ecx, dword ptr [ebp-9C]
00403AD1 . 50 push eax
00403AD2 . 51 push ecx ; z=username[i]/=0ah
00403AD3 . FFD6 call esi
00403AD5 . 8D95 54FFFFFF lea edx, dword ptr [ebp-AC]
00403ADB . 50 push eax ; y/=z
00403ADC . 52 push edx
00403ADD . FFD6 call esi
00403ADF . 50 push eax
00403AE0 . FF15 D0104000 call dword ptr [<&MSVBVM60.__vbaI2Err>; MSVBVM60.__vbaI2ErrVar
00403AE6 . 66:8985 4CFFF>mov word ptr [ebp-B4], ax
00403AED . 8D85 44FFFFFF lea eax, dword ptr [ebp-BC]
00403AF3 . 8D8D 34FFFFFF lea ecx, dword ptr [ebp-CC]
00403AF9 . 50 push eax
00403AFA . 51 push ecx
00403AFB . 89BD 44FFFFFF mov dword ptr [ebp-BC], edi
00403B01 . FF15 C4104000 call dword ptr [<&MSVBVM60.#613>] ; MSVBVM60.rtcVarStrFromVar
00403B07 . 8D95 34FFFFFF lea edx, dword ptr [ebp-CC] ; 将y转化为字串
00403B0D . 8D85 24FFFFFF lea eax, dword ptr [ebp-DC]
00403B13 . 52 push edx
00403B14 . 50 push eax
00403B15 . FF15 48104000 call dword ptr [<&MSVBVM60.#520>] ; MSVBVM60.rtcTrimVar
00403B1B . 8D4D CC lea ecx, dword ptr [ebp-34]
00403B1B . 8D4D CC lea ecx, dword ptr [ebp-34] ; 去空格
00403B1E . 8D95 24FFFFFF lea edx, dword ptr [ebp-DC]
00403B24 . 51 push ecx
00403B25 . 8D85 14FFFFFF lea eax, dword ptr [ebp-EC]
00403B2B . 52 push edx
00403B2C . 50 push eax
00403B2D . FF15 C0104000 call dword ptr [<&MSVBVM60.__vbaVarAd>; MSVBVM60.__vbaVarAdd
00403B33 . 8BD0 mov edx, eax ; 连接字串s+=y
再往下就是VB中For语句的结束标志 Next了,所以分析这个大循环的主要算法如下(伪代码,y没转化):
首先s = strcat(s, y),那么y呢, y = y*x/z的商, x = username[i]/6, y = username[i]/4, z = username[i]/10
呵呵,不要晕啊!这一步弄清了后面就简单多了!后面就是简单的字串连接操作了:
00403BB5 > \8B45 A8 mov eax, dword ptr [ebp-58] ; -"PYG-"
00403BB8 . 8B4D B8 mov ecx, dword ptr [ebp-48]
00403BBB . 8B35 90104000 mov esi, dword ptr [<&MSVBVM60.__vba>; MSVBVM60.__vbaVarCat
00403BC1 . 8945 9C mov dword ptr [ebp-64], eax
00403BC4 . 8B45 B4 mov eax, dword ptr [ebp-4C]
00403BC7 . 8D55 CC lea edx, dword ptr [ebp-34]
00403BCA . 8985 08FFFFFF mov dword ptr [ebp-F8], eax
00403BD0 . 898D 0CFFFFFF mov dword ptr [ebp-F4], ecx
00403BD6 . 8D45 94 lea eax, dword ptr [ebp-6C]
00403BD9 . 52 push edx ; 将上面得到的结果y与-PYG-相连接
00403BDA . 8D4D 84 lea ecx, dword ptr [ebp-7C] ; 设为s1
00403BDD . 50 push eax
00403BDE . 51 push ecx
00403BDF . C745 A8 00000>mov dword ptr [ebp-58], 0
00403BE6 . C745 94 08000>mov dword ptr [ebp-6C], 8
00403BED . C785 00FFFFFF>mov dword ptr [ebp-100], 5
00403BF7 . FFD6 call esi ; <&MSVBVM60.__vbaVarCat>
00403BF9 . 50 push eax ; s1再与最先计算得到的m相连接,设为s
00403BFA . 8D95 00FFFFFF lea edx, dword ptr [ebp-100]
00403C00 . 8D85 74FFFFFF lea eax, dword ptr [ebp-8C]
00403C06 . 52 push edx
00403C07 . 50 push eax
00403C08 . FFD6 call esi ; EAX=s=计算后最终得到的真码
然后就是关键跳转处的比较了。呵呵!综上所述,可以得到注册算法如下,VB版的CM,当然用VB写注册机咯:)
Private Sub Command1_Click()
On Error GoTo Err:
Dim m As Long, x As Long, y As Long, z As Long, n As Long, s As String, i As Integer
m = Len(Username) * &H16 + &H2429 - &H3E8 '根据用户名计算的m值
For i = 1 To Len(Username)
n = Asc(Mid(Username, i, 1)) '用户名的ASCII码
x = (n - (n Mod 6)) / 6 '以下为了得到除以某数的整数部分,先减去多余的余数部分再进行相除
z = (n - (n Mod 10)) / 10
y = (n - (n Mod 4)) / 4
y = y * x
y = (y - (y Mod z)) / z
s = s & y
Next
Codekey = s & "-PYG-" & m
Err:
End Sub
这样,这个CM的三关就被轻松拿下,完美破解了。我不知道有没有人分析过此CM,但这是我个人的心得,奉献给大家,愿大家和我一起进步!
by 不问年少
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!
上传的附件: