有關VB程式P-CODE程式碼逆向工程入門淺說

看雪資料發表於2015-11-15

有關VB程式P-CODE程式碼逆向工程入門淺說

對於破解初學者來說,可能在除錯VB(P-CODE)編寫的程式時感到難於分析和跟蹤,特別是查詢和定位“註冊碼比較”關鍵點,以及修補程式碼等。小弟對VB程式內部構造同樣也是一塌糊塗,對破解更是一知半解,和各位初學者一樣,只是感興趣而已。偶爾嘗試除錯,跟蹤個VB程式玩玩,沒什麼目的。閒著沒事,我們就隨便扯點個人淺顯的經驗,僅供和我一樣的菜鳥同道參考,讓各位高手見笑了。

特別宣告:本文僅僅服務於對VB P-CODE程式破解感興趣的初學者,絕非專業學術研究,不提供任何有關研究分析的科學方法和步驟。

注:如果您僅僅對OLLYDBG除錯VB P-CODE感興趣,請直接參考第4部分。


1.緣起

有天,您正在網上溜達,忽然發現一個感興趣的共享小程式,想拿來用用,可還沒怎麼試,它就跟您較勁兒,老是讓您註冊,煩不煩?我們能受這個限制嗎?… 既然玩保護,那我們們就幫作者測試測試保護的強度,呵呵,考驗我們們的時候又到了。。。3下5/2, 經過您的火眼金睛一看,原來是個VB(P-CODE)捏把的東東。怎麼看出是P-CODE? 方法很多,比如拿WKTVBDE要是能LOAD,我想它就是了,什麼?不知道WKTVBDE是什麼?那用Exdec反一下,什麼,這個也沒聽說過?那我們們先別往下繼續了,您最好先了解一下有關的預備知識,也可以在本論壇搜尋相關vb p-code破解案例分析。擅自推薦您參考“FLY”大俠的破解例項。

對手出現了,怎麼辦?要是我,可能準備如下工具:

VBExplorer (靜態分析P-CODE的好東西,又免費,建議作者繼續完善,堅持不收費政策50年不變 ^&^ )

WKTVBDE (VB P-CODE動態跟蹤偵錯程式,在下一般用它來動態修改程式碼,判斷分析的效果。要想用它真正搞清楚程式的細節,小弟還沒有發現好辦法,但作為粗略的分析工具,檢視程式分支判斷,迴圈次數,它還是蠻好用的。對於分析VB P-CODE,它有如一個大砂輪,先用它磨一磨,精細加工,那是下一個將介紹的工具)

Ollydbg(很不錯的偵錯程式,我用1.09D。好在它的相容性和便捷性,在我的WIN2003 sever上表現很穩定,跟蹤,除錯VB P-CODE再合適不過了,只可惜不是我們們中國人的產品。在本短文稍後,我們們主要就討論如何用它跟蹤分析VB P-CODE,因為這個步驟也算蠻重要嘛)

還有其它一些可以選擇的工具,就看您的個人愛好了,比如:

Exdec vb p-code程式碼反編譯器,不錯的工具
Vbparser 1.2 同樣是 vb p-code反編譯器,不過我用的版本不能反VB 5, 有些vb 6的也不行,不知道是怎麼回事。

還有什麼好工具希望您告訴我。

2.鬼窮三技

聊齋上說,小鬼兒也沒什麼可怕的,也就有3招,你知道了,對付它就心裡有了底,有了戰勝它的信心。話說VB P-CODE程式,我們們這些新手外行如何搞定它呢?我們們也來個3招克敵:

a.靜態分析:粗略搞清楚目標程式的大致流程,分支,憑分析結果和程式設計,破解的經驗,判斷和假設目標程式的設計思路
b.程式碼還原:根據p-code虛擬碼,大致可以還原出VB源程式程式碼(針對關鍵和重要的部分,對於破解,就是還原判斷有關的和比較註冊碼前後部分的VB程式碼)
c.動態跟蹤:應用原始碼級偵錯程式(例如olldbg)跟蹤程式的執行細節,發現重要資料,甚至註冊碼等資訊

空口無憑,我們們還是透過一個簡單案例來演示一下整個的VB P-CODE逆向過程,如何?

3.循序漸進

為了演示方便,我們們先寫一個簡單的VB註冊小程式,原始碼如下(程式未經任何最佳化,僅用於演示):

Private Sub Text1_Change()
 
  Dim i As Byte
 
  For i = 1 To Len(Text1.Text)
  
  If Mid(Text1.Text, i, 1) > "9" Or Mid(Text1.Text, i, 1) < "0" Then
   
   Text2.Text = "Please enter 0-9, try again"
   GoTo final_end
  End If
  
  Next
 
 If Len(Text1.Text) >= 3 Then
 
  get_1 = CInt(Mid(Text1.Text, 1, 1))
  get_2 = CInt(Mid(Text1.Text, 2, 1))
  get_3 = CInt(Mid(Text1.Text, 3, 1))
  
  get_4 = get_2 + get_3
  
  If get_1 = get_4 Then
  Text2.Text = "good"
  Else
  Text2.Text = "bad"
  End If
 
 End If
 
final_end:
 
End Sub

程式僅僅根據使用者輸入的數字判斷是否符合內定的規則,如果是,顯示:good,錯誤,則提示:bad。程式很簡單,您自己看一下就明白了,我們們就不再詳細解釋了,不耽誤您的時間了。

這段小程式對應的P-CODE程式碼如下(使用VBExplorer獲得,相關程式可以從本論壇得到,或聯絡作者):

[Text1.Change]
:00401B9C  F401                LitI2_Byte           ;Push 01
:00401B9E  FC0D                CUI1I2               ;
:00401BA0  047AFF              FLdRfVar             ;Push LOCAL_0086
:00401BA3  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401BA6  21                  FLdPrThis            ;[SR]=[stack2]
:00401BA7  0F0003              VCallAd              ;Return the control index 02
:00401BAA  1974FF              FStAdFunc            ;

For i = 1 To Len(Text1.Text)

:00401BAD  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text
:00401BB0  0DA0000000          VCallHresult         ;Call ptr_004016B8
:00401BB5  6C70FF              ILdRf                ;Push DWORD [LOCAL_0090]
:00401BB8  4A                  FnLenStr    ;取得輸入串的長度,作為迴圈的引數
:00401BB9  FC0E                CUI1I4               ;
:00401BBB  2F70FF              FFree1Str            ;SysFreeString [LOCAL_0090];
:00401BBE  1A74FF              FFree1Ad             ;Push [LOCAL_008C];  
:00401BC1  FE626CFFD900        ForUI1      ; 迴圈開始
:00401BC7  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401BCA  21                  FLdPrThis            ;[SR]=[stack2]
:00401BCB  0F0003              VCallAd              ;Return the control index 02
:00401BCE  1974FF              FStAdFunc            ;
:00401BD1  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text  ;出現這個提示,說明程式中參照了輸入框內容
:00401BD4  0DA0000000          VCallHresult         ;Call ptr_004016B8

If Mid(Text1.Text, i, 1) > "9" Or Mid(Text1.Text, i, 1) < "0" Then

:00401BD9  0404FF              FLdRfVar             ;Push LOCAL_00FC
:00401BDC  21                  FLdPrThis            ;[SR]=[stack2]
:00401BDD  0F0003              VCallAd              ;Return the control index 02
:00401BE0  1908FF              FStAdFunc            ;
:00401BE3  0808FF              FLdPr                ;[SR]=[LOCAL_00F8]
***********Reference To:[propget]TextBox.Text
:00401BE6  0DA0000000          VCallHresult         ;Call ptr_004016B8
:00401BEB  283CFF0100          LitVarI2    ;Push 數字 1
:00401BF0  FCE07AFF            FLdUI1               ;
:00401BF4  E7                  CI4UI1      ;Push 變數 i
:00401BF5  3E70FF              FLdZeroAd            ; 
:00401BF8  465CFF              CVarStr              ;
:00401BFB  042CFF              FLdRfVar             ;
**********Reference To->msvbvm60.rtcMidCharVar       ;呼叫了Mid 函式,一般相關的引數在呼叫前已經入棧,注意上邊兩個PUSH指令,引數入棧順序是從右到左,對於MID,既是壓入1,i。意思是取從第i個開始的字元,總共取1個。

:00401BFE  0A01001000          ImpAdCallFPR4        ;Call ptr_00401020; 
:00401C03  042CFF              FLdRfVar             ;Push LOCAL_00D4
******Possible String Ref To->"9"    ;表示”9”這個文字字元被引用   
:00401C06  3A1CFF0200          LitVarStr            ;PushVarString ptr_004016CC
:00401C0B  5D                  HardType             ;
:00401C0C  FB700CFF            GtVar                ;
:00401C10  28D4FE0100          LitVarI2 ;Push 數字 1
:00401C15  FCE07AFF            FLdUI1               ;
:00401C19  E7                  CI4UI1   ;Push 變數 i
:00401C1A  3E04FF              FLdZeroAd            ;
:00401C1D  46F4FE              CVarStr              ;
:00401C20  04C4FE              FLdRfVar             ;
**********Reference To->msvbvm60.rtcMidCharVar
:00401C23  0A01001000          ImpAdCallFPR4        ;Call ptr_00401020;
:00401C28  04C4FE              FLdRfVar             ;Push LOCAL_013C
******Possible String Ref To->"0"
:00401C2B  3AB4FE0300          LitVarStr ; 表示”0”文字字串被引用
:00401C30  5D                  HardType             ;
:00401C31  FB63A4FE            LtVar                ;
:00401C35  FB1F94FE            OrVar     ; or 另一個條件
:00401C39  FF1B                CBoolVarNull         ;vbaBoolVarNull
:00401C3B  29040074FF08FF      FFreeAd              ;
:00401C42  360C005CFF3CFF2C    FFreeVar             ;Free 000C/2 variants
:00401C51  1CD000              BranchF   ;比較指令,
******Possible String Ref To->"Please enter 0-9, try again"

Text2.Text = "Please enter 0-9, try again"        ;如果輸入字元無效,提示重新輸入

:00401C54  1B0400              LitStr               ;Push ptr_004016DC
:00401C57  21                  FLdPrThis            ;[SR]=[stack2]
:00401C58  0F0803              VCallAd              ;Return the control index 04
:00401C5B  1974FF              FStAdFunc            ;
:00401C5E  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propput]TextBox.Text
:00401C61  0DA4000000          VCallHresult         ;Call ptr_004016B8
:00401C66  1A74FF              FFree1Ad             ;

GoTo final_end

:00401C69  1E1002              Branch               ;ESI=00401DAC
:00401C6C  047AFF              FLdRfVar             ;Push LOCAL_0086

Next

:00401C6F  FE786CFF2B00        NextUI1       ; 迴圈部分中止
:00401C75  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401C78  21                  FLdPrThis            ;[SR]=[stack2]
:00401C79  0F0003              VCallAd              ;Return the control index 02
:00401C7C  1974FF              FStAdFunc            ;

If Len(Text1.Text) >= 3 Then

:00401C7F  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text      
:00401C82  0DA0000000          VCallHresult         ;Call ptr_004016B8
:00401C87  6C70FF              ILdRf                ;Push DWORD [LOCAL_0090]
:00401C8A  4A                  FnLenStr     ; 輸入字串長度
:00401C8B  F503000000          LitI4        ;常數3用於比較
:00401C90  E0                  GeI4                 ;
:00401C91  2F70FF              FFree1Str            ;SysFreeString [LOCAL_0090]; 
:00401C94  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; 
:00401C97  1C1002              BranchF      ;比較判斷

get_1 = CInt(Mid(Text1.Text, 1, 1))

:00401C9A  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401C9D  21                  FLdPrThis            ;[SR]=[stack2]
:00401C9E  0F0003              VCallAd              ;Return the control index 02
:00401CA1  1974FF              FStAdFunc            ;
:00401CA4  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text
:00401CA7  0DA0000000          VCallHresult         ;
:00401CAC  283CFF0100          LitVarI2        ; Push 1 引數,用於MID函式 取幾個字元
:00401CB1  F501000000          LitI4           ;Push 1 引數,用於MID函式
                                                        ;表示 從哪個字元位置開始取
:00401CB6  3E70FF              FLdZeroAd            ;Push DWORD [LOCAL_0090]; 
:00401CB9  465CFF              CVarStr              ;
:00401CBC  042CFF              FLdRfVar             ;Push LOCAL_00D4
**********Reference To->msvbvm60.rtcMidCharVar          ;mid函式呼叫
                               |
:00401CBF  0A01001000          ImpAdCallFPR4        ;Call ptr_00401020; check stack 0010; Push EAX
:00401CC4  042CFF              FLdRfVar             ;Push LOCAL_00D4
:00401CC7  FC45                FnCIntVar            ;vbaI2ErrVar
:00401CC9  441CFF              CVarI2               ;
:00401CCC  FCF684FE            FStVar               ;
:00401CD0  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; Call  
:00401CD3  3608005CFF3CFF2C    FFreeVar             ;Free 0008/2 variants

get_2 = CInt(Mid(Text1.Text, 2, 1))

:00401CDE  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401CE1  21                  FLdPrThis            ;[SR]=[stack2]
:00401CE2  0F0003              VCallAd              ;Return the control index 02
:00401CE5  1974FF              FStAdFunc            ;
:00401CE8  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text
:00401CEB  0DA0000000          VCallHresult         ;Call ptr_004016B8
:00401CF0  283CFF0100          LitVarI2             ;PushVarInteger 0001
:00401CF5  F502000000          LitI4                ;Push 00000002
:00401CFA  3E70FF              FLdZeroAd            ;Push DWORD [LOCAL_0090]; 
:00401CFD  465CFF              CVarStr              ;
:00401D00  042CFF              FLdRfVar             ;Push LOCAL_00D4
**********Reference To->msvbvm60.rtcMidCharVar
:00401D03  0A01001000          ImpAdCallFPR4        ;Call ptr_00401020;
:00401D08  042CFF              FLdRfVar             ;Push LOCAL_00D4
:00401D0B  FC45                FnCIntVar            ;vbaI2ErrVar
:00401D0D  441CFF              CVarI2               ;
:00401D10  FCF674FE            FStVar               ;
:00401D14  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; Call 
:00401D17  3608005CFF3CFF2C    FFreeVar             ;Free 0008/2 variants

get_3 = CInt(Mid(Text1.Text, 3, 1))

:00401D22  0470FF              FLdRfVar             ;Push LOCAL_0090
:00401D25  21                  FLdPrThis            ;[SR]=[stack2]
:00401D26  0F0003              VCallAd              ;Return the control index 02
:00401D29  1974FF              FStAdFunc            ;
:00401D2C  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propget]TextBox.Text
:00401D2F  0DA0000000          VCallHresult         ;Call ptr_004016B8
:00401D34  283CFF0100          LitVarI2             ;PushVarInteger 0001
:00401D39  F503000000          LitI4                ;Push 00000003
:00401D3E  3E70FF              FLdZeroAd            ;Push DWORD [LOCAL_0090]; 
:00401D41  465CFF              CVarStr              ;
:00401D44  042CFF              FLdRfVar             ;Push LOCAL_00D4
**********Reference To->msvbvm60.rtcMidCharVar
:00401D47  0A01001000          ImpAdCallFPR4        ;Call ptr_00401020; check stack 0010; Push EAX
:00401D4C  042CFF              FLdRfVar             ;Push LOCAL_00D4
:00401D4F  FC45                FnCIntVar            ;vbaI2ErrVar
:00401D51  441CFF              CVarI2               ;
:00401D54  FCF664FE            FStVar               ;
:00401D58  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; Call 
:00401D5B  3608005CFF3CFF2C    FFreeVar             ;Free 0008/2 variants

get_4 = get_2 + get_3

:00401D66  0474FE              FLdRfVar      ;Push 變數1 用於相加
:00401D69  0464FE              FLdRfVar      ;Push 變數2 用於相加
:00401D6C  FB945CFF            AddVar               ;
:00401D70  FCF654FE            FStVar               ;

If get_1 = get_4 Then

:00401D74  0484FE              FLdRfVar      ;Push 變數1 用於比較
:00401D77  0454FE              FLdRfVar      ;Push 變數2 用於比較
:00401D7A  FB33                EqVarBool            ;
:00401D7C  1CFB01              BranchF       ;比較判斷結果
******Possible String Ref To->"good"

Text2.Text = "good"                                   ;正確

:00401D7F  1B0500              LitStr               ;Push ptr_00401718
:00401D82  21                  FLdPrThis            ;[SR]=[stack2]
:00401D83  0F0803              VCallAd              ;Return the control index 04
:00401D86  1974FF              FStAdFunc            ;
:00401D89  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propput]TextBox.Text
:00401D8C  0DA4000000          VCallHresult         ;Call ptr_004016B8
:00401D91  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; Call 

Else
  Text2.Text = "bad"

:00401D94  1E1002              Branch               ;ESI=00401DAC
******Possible String Ref To->"bad"
:00401D97  1B0600              LitStr               ;Push ptr_00401728
:00401D9A  21                  FLdPrThis            ;[SR]=[stack2]
:00401D9B  0F0803              VCallAd              ;Return the control index 04
:00401D9E  1974FF              FStAdFunc            ;
:00401DA1  0874FF              FLdPr                ;[SR]=[LOCAL_008C]
***********Reference To:[propput]TextBox.Text
:00401DA4  0DA4000000          VCallHresult         ;Call ptr_004016B8
:00401DA9  1A74FF              FFree1Ad             ;Push [LOCAL_008C]; Call 
:00401DAC  13                  ExitProcHresult      ;
:00401DAD  0000                LargeBos             ;IDE beginning of line 

注意:以上偽碼中提示的VB原始碼行,可能並不是精確的定位,僅是小弟憑經驗加入的,僅供參考。由於在下對P-CODE以及VBExplorer都不甚瞭解,許多虛擬碼的含義,以及其在VBExplorer中給出的註釋,都不能明瞭箇中的含義,還望瞭解者指點,多謝。

不論如何,根據P-CODE程式碼,我們可以大致分析出粗略的程式流程,變數的使用和定位並不一定精確,許多還要憑您的破解經驗和程式設計經驗。但是,這個粗略的分析可以幫助我們模擬出大致的VB原始碼。

在反向出粗略的VB原始碼的過程中,您要不斷將您寫出的VB程式碼編譯後P-CODE程式碼與源程式反編譯後的P-code程式碼進行比對,儘量使其一致,至少看上去相似。這個過程需要您花些時間了,您要假設,如果你就是作者,你會如何寫,特別是變數的運用,型別的定義,程式設計的習慣以及經驗等。這個過程在不斷的進行中,會使你逐漸積累更多有益的經驗,不知不覺中,你就會有一種“感覺”,以前,那個臺灣寫破解教程的老兄說這個叫“觸機”,大概對應的英文詞是“sense”。總之,您就是知道了,似乎一下就明白了,原來做這個程式的老兄是這樣的,是這個意思。好了,下一步就是驗證我們的思路是否真的就是對的了。


4.著法寶

通常,我們可以用WKTVBDE跟蹤程式P-CODE,看看它在關鍵部分的迴圈,分支走向,在某些關節點(P-CODE虛擬碼,或者是某個VB函式呼叫上)設斷點,這樣,基本上可以將我們模擬出來的VB原始碼中大的框架構造搞清楚,設定好基本的分支條件。那麼,到底在程式的細節實現上,哪裡使用了哪些變數,關鍵的比較點,比較的變數值是怎樣計算得到的,還有什麼隱藏的花招,以及一些細節的東西?為了快速獲得有益的資訊,我們還是應該透過OLLDBG這樣的實時偵錯程式去觀察分析。

在應用OLLDBG除錯VB P-CODE程式碼時,我們應該注意幾點:

一般VB中的使用的區域性變數位置在記憶體中是不確定的,這次除錯和上次除錯的同一變數位置基本是不同的,是動態產生的,所以,不要象除錯其他C編譯或彙編程式那樣,下一個固定的記憶體斷點去發現某些變數的變化(僅僅是個人意見,不一定對)。

VB P-CODE編譯的程式執行時,在主要流程中,通常ESI暫存器指向相應的VB p-code虛擬碼。 所以,除錯時,最好同時開啟相應程式的P-CODE虛擬碼(例如執行VBExplorer,並開啟相應的程式。為了便於分析,可以是同樣程式的複製副本),以供參考,檢視程式的實際流程。

通常,vb 程式執行在虛擬機器(MSVBVM60.DLL)中 ,因此,當您使用OLLDBG開啟一個vb p-code程式後,應該在選單中選擇“view”選項,然後再進入選擇“Executable modules”, 並在其中的“MSVBVM60”行上,點選滑鼠右鍵,然後選“view name”。如此,可以直接檢視VB執行庫中的函式名,查詢有關的函式名,在常用的函式名上點選,並設定斷點。

例如:在rtcMidCharVar上設定斷點:
在我得機器上是:7352B403 > 55    PUSH EBP

例如:設定條件斷點 esi = = 401BEF ;ESI指向的P-CODE程式碼,應該是你在分析目標程式後,認為重要的呼叫了MID函式的位置。參考上面的演示程式,我們假定要檢視兩個MID函式被呼叫的位置,這兩個位置可能是:
語句If Mid(Text1.Text, i, 1) > "9" Or Mid(Text1.Text, i, 1) < "0" 中的兩個呼叫了MID的地方(p-code程式碼的相對位置):00401BFE 和 00401C23(VBExplorer 中看到的)

當程式中斷在您設定的斷點後,你可以逐步跟蹤程式了,為了把握住程式的流向,您要時刻關注ESI值的變化,它通常在40xxxx範圍內,它明確地指向VB P-CODE虛擬碼的流向,你不用擔心不知道自己所在的位置。你可以隨時切換到VBExplorer中,看看程式到底跑到哪裡去了。

在您除錯的過程中,您會發CALL AX,應該單步跟進去,它通常會帶你返回那個正被除錯的VB程式主域(或叫“領空”,學臺灣人的說法),一般附近是一些JMP長跳轉,這些是程式中需要呼叫函式,應該給予重視,可以嘗試在相關函式上下斷點。

當您看到call bx時,通常程式要呼叫真正的函式執行功能,你應該跟進去,一般在執行P-CODE比較偽指令的過程中,你會發現一個call bx,一定要跟進去,通常會它引導你看到真正的註冊碼以及你輸入的假註冊碼進行比較。透過觀察堆疊的顯示,你就可以看到他們,兩個可愛的字串(通常出現在OLLYDBG的除錯視窗的右下方)。

跟蹤VB程式時,通常會看到如下的程式碼:

7353F7B7   3BFC             CMP EDI,ESP
7353F7B9   0F85 D67D0000    JNZ MSVBVM60.73547595
7353F7BF   33C0             XOR EAX,EAX
7353F7C1   8A06             MOV AL,BYTE PTR DS:[ESI]
7353F7C3   46               INC ESI
7353F7C4   FF2485 58FA5373  JMP DWORD PTR DS:[EAX*4+7353FA58]

7353F7CB   0FB70E           MOVZX ECX,WORD PTR DS:[ESI]
7353F7CE   0FB77E 02        MOVZX EDI,WORD PTR DS:[ESI+2]
7353F7D2   83C6 04          ADD ESI,4
7353F7D5   03FC             ADD EDI,ESP
7353F7D7   8B55 AC          MOV EDX,DWORD PTR SS:[EBP-54]
7353F7DA   8B048A           MOV EAX,DWORD PTR DS:[EDX+ECX*4]
7353F7DD   0BC0             OR EAX,EAX
7353F7DF   90               NOP
7353F7E0   0F84 027F0000    JE MSVBVM60.735476E8
7353F7E6   803D B4115573 00 CMP BYTE PTR DS:[735511B4],0
7353F7ED   0F85 037F0000    JNZ MSVBVM60.735476F6
7353F7F3   FFD0             CALL EAX
7353F7F5   3BFC             CMP EDI,ESP
7353F7F7   0F85 987D0000    JNZ MSVBVM60.73547595
7353F7FD   50               PUSH EAX
7353F7FE   33C0             XOR EAX,EAX
7353F800   8A06             MOV AL,BYTE PTR DS:[ESI]
7353F802   46               INC ESI
7353F803   FF2485 58FA5373  JMP DWORD PTR DS:[EAX*4+7353FA58]

7353F80A   0FB706           MOVZX EAX,WORD PTR DS:[ESI]

其中:
7353F7BF   33C0             XOR EAX,EAX
7353F7C1   8A06             MOV AL,BYTE PTR DS:[ESI]
7353F7C3   46               INC ESI
7353F7C4   FF2485 58FA5373  JMP DWORD PTR DS:[EAX*4+7353FA58]
既是虛擬碼的執行模板。JMP指令轉入偽指令的執行,不斷按下“F8”,盯著esi暫存器的變化,參照vbexplorer中提示的p-code,你就不會迷失方向(通常是這樣。當然,如果你按錯了鍵,那就是你自己的事了,別怪我沒提醒你)


大結局

關於最後的修改VB P-CODE程式碼,暴力破解法,據我所知一般只要能將重要的轉移指令改變就可以了。無非是在您選好的比較指令的位置將BranchF(虛擬碼1c)BranchT(1d) 或者Branch(1e)改來改去。別的好招我還不會呢,等著我們們繼續切磋。

有空的朋友,還可以分析程式中的演算法,只要花功夫,沒什麼看不懂的。除非程式設計序的那位憋著勁和我們們作對,不怕,我們不用他的軟體了還不行?我是菜鳥,我怕誰?

夠了,說了一堆有用沒用的廢話,您自己看著辦8,您也聽累了,我手也酸了。總之,vb p-code畢竟是由高階語言轉換來的,應該不難分析和跟蹤,只是特點不同,掌握了基本的要點,用OLLDBG跟蹤沒什麼難的。現在又有WKTVBDE 和vbexplorer助陣,一邊捏著P-CODE,一邊瞄著ESI, 祭起OLLYDBG,一手按著F8,您說,我們還怕誰呀?

什麼逆向工程,什麼VB,  V JQK,誰是破解高手?不就是花時間嘛。
唉,所以高手都不來發言了,所以,您和我,還是菜鳥。苦惱中。。。。

要是那位高手作個OLLDBG的VB P-CODE外掛,一遇到VB p-code中JMP DWORD PTR DS:[EAX*4+&*%$@$^] 就顯示相關的P-CODE指令就更方便了,尤其期待中。。。。

相關文章