逆向分析是一个考验耐心的事情,所以还是按照步骤一步一步来。
就比如这个程序,其实丢到OD动态调试的话还是比较容易的,但是丢到VB Decompiler里面发现看不太明白了哈哈。
才疏学浅,以作记录
0X00 首先还是打开程序咯,是一个点选数字和'*'、'#'的输入验证码的程序。
另外发现status显示未注册、也没有按钮,根据经验大概就是程序不停循环判断文本框内是否是正确的验证码。
然后成功之后将status变成REGISTERED。
0X01 那么进行爆破,这里我走了一点弯路。。我先进行了静态分析,找到了刚拿到的神器VB Decompiler进行反编译。
但还是分析出了一点代码的逻辑。
左边Command_Click分别对应了程序当中13个按键,分析代码很容易能看出来每个按键的功能。
那么重点应该就在于Timer当中了。
大致分析了一下确实没怎么看太懂。。
Private Sub Timer1_Timer() '404650
loc_0040479F: var_48 = Text1.Text
loc_004047D5: ebx = (var_48 = vbNullString) + 1
loc_004047ED: If (var_48 = vbNullString) + 1 = 0 Then GoTo loc_00404814
loc_00404806: Command13.Enabled = esi
loc_00404810: If ebx >= 0 Then GoTo loc_0040484A
loc_00404812: GoTo loc_00404838
loc_0040482C: Command13.Enabled = True
loc_00404836: If ebx >= 0 Then GoTo loc_0040484A
loc_00404838: 'Referenced from: 00404812
loc_00404844: ebx = CheckObj(ebx, var_00401E30, 140)
loc_0040484A:
loc_00404870: var_48 = Text1.Text //var_48=serial
loc_004048AA: var_44 = var_48 //var_44=serial
loc_0040491D: For var_24 = 1 To Len(var_44) Step 1 //遍历serial中每一个字符
loc_0040492F:
loc_00404931: If var_F8 = 0 Then GoTo loc_00404A60
loc_0040494B: var_50 = CStr(Left(var_44, 1)) //var_50=serial的第一个字符
loc_0040499D: var_304 = Asc(Mid$(CStr(var_44), CLng(var_24), 1)) //var_304=第i个字符的ASCII码
loc_004049E2: var_8C = Hex$((var_30C + var_CC)) //var_8C 没有看明白。。。不知道后面两个变量是干什么的
loc_00404A0C: var_34 = var_34 & Hex$((var_30C + var_CC))
loc_00404A55: Next var_24
loc_00404A5B: GoTo loc_0040492F
loc_00404A60: 'Referenced from: 00404931
loc_00404A88: If (var_34 = "0817E747D7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C") = 0 Then GoTo loc_00404AD6
loc_00404AAF: var_eax = Unknown_VTable_Call[ecx+00000054h]
loc_00404AD6: 'Referenced from: 00404A88
截取了部分代码做了分析。大概就是对文本框的内容进行一系列操作,然后和下面出现的51个字符的字符串进行对比,正确就通过。
索性丢到OD当中进行动态分析
首先知道程序没有加壳,那么先搜索一下字符串发现了一些端倪
大概都是注册码吧。。。
我就随便跟进了一个,调用了_vbaVarTstEq比较,然后找到了关键跳转,下断点修改标志位。
最后爆破成功
0X02 那么接下来分析一下注册的算法吧
在OD动态调试下做一些批注
0040C061 . 50 push eax ; /Step8 = NULL
0040C062 . 8D55 9C lea edx,dword ptr ss:[ebp-0x64] ; |
0040C065 . 51 push ecx ; |/var18 = C7EF69B9
0040C066 . 52 push edx ; ||retBuffer8 = 00000010
0040C067 . FF15 30104000 call dword ptr ds:[<&MSVBVM60.__vbaLenVa>; |\__vbaLenVar
0040C06D . 50 push eax ; |End8 = NULL
0040C06E . 8D85 3CFFFFFF lea eax,dword ptr ss:[ebp-0xC4] ; |
0040C074 . 8D8D 48FEFFFF lea ecx,dword ptr ss:[ebp-0x1B8] ; |
0040C07A . 50 push eax ; |Start8 = NULL
0040C07B . 8D95 58FEFFFF lea edx,dword ptr ss:[ebp-0x1A8] ; |
0040C081 . 51 push ecx ; |TMPend8 = C7EF69B9
0040C082 . 8D45 DC lea eax,dword ptr ss:[ebp-0x24] ; |
0040C085 . 52 push edx ; |TMPstep8 = 00000010
0040C086 . 50 push eax ; |Counter8 = NULL
0040C087 . FF15 38104000 call dword ptr ds:[<&MSVBVM60.__vbaVarFo>; \__vbaVarForInit
0040C08D > 85C0 test eax,eax ; 设定循环
0040C08F . 0F84 29010000 je Andréna.0040C1BE
0040C095 . 8D4D BC lea ecx,dword ptr ss:[ebp-0x44]
0040C098 . 6A 07 push 0x7
0040C09A . 8D55 8C lea edx,dword ptr ss:[ebp-0x74]
0040C09D . 51 push ecx
0040C09E . 52 push edx
0040C09F . FFD3 call ebx ; msvbvm60.rtcLeftCharVar
0040C0A1 . 8D45 8C lea eax,dword ptr ss:[ebp-0x74]
0040C0A4 . 8D4D B0 lea ecx,dword ptr ss:[ebp-0x50]
0040C0A7 . 50 push eax
0040C0A8 . 51 push ecx
0040C0A9 . FFD6 call esi ; msvbvm60.__vbaStrVarVal
0040C0AB . 50 push eax ; eax=name
0040C0AC . FF15 D8104000 call dword ptr ds:[<&MSVBVM60.#581>] ; msvbvm60.rtcR8ValFromBstr
0040C0B2 . DD9D 34FFFFFF fstp qword ptr ss:[ebp-0xCC] ; 将name转换成浮点数
0040C0B8 . 8D55 9C lea edx,dword ptr ss:[ebp-0x64]
0040C0BB . 8D45 DC lea eax,dword ptr ss:[ebp-0x24]
0040C0BE . 52 push edx
0040C0BF . 50 push eax
0040C0C0 . C745 A4 01000>mov dword ptr ss:[ebp-0x5C],0x1
0040C0C7 . C745 9C 02000>mov dword ptr ss:[ebp-0x64],0x2
0040C0CE . FF15 AC104000 call dword ptr ds:[<&MSVBVM60.__vbaI4Var>; msvbvm60.__vbaI4Var
0040C0D4 . 8D4D BC lea ecx,dword ptr ss:[ebp-0x44]
0040C0D7 . 50 push eax
0040C0D8 . 8D55 B8 lea edx,dword ptr ss:[ebp-0x48]
0040C0DB . 51 push ecx
0040C0DC . 52 push edx
0040C0DD . FFD6 call esi ; msvbvm60.__vbaStrVarVal
0040C0DF . 50 push eax
0040C0E0 . FF15 4C104000 call dword ptr ds:[<&MSVBVM60.#631>] ; msvbvm60.rtcMidCharBstr
0040C0E6 . 8BD0 mov edx,eax ; 第一次取出了第一个字符
0040C0E8 . 8D4D B4 lea ecx,dword ptr ss:[ebp-0x4C]
0040C0EB . FF15 BC104000 call dword ptr ds:[<&MSVBVM60.__vbaStrMo>; msvbvm60.__vbaStrMove
0040C0F1 . 50 push eax ; /String = NULL
0040C0F2 . FF15 20104000 call dword ptr ds:[<&MSVBVM60.#516>] ; \rtcAnsiValueBstr
0040C0F8 . 0FBFC0 movsx eax,ax ; 计算ASCII码
0040C0FB . 8985 B4FCFFFF mov dword ptr ss:[ebp-0x34C],eax
0040C101 . 8D8D 7CFFFFFF lea ecx,dword ptr ss:[ebp-0x84]
0040C107 . DB85 B4FCFFFF fild dword ptr ss:[ebp-0x34C] ; 大概转换成了十进制的浮点数
0040C10D . 51 push ecx
0040C10E . C785 7CFFFFFF>mov dword ptr ss:[ebp-0x84],0x5
0040C118 . DD9D ACFCFFFF fstp qword ptr ss:[ebp-0x354] ; 第一次49,所以第二次50
0040C11E . DD85 ACFCFFFF fld qword ptr ss:[ebp-0x354]
0040C124 . DC85 34FFFFFF fadd qword ptr ss:[ebp-0xCC] ; 与之前转换的name相加
0040C12A . DD5D 84 fstp qword ptr ss:[ebp-0x7C]
0040C12D . DFE0 fstsw ax
0040C12F . A8 0D test al,0xD ; 不知道在测什么。。可能是看看有没有异常,不管了
0040C131 . 0F85 45130000 jnz Andréna.0040D47C
0040C137 . FF15 94104000 call dword ptr ds:[<&MSVBVM60.#572>] ; msvbvm60.rtcHexBstrFromVar
0040C13D . 8985 74FFFFFF mov dword ptr ss:[ebp-0x8C],eax ; 将结果转换成16进制数
0040C143 . 8D55 CC lea edx,dword ptr ss:[ebp-0x34]
0040C146 . 8D85 6CFFFFFF lea eax,dword ptr ss:[ebp-0x94]
0040C14C . 52 push edx
0040C14D . 8D8D 5CFFFFFF lea ecx,dword ptr ss:[ebp-0xA4]
0040C153 . 50 push eax
0040C154 . 51 push ecx
0040C155 . C785 6CFFFFFF>mov dword ptr ss:[ebp-0x94],0x8
0040C15F . FF15 84104000 call dword ptr ds:[<&MSVBVM60.__vbaVarCa>; msvbvm60.__vbaVarCat
0040C165 . 8BD0 mov edx,eax ; 将每次得到的结果拼接到eax后面,第一位是0
0040C167 . 8D4D CC lea ecx,dword ptr ss:[ebp-0x34]
0040C16A . FFD7 call edi ; msvbvm60.__vbaVarMove
0040C16C . 8D55 B0 lea edx,dword ptr ss:[ebp-0x50]
0040C16F . 8D45 B4 lea eax,dword ptr ss:[ebp-0x4C]
0040C172 . 52 push edx
0040C173 . 8D4D B8 lea ecx,dword ptr ss:[ebp-0x48]
0040C176 . 50 push eax
0040C177 . 51 push ecx
0040C178 . 6A 03 push 0x3
0040C17A . FF15 9C104000 call dword ptr ds:[<&MSVBVM60.__vbaFreeS>; msvbvm60.__vbaFreeStrList
0040C180 . 8D95 6CFFFFFF lea edx,dword ptr ss:[ebp-0x94]
0040C186 . 8D85 7CFFFFFF lea eax,dword ptr ss:[ebp-0x84]
0040C18C . 52 push edx
0040C18D . 8D4D 8C lea ecx,dword ptr ss:[ebp-0x74]
0040C190 . 50 push eax
0040C191 . 8D55 9C lea edx,dword ptr ss:[ebp-0x64]
0040C194 . 51 push ecx
0040C195 . 52 push edx
0040C196 . 6A 04 push 0x4
0040C198 . FF15 14104000 call dword ptr ds:[<&MSVBVM60.__vbaFreeV>; msvbvm60.__vbaFreeVarList
0040C19E . 83C4 24 add esp,0x24
0040C1A1 . 8D85 48FEFFFF lea eax,dword ptr ss:[ebp-0x1B8]
0040C1A7 . 50 push eax ; /TMPend8 = NULL
0040C1A8 . 8D8D 58FEFFFF lea ecx,dword ptr ss:[ebp-0x1A8] ; |
0040C1AE . 8D55 DC lea edx,dword ptr ss:[ebp-0x24] ; |
0040C1B1 . 51 push ecx ; |TMPstep8 = C7EF69B9
0040C1B2 . 52 push edx ; |Counter8 = 00000010
0040C1B3 . FF15 C8104000 call dword ptr ds:[<&MSVBVM60.__vbaVarFo>; \__vbaVarForNext
0040C1B9 .^ E9 CFFEFFFF jmp Andréna.0040C08D
0040C1BE > 8D45 CC lea eax,dword ptr ss:[ebp-0x34]
0040C1C1 . 8D8D 4CFFFFFF lea ecx,dword ptr ss:[ebp-0xB4]
0040C1C7 . 50 push eax ; /var18 = NULL
0040C1C8 . 51 push ecx ; |var28 = C7EF69B9
0040C1C9 . C785 54FFFFFF>mov dword ptr ss:[ebp-0xAC],Andréna.0040>; |0817E7WOD7AFF7C7F82836D74RR7A7F7E7B7C7D826D81KE7B7C
0040C1D3 . C785 4CFFFFFF>mov dword ptr ss:[ebp-0xB4],0x8008 ; |嗯,将拼接后得到的结果与指定内容进行比较
0040C1DD . FF15 5C104000 call dword ptr ds:[<&MSVBVM60.__vbaVarTs>; \__vbaVarTstEq
0040C1E3 . 66:85C0 test ax,ax
0040C1E6 . 74 4C je short Andréna.0040C234 ; 关键跳转
0040C1E8 . 8B45 08 mov eax,dword ptr ss:[ebp+0x8]
0040C1EB . 50 push eax
0040C1EC . 8B10 mov edx,dword ptr ds:[eax]
0040C1EE . FF92 38030000 call dword ptr ds:[edx+0x338]
0040C1F4 . 50 push eax
0040C1F5 . 8D45 AC lea eax,dword ptr ss:[ebp-0x54]
0040C1F8 . 50 push eax
0040C1F9 . FF15 3C104000 call dword ptr ds:[<&MSVBVM60.__vbaObjSe>; msvbvm60.__vbaObjSet
0040C1FF . 8B08 mov ecx,dword ptr ds:[eax]
0040C201 . 68 BC1E4000 push Andréna.00401EBC ; REGISTRIERT
0040C206 . 50 push eax
0040C207 . 8985 30FFFFFF mov dword ptr ss:[ebp-0xD0],eax
0040C20D . FF51 54 call dword ptr ds:[ecx+0x54]
0040C210 . 85C0 test eax,eax
这样逻辑就非常清晰了,当然分析中还是用了一些刚学到的小技巧,比如将十六进制存到eax当中的时候发现寄存器窗口无法查看。。
于是在OD的命令行dd eax就能很轻易地看到结果。
根据算法写出注册机即可,但是写的时候发现,逆出来的注册码不是由数字和‘*’、‘#’组成的。。。
这就很尴尬了,于是可以采用爆破的思路。
遍历出50位的注册码,按照算法步骤转换后与正确的验证码对比。找到能正确验证的情况。
但是。。好像运算量挺大的。。于是先搁置了。
总之程序还是把算法分析清楚了。