淺談VB6逆向工程(1)

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

前言                                
   
   VB的編譯有兩種方式,一種是P-Code方式,一種是本機程式碼。P_Code方式是VB
從早期版本保留下來的,也是比較難逆向的一種。而本機程式碼方式編譯的程式已經
和VC很接近了。這裡只探討以本機程式碼方式編譯的程式。由於微軟在VB的實現方面
的資料很少,使人覺得VB的逆向比較難。其實掌握一些規律,VB的程式還是很容易
入門的。
    這裡所提到的知識都是個人的經驗,沒有什麼官方的資料作為依據。所以錯誤
之處難免,如果你發現什麼錯誤,歡迎指正。


                       1. 從簡單變數的實現開始
    
   一個VB簡單變數的表示至少需要12個位元組。通常前2個位元組是表示型別資訊的。
從第5個位元組到第8個位元組並不總是使用到,實際上很少被使用。我們不妨先叫它
輔助型別資訊。從第9個位元組開始就是真正的變數的值了。這裡有可能儲存一個指標
值,也可能是資料,具體是什麼取決於變數型別。
    另一個值得注意的事實是VB的記憶體是以4個位元組對齊的。即使你使用一個位元組,
那至少也要4個位元組來表示。而且編譯器只初始化它需要的那些位元組,剩餘的位元組
可能是隨機資料。下面我們將會看到這些。
              

    想弄明白編譯器在內部怎麼實現的,最好的方法就是編一段程式跟蹤執行看看。
我編寫的程式碼如下:

    Dim a, i As Byte
    Dim b, j As Integer
    Dim c, k As Long
    Dim d, l As Boolean
    Dim e, m As String
    Dim f, n As Date
    Dim g, o As Double
    Dim h, p As Single
    
    a = &H30
    b = 330
    c = 66000
    d = True
    e = "hello"
    f = Now
    g = 3.1415
    h = 1.27
    
    i = a
    j = b
    k = c
    l = d
    m = e
    n = f
    o = g
    p = h
    這段程式碼在VB的預設設定(速度最佳化)下編譯。然後用od反彙編出來如下:
    去掉了部分無關內容,其餘的我在這段程式碼的實現裡做了註釋:
    
00401B02  MOV ESI,DWORD PTR DS:[<&MSVBVM60.__vbaVa>;  MSVBVM60.__vbaVarMove
00401B08  XOR EDI,EDI
00401B0A  MOV EBX,2
00401B0F  MOV DWORD PTR SS:[EBP-DC],EDI
00401B15  LEA EDX,DWORD PTR SS:[EBP-DC]
00401B1B  LEA ECX,DWORD PTR SS:[EBP-4C]
00401B1E  MOV DWORD PTR SS:[EBP-28],EDI
00401B21  MOV DWORD PTR SS:[EBP-4C],EDI
00401B24  MOV DWORD PTR SS:[EBP-5C],EDI
00401B27  MOV DWORD PTR SS:[EBP-6C],EDI
00401B2A  MOV DWORD PTR SS:[EBP-7C],EDI
00401B2D  MOV DWORD PTR SS:[EBP-8C],EDI
00401B33  MOV DWORD PTR SS:[EBP-9C],EDI
00401B39  MOV DWORD PTR SS:[EBP-AC],EDI
00401B3F  MOV DWORD PTR SS:[EBP-BC],EDI
00401B45  MOV DWORD PTR SS:[EBP-CC],EDI

00401B4B  MOV DWORD PTR SS:[EBP-D4],30     //30h = &H30
00401B55  MOV DWORD PTR SS:[EBP-DC],EBX    //EBX = 2: integer型
00401B5B  CALL ESI                                 ;  <&MSVBVM60.__vbaVarMove>

                                           **** a =&H30  即[ebp-4c]

00401B5D  LEA EDX,DWORD PTR SS:[EBP-DC]
00401B63  LEA ECX,DWORD PTR SS:[EBP-5C]    //變數b
00401B66  MOV DWORD PTR SS:[EBP-D4],14A    //14Ah = 330
00401B70  MOV DWORD PTR SS:[EBP-DC],EBX    //EBX = 2: integer型
00401B76  CALL ESI
                                           **** b = 330  即[ebp-5c]
                                           
00401B78  LEA EDX,DWORD PTR SS:[EBP-DC]
00401B7E  LEA ECX,DWORD PTR SS:[EBP-6C]
00401B81  MOV DWORD PTR SS:[EBP-D4],101D0  //101D0 = 66000
00401B8B  MOV DWORD PTR SS:[EBP-DC],3      //3:long型
00401B95  CALL ESI

                                           **** c = 66000 即[ebp-6c]
                                           
00401B97  LEA EDX,DWORD PTR SS:[EBP-DC]
00401B9D  LEA ECX,DWORD PTR SS:[EBP-7C]
00401BA0  MOV DWORD PTR SS:[EBP-D4],-1     //-1 TRUE
00401BAA  MOV DWORD PTR SS:[EBP-DC],0B     //12:boolean型
00401BB4  CALL ESI

                                           **** d = TRUE 即[ebp-7c]
                                           
00401BB6  LEA EDX,DWORD PTR SS:[EBP-DC]
00401BBC  LEA ECX,DWORD PTR SS:[EBP-8C]
00401BC2  MOV DWORD PTR SS:[EBP-D4],工程1.00401948   ;  UNICODE "hello" //"hello"
00401BCC  MOV DWORD PTR SS:[EBP-DC],8      //8:string型
00401BD6  CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarCo>;  MSVBVM60.__vbaVarCopy

                                           **** e = "hello" 即[ebp-8c]

00401BDC  LEA EAX,DWORD PTR SS:[EBP-CC]
00401BE2  PUSH EAX
00401BE3  CALL DWORD PTR DS:[<&MSVBVM60.#546>] //Now
00401BE9  LEA EDX,DWORD PTR SS:[EBP-CC]    //Now
00401BEF  LEA ECX,DWORD PTR SS:[EBP-9C]
00401BF5  CALL ESI

                                           **** f = Now  即[ebp-9c]

00401BF7  MOV EBX,5
00401BFC  LEA EDX,DWORD PTR SS:[EBP-DC]
00401C02  LEA ECX,DWORD PTR SS:[EBP-AC]
00401C08  MOV DWORD PTR SS:[EBP-D4],C083126F
00401C12  MOV DWORD PTR SS:[EBP-D0],400921CA //3.1415
00401C1C  MOV DWORD PTR SS:[EBP-DC],EBX    //EBX = 5 :double型
00401C22  CALL ESI

                                           **** g = 3.1415 即[ebp-ac]
                                           
00401C24  LEA EDX,DWORD PTR SS:[EBP-DC]
00401C2A  LEA ECX,DWORD PTR SS:[EBP-BC]
00401C30  MOV DWORD PTR SS:[EBP-D4],851EB852
00401C3A  MOV DWORD PTR SS:[EBP-D0],3FF451EB //1.27
00401C44  MOV DWORD PTR SS:[EBP-DC],EBX    //EBX = 5 :double型 
00401C4A  CALL ESI

                                           // h = 1.27

00401C4C  LEA ECX,DWORD PTR SS:[EBP-4C]
00401C4F  PUSH ECX
00401C50  CALL DWORD PTR DS:[<&MSVBVM60.__vbaUI1Va>;  MSVBVM60.__vbaUI1Var
                                           //取byte, al中
                                           
                                           **** i = a
00401C56  LEA EDX,DWORD PTR SS:[EBP-5C]
00401C59  PUSH EDX
00401C5A  CALL DWORD PTR DS:[<&MSVBVM60.__vbaI2Var>;  MSVBVM60.__vbaI2Var
                                           //取integer, ax中
                                           
                                           **** j = b
00401C60  LEA EAX,DWORD PTR SS:[EBP-6C]
00401C63  PUSH EAX
00401C64  CALL DWORD PTR DS:[<&MSVBVM60.__vbaI4Var>;  MSVBVM60.__vbaI4Var
                                           //取long, eax中
                                           
                                           **** k = c
00401C6A  LEA ECX,DWORD PTR SS:[EBP-7C]
00401C6D  PUSH ECX
00401C6E  CALL DWORD PTR DS:[<&MSVBVM60.__vbaBoolV>;  MSVBVM60.__vbaBoolVar
                                           //取boolean, ax中
                                           
                                           **** l = d
00401C74  LEA EDX,DWORD PTR SS:[EBP-8C]
00401C7A  PUSH EDX
00401C7B  CALL DWORD PTR DS:[<&MSVBVM60.__vbaStrVa>;  MSVBVM60.__vbaStrVarCopy
                                           //取string, eax中是地址
                                           
                                           **** m = e
00401C81  MOV EDX,EAX
00401C83  LEA ECX,DWORD PTR SS:[EBP-28]
00401C86  CALL DWORD PTR DS:[<&MSVBVM60.__vbaStrMo>;  MSVBVM60.__vbaStrMove

00401C8C  LEA EAX,DWORD PTR SS:[EBP-9C]
00401C92  PUSH EAX
00401C93  CALL DWORD PTR DS:[<&MSVBVM60.__vbaDateV>;  MSVBVM60.__vbaDateVar
                                           //取date, 浮點棧中
                                           
                                           **** n = f
00401C99  LEA ECX,DWORD PTR SS:[EBP-AC]
00401C9F  FSTP ST
00401CA1  PUSH ECX
00401CA2  CALL DWORD PTR DS:[<&MSVBVM60.__vbaR8Var>;  MSVBVM60.__vbaR8Var
                                           //取double, 浮點棧中
                                           
                                           **** o = g
00401CA8  LEA EDX,DWORD PTR SS:[EBP-BC]
00401CAE  FSTP ST
00401CB0  PUSH EDX
00401CB1  CALL DWORD PTR DS:[<&MSVBVM60.__vbaR4Var>;  MSVBVM60.__vbaR4Var
00401CB7  FSTP ST
                                           //取single, 浮點棧中
                                           
                                           **** p = h

==========================================
    先總結一下:byte 和 integer一樣,內部都是使用integer型別表示,single和double一樣,
內部都是使用double型別表示。date佔用8個位元組。boolean型別佔用2個位元組&HFFFF表示TRUE,而
0表示FALSE.
    這些簡單變數在記憶體中的表示如下:前4個位元組含有變數型別,接著4個位元組(意義還不清楚),
我們不妨先叫他輔助型別資訊,過了這8個位元組就是真正的變數資料了。
    如變數a的記憶體表示如下:63F3C4 : 02 00 00 00  
                           63F3C8 : 00 00 00 00 
                           63F3CC : 30 00 00 00
    可以看到,63F3CC處是真正的變數值。如果是字串,這個位置可以看到一個指標。


    簡單變數裡沒有提到的型別是Currency,Decimal,這些你可以自己實際觀察一下。
    關於簡單變數就總結這些,不知道你看懂了沒有。我沒有辦法把機器搬上來讓你看。所以還是
那句話:如果你想弄明白我所講的到底是怎麼一回事,就把上面那段程式編譯一下,然後用ollydbg
跟蹤一下看看。

    在本文即將結束時要提到的一個事實是:VB並不是強型別語言。例如你可以把一個boolean型別
的變數賦值給一個整數,然後再列印出這個整數的值,你可以看到TRUE的輸出為-1,而FALSE的輸
出為0。當然在你決定這樣做的時候你要保證兩個變數所佔記憶體空間大小一樣或者被賦值的變數的
空間要大於所賦值的變數的空間。否則你可能會得到一個溢位錯誤。你可以試試把date型別的變數
賦值給一個integer型別的變數 :)

相關文章