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