淺談VB6逆向工程(4)

看雪資料發表於2004-12-27

4. VB內部函式
    1) 自定義函式的呼叫
    
    這裡我們看看和VB的內部函式有關的一些內容。
    老規矩,先看一段程式碼:
    Function myadd(ByVal a As Variant, b As Variant)
        myadd = a + b
    End Function
    
    Sub myprint(ByVal a As Variant)
        Print a
    End Sub
        
    Private Sub Command1_Click()
        Dim a, b, c
    
        a = 10
        b = 20
        c = myadd(a, b)
        myprint c
    End Sub 
    
    這段程式碼裡包含了自定義的過程,函式及函式的兩種引數傳遞方式。下面的反彙編程式碼
是過程Command1_Click()的。自定義的函式和過程的反彙編程式碼和這相仿,可以位元組反匯
編對比看一下。
    反彙編程式碼如下,預設方式(速度最佳化)編譯的,這次給出的是完整的彙編程式碼:
    
00401C50   PUSH EBP
00401C51   MOV EBP,ESP
00401C53   SUB ESP,0C 

00401C56   PUSH <JMP.&MSVBVM60.__vbaExceptHandler>              
00401C5B   MOV EAX,DWORD PTR FS:[0]
00401C61   PUSH EAX
00401C62   MOV DWORD PTR FS:[0],ESP  //安裝區域性執行緒異常

00401C69   SUB ESP,5C                //下面這一段和vb編譯器有關
00401C6C   PUSH EBX                  //因為vb是基於com技術實現的
00401C6D   PUSH ESI                  //更詳細的內容可以參考
00401C6E   PUSH EDI                  //<<軟體加密技術內幕>>一書
00401C6F   MOV DWORD PTR SS:[EBP-C],ESP
00401C72   MOV DWORD PTR SS:[EBP-8],工程2.004010B0
00401C79   MOV ESI,DWORD PTR SS:[EBP+8]
00401C7C   MOV EAX,ESI
00401C7E   AND EAX,1
00401C81   MOV DWORD PTR SS:[EBP-4],EAX
00401C84   AND ESI,FFFFFFFE
00401C87   PUSH ESI
00401C88   MOV DWORD PTR SS:[EBP+8],ESI  //me
00401C8B   MOV ECX,DWORD PTR DS:[ESI]
00401C8D   CALL DWORD PTR DS:[ECX+4]   ;MSVBVM60.Zombie_AddRef

00401C90   MOV EDI,DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]      
00401C96   XOR EBX,EBX
00401C98   MOV DWORD PTR SS:[EBP-64],EBX
00401C9B   LEA EDX,DWORD PTR SS:[EBP-64]
00401C9E   LEA ECX,DWORD PTR SS:[EBP-24]
00401CA1   MOV DWORD PTR SS:[EBP-24],EBX
00401CA4   MOV DWORD PTR SS:[EBP-34],EBX
00401CA7   MOV DWORD PTR SS:[EBP-44],EBX
00401CAA   MOV DWORD PTR SS:[EBP-54],EBX
00401CAD   MOV DWORD PTR SS:[EBP-5C],0A  //10
00401CB4   MOV DWORD PTR SS:[EBP-64],2   //integer
00401CBB   CALL EDI   
                                         //a = 10 
00401CBD   LEA EDX,DWORD PTR SS:[EBP-64]
00401CC0   LEA ECX,DWORD PTR SS:[EBP-34]
00401CC3   MOV DWORD PTR SS:[EBP-5C],14  //20
00401CCA   MOV DWORD PTR SS:[EBP-64],2   //integer
00401CD1   CALL EDI
                                         // b = 20
00401CD3   LEA EAX,DWORD PTR SS:[EBP-54]
00401CD6   LEA ECX,DWORD PTR SS:[EBP-34]
00401CD9   PUSH EAX                      //存放函式的返回值
00401CDA   PUSH ECX                      //引用引數b
00401CDB   MOV ECX,DWORD PTR SS:[EBP-24]
00401CDE   SUB ESP,10                    //這個空間複製變數引數a
00401CE1   MOV EAX,ESP                   //變體型別,所以要16個位元組
00401CE3   MOV EDX,DWORD PTR DS:[ESI]
00401CE5   PUSH ESI                      //me
00401CE6   MOV DWORD PTR DS:[EAX],ECX
00401CE8   MOV ECX,DWORD PTR SS:[EBP-20]
00401CEB   MOV DWORD PTR DS:[EAX+4],ECX
00401CEE   MOV ECX,DWORD PTR SS:[EBP-1C]
00401CF1   MOV DWORD PTR DS:[EAX+8],ECX
00401CF4   MOV ECX,DWORD PTR SS:[EBP-18]
00401CF7   MOV DWORD PTR DS:[EAX+C],ECX
00401CFA   CALL DWORD PTR DS:[EDX+6F8]    //呼叫函式 myadd
00401D00   CMP EAX,EBX
00401D02   JGE SHORT 工程2.00401D16
00401D04   PUSH 6F8
00401D09   PUSH 工程2.00401644
00401D0E   PUSH ESI
00401D0F   PUSH EAX
00401D10   CALL DWORD PTR DS:[<&MSVBVM60.__vbaHresultCheckObj>] 
00401D16   LEA EDX,DWORD PTR SS:[EBP-54]  
00401D19   LEA ECX,DWORD PTR SS:[EBP-44]  
00401D1C   CALL EDI       
                                          //把結果賦值給變數c
                                          
00401D1E   MOV ECX,DWORD PTR SS:[EBP-44]  //c作為變數引數傳遞
00401D21   SUB ESP,10                     //所以這裡要分配16個位元組
00401D24   MOV EAX,ESP
00401D26   MOV EDX,DWORD PTR DS:[ESI]
00401D28   PUSH ESI                       //me
00401D29   MOV DWORD PTR DS:[EAX],ECX
00401D2B   MOV ECX,DWORD PTR SS:[EBP-40]
00401D2E   MOV DWORD PTR DS:[EAX+4],ECX
00401D31   MOV ECX,DWORD PTR SS:[EBP-3C]
00401D34   MOV DWORD PTR DS:[EAX+8],ECX
00401D37   MOV ECX,DWORD PTR SS:[EBP-38]
00401D3A   MOV DWORD PTR DS:[EAX+C],ECX
00401D3D   CALL DWORD PTR DS:[EDX+6FC]    //呼叫myprint
00401D43   CMP EAX,EBX
00401D45   JGE SHORT 工程2.00401D59
00401D47   PUSH 6FC
00401D4C   PUSH 工程2.00401644
00401D51   PUSH ESI
00401D52   PUSH EAX
00401D53   CALL DWORD PTR DS:[<&MSVBVM60.__vbaHresultCheckObj>] 


00401D59   MOV DWORD PTR SS:[EBP-4],EBX
00401D5C   PUSH 工程2.00401D83            //這裡壓入返回地址
00401D61   JMP SHORT 工程2.00401D6D
00401D63   LEA ECX,DWORD PTR SS:[EBP-54]
00401D66   CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeVar>]         
00401D6C   RETN

00401D6D   MOV ESI,DWORD PTR DS:[<&MSVBVM60.__vbaFreeVar>]      
00401D73   LEA ECX,DWORD PTR SS:[EBP-24]
00401D76   CALL ESI                                             
00401D78   LEA ECX,DWORD PTR SS:[EBP-34]
00401D7B   CALL ESI
00401D7D   LEA ECX,DWORD PTR SS:[EBP-44]
00401D80   CALL ESI
00401D82   RETN                           //上面這裡釋放變數a,b,c

00401D83   MOV EAX,DWORD PTR SS:[EBP+8]   //返回到這裡做善後處理
00401D86   PUSH EAX
00401D87   MOV EDX,DWORD PTR DS:[EAX]
00401D89   CALL DWORD PTR DS:[EDX+8] ;  MSVBVM60.Zombie_Release
00401D8C   MOV EAX,DWORD PTR SS:[EBP-4]
00401D8F   MOV ECX,DWORD PTR SS:[EBP-14]
00401D92   POP EDI
00401D93   POP ESI
00401D94   MOV DWORD PTR FS:[0],ECX       //恢復區域性執行緒異常
00401D9B   POP EBX
00401D9C   MOV ESP,EBP
00401D9E   POP EBP
00401D9F   RETN 4

    從這裡可以看出,在呼叫自程式時還要傳遞一個me引數。對於函式來說,還有一個
返回結果要傳遞過去。

    2) VB的內部函式
    VB的內部函式在反彙編程式碼中看起來和我們熟悉的函式名並不一樣。這一點跟蹤過
VB程式的人一定深有體會。大多數函式名都可以從名字上猜出來。但也有相差太多的。
我整理了一份函式列表。不是全部,但包含了大多數內部函式,應該能應付一般的應用。
函式列表在這個貼子的附件中。
    VB的運算子大多是用函式實現的。這是一個好訊息。這意味著我們不必費力去分析
過多的程式碼而只要能辨別出那些函式名即可。
    VB的內部函式並不都是以Stdcall的方式傳遞引數,儘管大部分是這樣的。分析
VB程式時要注意這點。
    VB的反彙編程式碼中大部分的函式都要傳遞一個存放返回值的變數,而且返回值也會
在EAX中或者浮點棧中返回。
    這裡只舉一個例子。其他的可以參考我整理的列表。
    
    這是函式instr,常用的一個:
    
__vbaInStrVar       ;函式 InStr(起始位置,源字串,目標字串,比較方式)      

LEA EDX,DWORD PTR SS:[EBP-24]                
PUSH 1                         ;起始位置,從1開始             
LEA EAX,DWORD PTR SS:[EBP-34]                
PUSH EDX                       ;被搜尋的字串              
PUSH EAX                       ;要搜的字串              
LEA ECX,DWORD PTR SS:[EBP-54]                
PUSH 1                         ;比較方式              
PUSH ECX                       ;返回的結果              
CALL DWORD PTR DS:[<&MSVBVM60.__vbaInStrVar>]
MOV EDX,EAX                    ;結果同時在eax中返回

    
    3) VB的外部函式呼叫
    VB對外部函式的呼叫是如何實現的呢?先看看下面的程式碼:
Private Declare Function MessageBeep Lib "user32" (ByVal wType As Long) As Long
Private Sub Command1_Click()
    MessageBeep 0
End Sub
    對應的反彙編程式碼如下:
    
00401A2F   PUSH 0              //這裡壓入引數
00401A31   CALL 工程2.004016C8 //這個Call我們要繼續跟進才知道呼叫的什麼函式
00401A36   CALL DWORD PTR DS:[<&MSVBVM60.__vbaSetSystemError>]  


004016C8   MOV EAX,DWORD PTR DS:[4022DC] //第一次呼叫時為0,以後就呼叫這裡
004016CD   OR EAX,EAX                    //這個程式裡為0
004016CF   JE SHORT 工程2.004016D3
004016D1   JMP EAX
004016D3   PUSH 工程2.004016B0            //注意這個地址,這是指向程式碼段的
                                         //我們先看看這裡有什麼
004016B0  98 16 40 00 A4 16 40 00  ?@.?@.
                                         //再跟進
00401698  75 73 65 72 33 32 00 00  user32..
004016A0  0C 00 00 00 4D 65 73 73  ....Mess
004016A8  61 67 65 42 65 65 70 00  ageBeep.
                                         //是不是看到了要呼叫的函式了^_^
                                         //其實不用這麼麻煩
004016D8   MOV EAX,<JMP.&MSVBVM60.DllFunctionCall>
004016DD   CALL EAX                      //執行完這一行看eax,看到什麼了
                                         //EAX 84936A78 Thunk to USER32.MessageBeep
004016DF   JMP EAX                       //這裡就是真正的呼叫了

    注意:呼叫的外部函式名不在程式的匯入表裡,而是在程式碼段裡。程式是呼叫
函式MSVBVM60.DllFunctionCall來取得外部函式的地址的。

附件:vb函式.rar

相關文章