逆向分析是一個考驗耐心的事情,所以還是按照步驟一步一步來。
就比如這個程序,其實丟到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位的註冊碼,按照算法步驟轉換後與正確的驗證碼對比。找到能正確驗證的情況。
但是。。好像運算量挺大的。。於是先擱置了。
總之程序還是把算法分析清楚了。