• 标 题:浅谈VB6逆向工程(5)
  • 作 者:MengLong
  • 时 间:2004-12-27,12:51
  • 链 接:http://bbs.pediy.com

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更深一
层的论述。还有就是在末尾提到的那些资源。你应该学会自己获取需要的知识。^_^