淺談VB6逆向工程(5)

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

5. VB中的異常處理
                       
    這裡我只從跟蹤的角度來談異常處理。很多人說在VB中發生異常是會跟進虛擬機器裡,
在裡面打轉。其實VB的異常處理沒有那麼複雜,可以很容易的出來的。
    這裡先介紹一個VB的萬能斷點:MSVBVM60.__vbaExceptHandler,VB在每個過程
的開始都要安裝一個執行緒異常處理過程,在OD中對這個函式下斷點百分百有效。需要注意
的事當你找到自己需要的地方時要及時清除這個斷點,否則會在你不期望的時候中斷:)

    下面依舊以一段程式碼為例說明:
    Dim a, b, c, d
    On Error Resume Next
    a = 5
    b = 6
    c = 0
    d = b / c
    Print a
    
    到現在為止你應該能看懂下面的程式碼了。所以我只對原始碼註釋:
      
00401A20   PUSH EBP
00401A21   MOV EBP,ESP
00401A23   SUB ESP,18
00401A26   PUSH <JMP.&MSVBVM60.__vbaExceptHandler>         
00401A2B   MOV EAX,DWORD PTR FS:[0]
00401A31   PUSH EAX
00401A32   MOV DWORD PTR FS:[0],ESP
00401A39   MOV EAX,74
00401A3E   CALL <JMP.&MSVBVM60.__vbaChkstk>
00401A43   PUSH EBX
00401A44   PUSH ESI
00401A45   PUSH EDI
00401A46   MOV DWORD PTR SS:[EBP-18],ESP
00401A49   MOV DWORD PTR SS:[EBP-14],工程2.00401088
00401A50   MOV EAX,DWORD PTR SS:[EBP+8]
00401A53   AND EAX,1
00401A56   MOV DWORD PTR SS:[EBP-10],EAX
00401A59   MOV ECX,DWORD PTR SS:[EBP+8]
00401A5C   AND ECX,FFFFFFFE
00401A5F   MOV DWORD PTR SS:[EBP+8],ECX
00401A62   MOV DWORD PTR SS:[EBP-C],0
00401A69   MOV EDX,DWORD PTR SS:[EBP+8]
00401A6C   MOV EAX,DWORD PTR DS:[EDX]
00401A6E   MOV ECX,DWORD PTR SS:[EBP+8]
00401A71   PUSH ECX
00401A72   CALL DWORD PTR DS:[EAX+4]

00401A75   MOV DWORD PTR SS:[EBP-4],1
00401A7C   MOV DWORD PTR SS:[EBP-4],2
00401A83   PUSH -1
00401A85   CALL DWORD PTR DS:[<&MSVBVM60.__vbaOnError>] 

                             //On Error Resume Next
   
00401A8B   MOV DWORD PTR SS:[EBP-4],3
00401A92   MOV DWORD PTR SS:[EBP-78],5
00401A99   MOV DWORD PTR SS:[EBP-80],2
00401AA0   LEA EDX,DWORD PTR SS:[EBP-80]
00401AA3   LEA ECX,DWORD PTR SS:[EBP-30]
00401AA6   CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]   

                             // a = 5

00401AAC   MOV DWORD PTR SS:[EBP-4],4
00401AB3   MOV DWORD PTR SS:[EBP-78],6
00401ABA   MOV DWORD PTR SS:[EBP-80],2
00401AC1   LEA EDX,DWORD PTR SS:[EBP-80]
00401AC4   LEA ECX,DWORD PTR SS:[EBP-40]
00401AC7   CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>] 

                              //  b = 6
   
00401ACD   MOV DWORD PTR SS:[EBP-4],5
00401AD4   MOV DWORD PTR SS:[EBP-78],0
00401ADB   MOV DWORD PTR SS:[EBP-80],2
00401AE2   LEA EDX,DWORD PTR SS:[EBP-80]
00401AE5   LEA ECX,DWORD PTR SS:[EBP-50]
00401AE8   CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]   

                              // c = 0

00401AEE   MOV DWORD PTR SS:[EBP-4],6
00401AF5   LEA EDX,DWORD PTR SS:[EBP-40]
00401AF8   PUSH EDX
00401AF9   LEA EAX,DWORD PTR SS:[EBP-50]
00401AFC   PUSH EAX
00401AFD   LEA ECX,DWORD PTR SS:[EBP-70]
00401B00   PUSH ECX
00401B01   CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarDiv>]     
00401B07   MOV EDX,EAX
00401B09   LEA ECX,DWORD PTR SS:[EBP-60]
00401B0C   CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]    ;  MSVBVM60.__vbaVarMove

                              // d = b / c

00401B12   MOV DWORD PTR SS:[EBP-4],7
00401B19   LEA EDX,DWORD PTR SS:[EBP-30]
00401B1C   PUSH EDX
00401B1D   MOV EAX,DWORD PTR SS:[EBP+8]
00401B20   PUSH EAX
00401B21   PUSH 工程2.004016E8
00401B26   CALL DWORD PTR DS:[<&MSVBVM60.__vbaPrintObj>] 

                              //print a

    為了不佔篇幅,刪去了後面的程式碼.看到onError時你應該小心的處理這個
過程,剛才的斷點還沒有清除吧?如果清除了在__vbaExceptHandler這個函式
上重新下個斷點.執行程式,會在這個斷點上停下來,我們跟進這個函式里.
在OD中按f8一路向下走,你應該在這裡跟飛:
660E3D3A   MOV AX,WORD PTR DS:[ESI]
660E3D3D   TEST AL,30
660E3D3F   JE SHORT MSVBVM60.660E3D4D
660E3D41   CMP DWORD PTR DS:[EDI+14],0
660E3D45   JE SHORT MSVBVM60.660E3D4D
660E3D47   TEST BYTE PTR DS:[EDI+10],2
660E3D4B   JE SHORT MSVBVM60.660E3D55
660E3D4D   TEST AL,1
660E3D4F   JE MSVBVM60.660E3DDB
660E3D55   PUSH ECX
660E3D56   CALL MSVBVM60.660E415C
660E3D5B   PUSH DWORD PTR SS:[EBP+8]
660E3D5E   MOV DWORD PTR SS:[EBP+C],EAX
660E3D61   CALL MSVBVM60.660E4121
660E3D66   TEST EAX,EAX
660E3D68   JE SHORT MSVBVM60.660E3DDB
660E3D6A   CMP DWORD PTR SS:[EBP+C],0
660E3D6E   JE SHORT MSVBVM60.660E3D75
660E3D70   TEST BYTE PTR DS:[ESI],1
660E3D73   JE SHORT MSVBVM60.660E3DDB
660E3D75   PUSH EDI
660E3D76   CALL MSVBVM60.66103DBF
660E3D7B   CALL MSVBVM60.660CDE2E
660E3D80   XOR EAX,EAX
660E3D82   CMP DWORD PTR SS:[EBP+C],EAX
660E3D85   JNZ MSVBVM60.660E3E4B
660E3D8B   TEST BYTE PTR DS:[ESI],30
660E3D8E   JE SHORT MSVBVM60.660E3E04
660E3D90   CMP DWORD PTR DS:[EDI+14],EAX
660E3D93   JE SHORT MSVBVM60.660E3E04
660E3D95   TEST BYTE PTR DS:[EDI+10],2
660E3D99   JNZ SHORT MSVBVM60.660E3E04
660E3D9B   PUSH EAX
660E3D9C   PUSH 1
660E3D9E   PUSH EAX
660E3D9F   PUSH ESI
660E3DA0   PUSH EDI
660E3DA1   CALL MSVBVM60.660E3F47
660E3DA6   TEST BYTE PTR DS:[ESI],40
660E3DA9   PUSH DWORD PTR DS:[6610EE7C]
660E3DAF   JE SHORT MSVBVM60.660E3DE3
660E3DB1   CALL EBX
660E3DB3   MOV ECX,DWORD PTR DS:[EDI+1C]
660E3DB6   MOV EDX,DWORD PTR DS:[ESI+18]
660E3DB9   MOVZX ECX,WORD PTR DS:[EDX+ECX*2+2]
660E3DBE   MOV DWORD PTR DS:[EAX+98],ECX
660E3DC4   MOV EAX,DWORD PTR DS:[EDI+14]
660E3DC7   CMP EAX,-2
660E3DCA   JE SHORT MSVBVM60.660E3DF9
660E3DCC   CMP EAX,-1
660E3DCF   JE SHORT MSVBVM60.660E3DEE
660E3DD1   TEST EAX,EAX
660E3DD3   JE SHORT MSVBVM60.660E3DDB
660E3DD5   PUSH EDI
660E3DD6   CALL MSVBVM60.660E408D  //這裡跟飛

     我們在這裡下個斷點,重新執行程式,到這裡按F7跟進.會來到下面:
     
660E408D    PUSH EBP
660E408E    MOV EBP,ESP
660E4090    PUSH ECX
660E4091    MOV EAX,DWORD PTR SS:[EBP+8]
660E4094    AND DWORD PTR SS:[EBP-4],0
660E4098    AND DWORD PTR SS:[EBP+8],0
660E409C    PUSH EBX
660E409D    MOV ECX,DWORD PTR DS:[EAX+1C]
660E40A0    MOV EDX,DWORD PTR DS:[EAX+C]
660E40A3    MOV DWORD PTR DS:[EAX+18],ECX
660E40A6    PUSH ESI
660E40A7    MOV ECX,DWORD PTR DS:[EDX+10]
660E40AA    PUSH EDI
660E40AB    MOV ESI,DWORD PTR DS:[ECX]
660E40AD    TEST ESI,ESI
660E40AF    JLE SHORT MSVBVM60.660E40C6
660E40B1    LEA EDI,DWORD PTR DS:[ECX+4]
660E40B4    MOV EBX,DWORD PTR DS:[EAX+14]
660E40B7    CMP EBX,DWORD PTR DS:[EDI]
660E40B9    JE SHORT MSVBVM60.660E40EA
660E40BB    INC DWORD PTR SS:[EBP+8]
660E40BE    ADD EDI,8
660E40C1    CMP DWORD PTR SS:[EBP+8],ESI
660E40C4  ^ JL SHORT MSVBVM60.660E40B4
660E40C6    MOVSX ECX,WORD PTR DS:[EDX+2]
660E40CA    OR DWORD PTR DS:[EAX+10],2
660E40CE    PUSH MSVBVM60.660E3FD3
660E40D3    PUSH DWORD PTR DS:[EAX+8]
660E40D6    LEA EAX,DWORD PTR DS:[ECX+EAX+C]
660E40DA    PUSH EAX
660E40DB    PUSH DWORD PTR SS:[EBP-4] //這裡就是返回地址了
660E40DE    CALL MSVBVM60.66103DAC
660E40E3    POP EDI
660E40E4    POP ESI
660E40E5    POP EBX
660E40E6    LEAVE
660E40E7    RETN 4

    為了驗證一下,我們繼續跟進66103dac:
66103DAC    PUSH EBP
66103DAD    MOV EBP,ESP
66103DAF    MOV ECX,DWORD PTR SS:[EBP+14]
66103DB2    MOV EBX,DWORD PTR SS:[EBP+8]  //這裡是剛才那個引數
66103DB5    MOV ESP,DWORD PTR SS:[EBP+10]
66103DB8    MOV EBP,DWORD PTR SS:[EBP+C]
66103DBB    CALL ECX
66103DBD    JMP EBX                       //返回使用者程式

    注意:這裡所提到的是對使用者程式對異常做了處理的情況,否則你可能得到一個
出錯對話方塊程式就退出了.:(

             
             
             
                              6. 沒有結束的結束

    這一系列的貼子到這裡就告一段落了。工作太忙,一直斷斷續續的在寫,感謝你有耐心
看完。上面所提到的都是從語言這個角度說的。也是我分析大量VB程式的一點經驗。真正的
VB逆向工程只有這點知識遠遠不夠。這是隻是幫助你複習語言特性而已。你或許應該去好好
的看看編譯原理,看看C++,看看COM的實現,看看流行的編譯器技術等等。
    這裡要提到的是大家都知道的看學學院出的《軟體保護技術內幕》,那裡有對VB更深一
層的論述。還有就是在末尾提到的那些資源。你應該學會自己獲取需要的知識。^_^

相關文章