赋值给一个integer类型的变量</FONT>
@H_301_0@
@H_301_0@
//===================================================================
2. 复杂变量的内部实现@H_301_0@ @H_301_0@ 这里所提到的复杂变量(我自己的叫法 ),是指枚举,数组和记录类型的变量。@H_301_0@ @H_301_0@ @H_301_0@ 1) 枚举类型的实现 @H_301_0@ @H_301_0@ 先定义一个枚举类型如下:@H_301_0@ Enum myweek@H_301_0@ sun@H_301_0@ mon@H_301_0@ tues@H_301_0@ wednes@H_301_0@ thurs@H_301_0@ fri@H_301_0@ satur@H_301_0@ End Enum@H_301_0@ 然后再编写一段使用枚举类型的代码:@H_301_0@ Dim a As myweek@H_301_0@ Dim b As Integer@H_301_0@ @H_301_0@ a = sun@H_301_0@ b = a@H_301_0@ Print b@H_301_0@ @H_301_0@ 默认设置编译这段代码,接着我们看看编译器生成了什么。@H_301_0@ ; 37 : Dim a As myweek@H_301_0@ ; 38 : Dim b As Integer@H_301_0@ ; 39 : @H_301_0@ ; 40 : a = sun@H_301_0@ ; 41 : b = a@H_301_0@ @H_301_0@ xor ecx,ecx // a = sun,即 a = 0@H_301_0@ call DWORD PTR __imp_@__vbaI2I4 // b = a@H_301_0@ @H_301_0@ ; 42 : Print b@H_301_0@ @H_301_0@ push eax // b@H_301_0@ push esi@H_301_0@ push OFFSET FLAT:___vba@006255A0@H_301_0@ call DWORD PTR __imp____vbaPrintObj //Print@H_301_0@ @H_301_0@ ***************************************************@H_301_0@ 可以看出,枚举类型在代码里是直接用常量数值代替的。@H_301_0@ @H_301_0@ @H_301_0@ 2) 数组类型的实现@H_301_0@ @H_301_0@ 数组的概念比较复杂,为了研究方便,这里只讨论一维数组,并且不是嵌套的。 @H_301_0@ 先看看静态数组的定义与实现。@H_301_0@ @H_301_0@ 代码:@H_301_0@ Dim a(3 To 6) As Integer@H_301_0@ @H_301_0@ 反汇编代码:@H_301_0@ @H_301_0@ 004019FF PUSH 2@H_301_0@ 00401A01 LEA EAX,DWORD PTR SS:[EBP-2C] // 数组变量@H_301_0@ 00401A04 XOR ESI,ESI@H_301_0@ 00401A06 PUSH 工程1.00401694 // 指向代码段@H_301_0@ 00401A0B PUSH EAX @H_301_0@ 00401A0C MOV DWORD PTR SS:[EBP-34],ESI@H_301_0@ 00401A0F CALL DWORD PTR DS:[<&MSVBVM60.__vbaAryConstruct2>] // 构造一个数组@H_301_0@ @H_301_0@ 指行到这里时看[ebp-2c]的内容:@H_301_0@ 0063F3E4 01 00 92 00 02 00 00 00 .?...@H_301_0@ 0063F3EC 00 00 00 00 C0 0F 51 00 ....?Q.@H_301_0@ 0063F3F4 04 00 00 00 03 00 00 00 ......@H_301_0@ @H_301_0@ 这些数据除了63F3F0处的地址是__vbaAryConstruct2函数填进去的,其余的都是从@H_301_0@ 401694处拷贝过来的。因此__vbaAryConstruct2函数的作用可以这样理解:先从401694@H_301_0@ 处拷贝24个字节到ebp-2c处,然后分配一块空间,把指向新分配的空间的指针填到63F3F0@H_301_0@ 处。@H_301_0@ 那么上面这些数据到底是什么意思呢?看下面的分析.@H_301_0@ @H_301_0@ @H_301_0@ 00401A18 PUSH 工程1.00401A30 //指向退出地址@H_301_0@ 00401A1D LEA EDX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401A20 LEA ECX,DWORD PTR SS:[EBP-2C] //要释放的数组变量@H_301_0@ 00401A23 PUSH EDX@H_301_0@ 00401A24 PUSH 0@H_301_0@ 00401A26 MOV DWORD PTR SS:[EBP-34],ECX@H_301_0@ 00401A29 CALL DWORD PTR DS:[<&MSVBVM60.__vbaAryDestruct>] // 释放一个数组@H_301_0@ @H_301_0@ 为了弄清楚上面提到的那些内存数据的含义,我分别定义了不同大小不同类型的数组来比较,@H_301_0@ 下面是dump出来的典型数据:@H_301_0@ @H_301_0@ Dim a(3 To 6) @H_301_0@ 0063F3E4 01 00 92 08 10 00 00 00 .?...@H_301_0@ 0063F3EC 00 00 00 00 2C 01 41 00 ....,A.@H_301_0@ 0063F3F4 04 00 00 00 03 00 00 00 ......@H_301_0@ @H_301_0@ Dim a(3 To 6) As String @H_301_0@ 0063F3E4 01 00 92 01 04 00 00 00 .?...@H_301_0@ 0063F3EC 00 00 00 00 C0 0F 51 00 ....?Q.@H_301_0@ 0063F3F4 04 00 00 00 03 00 00 00 ...... @H_301_0@ @H_301_0@ Dim a(3 To 6) As Integer @H_301_0@ 0063F3E4 01 00 92 00 02 00 00 00 .?...@H_301_0@ 0063F3EC 00 00 00 00 C0 0F 51 00 ....?Q.@H_301_0@ 0063F3F4 04 00 00 00 03 00 00 00 ......@H_301_0@ @H_301_0@ 我总结的数组变量内存数据的说明:@H_301_0@ 0063F3E4 处的两个字节代表数组的维数@H_301_0@ 0063F3E6 处的一个字节 92 代表静态数组@H_301_0@ 0063F3E7 处的一个字节随着不同类型的变量有不同的变化。@H_301_0@ 08 : 变体类型 @H_301_0@ 01 : String@H_301_0@ 00 : Integer,byte,long,single,double,date @H_301_0@ 0063F3E8 处的两个字节表示一个数组元素所占的内存空间字节数。@H_301_0@ 0063F3EC 处的4个字节总是0,可能是为了对齐。@H_301_0@ 0063F3F0 处的两个字节代表分配的空间的地址指针,即数组数据。@H_301_0@ 0063F3F4 处的两个字节代表静态数组元素的个数。@H_301_0@ 0063F3F8 处的两个字节代表数组的起始下标。@H_301_0@ @H_301_0@ 上面大概的对数组变量的数据做了说明,为了验证一下,再看一个3维数组的定义:@H_301_0@ @H_301_0@ Dim a(1 To 2,3 To 5,6 To 9) As Integer@H_301_0@ @H_301_0@ 0063F3D4 03 00 92 00 02 00 00 00 .?...@H_301_0@ 0063F3DC 00 00 00 00 C0 0F 51 00 ....?Q.@H_301_0@ 0063F3E4 04 00 00 00 06 00 00 00 ......@H_301_0@ 0063F3EC 03 00 00 00 03 00 00 00 ......@H_301_0@ 0063F3F4 02 00 00 00 01 00 00 00 ......@H_301_0@ @H_301_0@ 可以看出,静态数组的信息在编译时就被编码到了代码段里。@H_301_0@ 静态数组的构造用 __vbaAryConstruct2@H_301_0@ 静态数组的释放用 __vbaAryDestruct@H_301_0@ @H_301_0@ ///////////////////////////////////////////////////////////@H_301_0@ @H_301_0@ 动态数组又是怎样实现的呢?@H_301_0@ 代码:@H_301_0@ Dim a() As Date@H_301_0@ ReDim a(2 To 5)@H_301_0@ @H_301_0@ 反汇编代码:@H_301_0@ 004019CF PUSH 2 //起始下标@H_301_0@ 004019D1 PUSH 5 //结束下标@H_301_0@ 004019D3 PUSH 1 //数组维数@H_301_0@ 004019D5 LEA EAX,DWORD PTR SS:[EBP-18]@H_301_0@ 004019D8 PUSH 7 //变量类型@H_301_0@ 004019DA PUSH EAX //我们重定义的数组变量@H_301_0@ 004019DB XOR ESI,ESI@H_301_0@ 004019DD PUSH 8 //数组元素所占内存空间的字节数@H_301_0@ 004019DF PUSH 80 //动态数组标记@H_301_0@ 004019E4 MOV DWORD PTR SS:[EBP-18],ESI@H_301_0@ 004019E7 CALL DWORD PTR DS:[<&MSVBVM60.__vbaRedim>] // ReDim@H_301_0@ 004019ED ADD ESP,1C@H_301_0@ 004019F0 MOV DWORD PTR SS:[EBP-4],ESI@H_301_0@ 004019F3 PUSH 工程1.00401A05@H_301_0@ 004019F8 LEA ECX,DWORD PTR SS:[EBP-18] //数组变量@H_301_0@ 004019FB PUSH ECX@H_301_0@ 004019FC PUSH 0@H_301_0@ 004019FE CALL DWORD PTR DS:[<&MSVBVM60.__vbaAryDestruct>] //释放数组@H_301_0@ @H_301_0@ 当执行到 004019ED 时,我们查看[ebp-18]处的内存数据,可以看到是@H_301_0@ @H_301_0@ 0063F3F8 D0 0F 51 00 ?Q.豇@H_301_0@ @H_301_0@ 这是一个指针,我们接着 follow dword in dump,可以看到数据如下:@H_301_0@ @H_301_0@ 00510FD0 01 00 80 00 08 00 00 00 .@H_301_0@
@H_301_0@
//=========================================================================================
3. VB6的控制结构@H_301_0@ @H_301_0@ 下面要提到的vb的控制结构语句有:if语句,select case语句,while语句,do语句,@H_301_0@ for语句。@H_301_0@ @H_301_0@ 1)if语句@H_301_0@ @H_301_0@ if语句的典型语法是: @H_301_0@ @H_301_0@ If 条件1 Then@H_301_0@ 语句块1 @H_301_0@ ElseIf 条件2 Then@H_301_0@ 语句块2 @H_301_0@ Else@H_301_0@ 语句块3 @H_301_0@ End If@H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @H_301_0@ 代码:@H_301_0@ Dim a //注意:这里定义的是变体变量。@H_301_0@ //如果不用变体变量,编译器将优化掉太多的代码。@H_301_0@ //当你熟悉变体类型后,其他的将很容易分析 ^_^@H_301_0@ a = 5@H_301_0@ @H_301_0@ If a < 5 Then@H_301_0@ MsgBox (\"a < 5\")@H_301_0@ ElseIf a = 5 Then@H_301_0@ MsgBox (\"a = 5\")@H_301_0@ Else@H_301_0@ MsgBox (\"a > 5\")@H_301_0@ End If@H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@H_301_0@ 反汇编代码:@H_301_0@ 00401A72 XOR ESI,ESI@H_301_0@ 00401A74 MOV EDI,5@H_301_0@ 00401A79 MOV DWORD PTR SS:[EBP-74],ESI@H_301_0@ 00401A7C LEA EDX,DWORD PTR SS:[EBP-74]@H_301_0@ 00401A7F LEA ECX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401A82 MOV DWORD PTR SS:[EBP-24],ESI@H_301_0@ 00401A85 MOV DWORD PTR SS:[EBP-34],ESI ----> 这些变量是为 MsgBox 使用的@H_301_0@ 00401A88 MOV DWORD PTR SS:[EBP-44],ESI |@H_301_0@ 00401A8B MOV DWORD PTR SS:[EBP-54],ESI |@H_301_0@ 00401A8E MOV DWORD PTR SS:[EBP-64],ESI ---@H_301_0@ 00401A91 MOV DWORD PTR SS:[EBP-6C],EDI // 5@H_301_0@ 00401A94 MOV DWORD PTR SS:[EBP-74],2 //整数类型@H_301_0@ 00401A9B CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]//赋值@H_301_0@ //到这里 a = 5 //[ebp-24]@H_301_0@ 00401AA1 LEA EAX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401AA4 LEA ECX,DWORD PTR SS:[EBP-74] @H_301_0@ 00401AA7 MOV EBX,8002@H_301_0@ 00401AAC PUSH EAX@H_301_0@ 00401AAD PUSH ECX@H_301_0@ 00401AAE MOV DWORD PTR SS:[EBP-6C],EDI // 5@H_301_0@ 00401AB1 MOV DWORD PTR SS:[EBP-74],EBX // 8002 @H_301_0@ 00401AB4 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarTstLt>] // a < 5 ?@H_301_0@ 00401ABA TEST AX,AX@H_301_0@ 00401ABD JE SHORT 工程2.00401AE4 //不小于则跳走@H_301_0@ @H_301_0@ 00401ABF MOV ECX,80020004@H_301_0@ 00401AC4 MOV EAX,0A@H_301_0@ 00401AC9 MOV DWORD PTR SS:[EBP-5C],ECX@H_301_0@ 00401ACC MOV DWORD PTR SS:[EBP-64],EAX@H_301_0@ 00401ACF MOV DWORD PTR SS:[EBP-4C],ECX@H_301_0@ 00401AD2 MOV DWORD PTR SS:[EBP-54],EAX@H_301_0@ 00401AD5 MOV DWORD PTR SS:[EBP-3C],ECX@H_301_0@ 00401AD8 MOV DWORD PTR SS:[EBP-44],EAX@H_301_0@ 00401ADB MOV DWORD PTR SS:[EBP-6C],工程2.004016C4; UNICODE \"a < 5\"@H_301_0@ 00401AE2 JMP SHORT 工程2.00401B63@H_301_0@ @H_301_0@ 00401AE4 LEA ECX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401AE7 LEA EDX,DWORD PTR SS:[EBP-74]@H_301_0@ 00401AEA PUSH ECX@H_301_0@ 00401AEB PUSH EDX@H_301_0@ 00401AEC MOV DWORD PTR SS:[EBP-6C],EDI // 5@H_301_0@ 00401AEF MOV DWORD PTR SS:[EBP-74],EBX // 8002@H_301_0@ 00401AF2 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarTstEq>]// a = 5 ?@H_301_0@ 00401AF8 TEST AX,AX@H_301_0@ 00401AFB MOV ECX,80020004@H_301_0@ 00401B00 MOV EAX,0A@H_301_0@ 00401B05 MOV DWORD PTR SS:[EBP-5C],ECX@H_301_0@ 00401B08 MOV DWORD PTR SS:[EBP-64],EAX@H_301_0@ 00401B0B MOV DWORD PTR SS:[EBP-4C],ECX@H_301_0@ 00401B0E MOV DWORD PTR SS:[EBP-54],EAX@H_301_0@ 00401B11 MOV DWORD PTR SS:[EBP-3C],ECX@H_301_0@ 00401B14 MOV DWORD PTR SS:[EBP-44],EAX@H_301_0@ 00401B17 JE SHORT 工程2.00401B5C //不相等则跳走@H_301_0@ @H_301_0@ 00401B19 LEA EDX,DWORD PTR SS:[EBP-74]@H_301_0@ 00401B1C LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401B1F MOV DWORD PTR SS:[EBP-6C],工程2.004016D4; UNICODE \"a = 5\"@H_301_0@ 00401B26 MOV DWORD PTR SS:[EBP-74],8@H_301_0@ 00401B2D CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarDup>]@H_301_0@ 00401B33 LEA EAX,DWORD PTR SS:[EBP-64]@H_301_0@ 00401B36 LEA ECX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401B39 PUSH EAX@H_301_0@ 00401B3A LEA EDX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401B3D PUSH ECX@H_301_0@ 00401B3E PUSH EDX@H_301_0@ 00401B3F LEA EAX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401B42 PUSH ESI@H_301_0@ 00401B43 PUSH EAX@H_301_0@ 00401B44 CALL DWORD PTR DS:[<&MSVBVM60.#595>]; MSVBVM60.rtcMsgBox@H_301_0@ 00401B4A LEA ECX,DWORD PTR SS:[EBP-64]@H_301_0@ 00401B4D LEA EDX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401B50 PUSH ECX@H_301_0@ 00401B51 LEA EAX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401B54 PUSH EDX@H_301_0@ 00401B55 LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401B58 PUSH EAX@H_301_0@ 00401B59 PUSH ECX@H_301_0@ 00401B5A JMP SHORT 工程2.00401B9D@H_301_0@ // 其他条件满足则执行这里@H_301_0@ 00401B5C MOV DWORD PTR SS:[EBP-6C],工程2.004016E4; UNICODE \"a > 5\"@H_301_0@ 00401B63 LEA EDX,DWORD PTR SS:[EBP-74]@H_301_0@ 00401B66 LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401B69 MOV DWORD PTR SS:[EBP-74],8@H_301_0@ 00401B70 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarDup>]@H_301_0@ 00401B76 LEA EDX,DWORD PTR SS:[EBP-64]@H_301_0@ 00401B79 LEA EAX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401B7C PUSH EDX@H_301_0@ 00401B7D LEA ECX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401B80 PUSH EAX@H_301_0@ 00401B81 PUSH ECX@H_301_0@ 00401B82 LEA EDX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401B85 PUSH ESI@H_301_0@ 00401B86 PUSH EDX@H_301_0@ 00401B87 CALL DWORD PTR DS:[<&MSVBVM60.#595>]; MSVBVM60.rtcMsgBox@H_301_0@ @H_301_0@ 流程大概如此。上面出现了一些VB内部函数,如果你不太熟悉那些函数的意义,可以@H_301_0@ 到DFCG上下载一份我整理的vb内部函数。@H_301_0@ ===========================================================@H_301_0@ 2)select case 语句@H_301_0@ @H_301_0@ select case 语句的语法如下:@H_301_0@ @H_301_0@ Select Case 测试表达式@H_301_0@ Case 表达式列表1@H_301_0@ 语句块1@H_301_0@ Case 表达式列表2@H_301_0@ 语句块2@H_301_0@ ......@H_301_0@ Case Else@H_301_0@ 语句块n@H_301_0@ End Select@H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@H_301_0@ 代码:@H_301_0@ Dim a,b@H_301_0@ a = 5 @H_301_0@ Select Case a@H_301_0@ Case 3@H_301_0@ b = \"3\"@H_301_0@ Case 5@H_301_0@ b = \"5\"@H_301_0@ Case Else@H_301_0@ b = \"0\"@H_301_0@ End Select@H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@H_301_0@ 反汇编代码(速度优化编译)@H_301_0@ 00401A2F XOR ESI,ESI // 用来初始化变量@H_301_0@ 00401A31 LEA EDX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401A34 MOV DWORD PTR SS:[EBP-44],ESI@H_301_0@ 00401A37 LEA ECX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401A3A MOV DWORD PTR SS:[EBP-24],ESI@H_301_0@ 00401A3D MOV DWORD PTR SS:[EBP-34],ESI@H_301_0@ 00401A40 MOV DWORD PTR SS:[EBP-54],ESI@H_301_0@ 00401A43 MOV DWORD PTR SS:[EBP-3C],5 // 5@H_301_0@ 00401A4A MOV DWORD PTR SS:[EBP-44],2 // 类型@H_301_0@ 00401A51 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]@H_301_0@ // a = 5 //[ebp-24]@H_301_0@ @H_301_0@ 00401A57 MOV EBX,DWORD PTR DS:[<&MSVBVM60.__vbaVarCopy>]@H_301_0@ 00401A5D LEA EDX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401A60 LEA ECX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401A63 CALL EBX // 生成一个临时变量 //[ebp-54]@H_301_0@ // Select Case a@H_301_0@ @H_301_0@ @H_301_0@ 00401A65 MOV EDI,DWORD PTR DS:[<&MSVBVM60.__vbaVarTstEq>@H_301_0@ 00401A6B LEA EAX,DWORD PTR SS:][EBP-54]@H_301_0@ 00401A6E LEA ECX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401A71 PUSH EAX@H_301_0@ 00401A72 PUSH ECX@H_301_0@ 00401A73 MOV DWORD PTR SS:[EBP-3C],3 // 3@H_301_0@ 00401A7A MOV DWORD PTR SS:[EBP-44],8002@H_301_0@ 00401A81 CALL EDI @H_301_0@ 00401A83 TEST AX,AX@H_301_0@ 00401A86 JE SHORT 工程2.00401A91 // 不等于3则跳@H_301_0@ // Case 3@H_301_0@ 00401A88 MOV DWORD PTR SS:[EBP-3C],工程2.004016B4 // \'\'\'\'3\'\'\'\'@H_301_0@ 00401A8F JMP SHORT 工程2.00401ABC@H_301_0@ @H_301_0@ 00401A91 LEA EDX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401A94 LEA EAX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401A97 PUSH EDX@H_301_0@ 00401A98 PUSH EAX@H_301_0@ 00401A99 MOV DWORD PTR SS:[EBP-3C],5 // 5@H_301_0@ 00401AA0 MOV DWORD PTR SS:[EBP-44],8002@H_301_0@ 00401AA7 CALL EDI@H_301_0@ 00401AA9 TEST AX,AX@H_301_0@ 00401AAC MOV DWORD PTR SS:[EBP-3C],工程2.004016BC // \'\'\'\'5\'\'\'\'@H_301_0@ 00401AB3 JNZ SHORT 工程2.00401ABC // 不等于5则跳@H_301_0@ // Case 5@H_301_0@ @H_301_0@ 00401AB5 MOV DWORD PTR SS:[EBP-3C],工程2.004016C4 // \'\'\'\'0\'\'\'\'@H_301_0@ 00401ABC LEA EDX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401ABF LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401AC2 MOV DWORD PTR SS:[EBP-44],8 // String类型@H_301_0@ 00401AC9 CALL EBX // 为变量 b 赋值@H_301_0@ // Case Else@H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@H_301_0@ 当然这段代码在逆向时也可以用if语句来表达。逆向出来的不如select case@H_301_0@ 语句那样直观。在我看来用if语句表达应该是这样的:@H_301_0@ dim a,b@H_301_0@ if a = 3 then@H_301_0@ b = \'\'\'\'3\'\'\'\'@H_301_0@ else if a = 5 then@H_301_0@ b = \'\'\'\'5\'\'\'\'@H_301_0@ else@H_301_0@ b = \'\'\'\'0\'\'\'\'@H_301_0@ end if@H_301_0@ =========================================================== @H_301_0@ 3)while语句@H_301_0@ @H_301_0@ while语句的典型语法是:@H_301_0@ @H_301_0@ While 条件@H_301_0@ 语句块@H_301_0@ Wend@H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@H_301_0@ 代码:@H_301_0@ Dim a,b@H_301_0@ a = 3@H_301_0@ b = 0@H_301_0@ While a > 0@H_301_0@ b = b + a@H_301_0@ a = a - 1@H_301_0@ Wend@H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@H_301_0@
@H_301_0@
@H_301_0@
反汇编代码(速度优化编译)@H_301_0@ 00401A1F MOV ESI,DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]@H_301_0@ 00401A25 XOR EDI,EDI // 初始化变量 @H_301_0@ 00401A27 MOV EBX,2@H_301_0@ 00401A2C MOV DWORD PTR SS:[EBP-54],EDI@H_301_0@ 00401A2F LEA EDX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401A32 LEA ECX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401A35 MOV DWORD PTR SS:[EBP-24],EDI@H_301_0@ 00401A38 MOV DWORD PTR SS:[EBP-34],EDI@H_301_0@ 00401A3B MOV DWORD PTR SS:[EBP-44],EDI@H_301_0@ 00401A3E MOV DWORD PTR SS:[EBP-4C],3 // 3@H_301_0@ 00401A45 MOV DWORD PTR SS:[EBP-54],EBX // integer类型@H_301_0@ 00401A48 CALL ESI @H_301_0@ // a = 3 //[ebp-24]@H_301_0@ @H_301_0@ 00401A4A LEA EDX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401A4D LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401A50 MOV DWORD PTR SS:[EBP-4C],EDI // 0@H_301_0@ 00401A53 MOV DWORD PTR SS:[EBP-54],EBX // integer类型@H_301_0@ 00401A56 CALL ESI@H_301_0@ // b = 0 //[ebp-34]@H_301_0@ @H_301_0@ 00401A58 MOV EDI,DWORD PTR DS:[<&MSVBVM60.__vbaVarAdd>] @H_301_0@ 00401A5E MOV EBX,DWORD PTR DS:[<&MSVBVM60.__vbaVarSub>] @H_301_0@ @H_301_0@ 00401A64 LEA EAX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401A67 LEA ECX,DWORD PTR SS:[EBP-54] // 0@H_301_0@ 00401A6A PUSH EAX@H_301_0@ 00401A6B PUSH ECX@H_301_0@ 00401A6C MOV DWORD PTR SS:[EBP-4C],0@H_301_0@ 00401A73 MOV DWORD PTR SS:[EBP-54],8002@H_301_0@ 00401A7A CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarTstGt>] @H_301_0@ 00401A80 TEST AX,AX@H_301_0@ 00401A83 JE SHORT 工程2.00401ABF // a 不大于0则退出循环@H_301_0@ // while a > 0@H_301_0@ @H_301_0@ 00401A85 LEA EDX,DWORD PTR SS:[EBP-34] @H_301_0@ 00401A88 LEA EAX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401A8B PUSH EDX // b@H_301_0@ 00401A8C LEA ECX,DWORD PTR SS:[EBP-44] @H_301_0@ 00401A8F PUSH EAX // a@H_301_0@ 00401A90 PUSH ECX@H_301_0@ 00401A91 CALL EDI @H_301_0@ 00401A93 MOV EDX,EAX // b + a@H_301_0@ 00401A95 LEA ECX,DWORD PTR SS:[EBP-34] // b @H_301_0@ 00401A98 CALL ESI @H_301_0@ // b = b + a@H_301_0@ @H_301_0@ 00401A9A LEA EDX,DWORD PTR SS:[EBP-24] // a@H_301_0@ 00401A9D LEA EAX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401AA0 PUSH EDX@H_301_0@ 00401AA1 LEA ECX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401AA4 PUSH EAX@H_301_0@ 00401AA5 PUSH ECX@H_301_0@ 00401AA6 MOV DWORD PTR SS:[EBP-4C],1 // 1@H_301_0@ 00401AAD MOV DWORD PTR SS:[EBP-54],2 // integer类型@H_301_0@ 00401AB4 CALL EBX@H_301_0@ 00401AB6 MOV EDX,EAX // a - 1@H_301_0@ 00401AB8 LEA ECX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401ABB CALL ESI@H_301_0@ // a = a - 1@H_301_0@ @H_301_0@ 00401ABD JMP SHORT 工程2.00401A64 //注意:这里往回跳@H_301_0@ // Wend@H_301_0@ =========================================================== @H_301_0@ 4)do语句 @H_301_0@ @H_301_0@ 这个语句的格式比较多,典型的格式如下:@H_301_0@ @H_301_0@ Do @H_301_0@ 语句块@H_301_0@ Loop Until 循环条件@H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@H_301_0@ Dim a,b@H_301_0@ a = 3@H_301_0@ b = 0@H_301_0@ Do@H_301_0@ b = a + b@H_301_0@ a = a - 1@H_301_0@ Loop Until a <= 0 @H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@H_301_0@ 反汇编代码(速度优化)@H_301_0@ 00401A1F MOV ESI,EDI@H_301_0@ 00401A27 MOV EBX,3 //3@H_301_0@ 00401A45 MOV DWORD PTR SS:[EBP-54],EBX //integer@H_301_0@ 00401A48 CALL ESI @H_301_0@ // a = 3 //[ebp-24]@H_301_0@ @H_301_0@ 00401A4A LEA EDX,EDI //0@H_301_0@ 00401A53 MOV DWORD PTR SS:[EBP-54],EBX //integer@H_301_0@ 00401A56 CALL ESI@H_301_0@ // b = 0 //[ebp-34]@H_301_0@ @H_301_0@ 00401A58 MOV EBX,DWORD PTR DS:[<&MSVBVM60.__vbaVarAdd>] @H_301_0@ 00401A5E LEA EAX,DWORD PTR SS:[EBP-24] // a@H_301_0@ 00401A61 LEA ECX,DWORD PTR SS:[EBP-34] // b@H_301_0@ 00401A64 PUSH EAX@H_301_0@ 00401A65 LEA EDX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401A68 PUSH ECX@H_301_0@ 00401A69 PUSH EDX@H_301_0@ 00401A6A CALL EBX@H_301_0@ 00401A6C MOV EDX,EAX@H_301_0@ 00401A6E LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401A71 CALL ESI@H_301_0@ // b = a + b@H_301_0@ @H_301_0@ 00401A73 LEA EAX,DWORD PTR SS:[EBP-24] // a@H_301_0@ 00401A76 LEA ECX,DWORD PTR SS:[EBP-54] @H_301_0@ 00401A79 PUSH EAX@H_301_0@ 00401A7A LEA EDX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401A7D PUSH ECX@H_301_0@ 00401A7E PUSH EDX@H_301_0@ 00401A7F MOV DWORD PTR SS:[EBP-4C],1 // 1@H_301_0@ 00401A86 MOV DWORD PTR SS:[EBP-54],2 // integer@H_301_0@ 00401A8D CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarSub>] @H_301_0@ 00401A93 MOV EDX,EAX@H_301_0@ 00401A95 LEA ECX,DWORD PTR SS:[EBP-24] // a@H_301_0@ 00401A98 CALL ESI@H_301_0@ // a = a - 1@H_301_0@ 00401A9A LEA EAX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401A9D LEA ECX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401AA0 PUSH EAX@H_301_0@ 00401AA1 PUSH ECX@H_301_0@ 00401AA2 MOV DWORD PTR SS:[EBP-4C],EDI // 0@H_301_0@ 00401AA5 MOV DWORD PTR SS:[EBP-54],8002@H_301_0@ 00401AAC CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarTstLe>] @H_301_0@ 00401AB2 TEST AX,AX@H_301_0@ 00401AB5 JE SHORT 工程2.00401A5E@H_301_0@ loop until a <= 0 @H_301_0@ ===========================================================@H_301_0@ 5)for语句@H_301_0@ @H_301_0@ for语句的典型语法如下:@H_301_0@ @H_301_0@ for 循环变量 = 初值 to 终值 [step 步长]@H_301_0@ 循环体@H_301_0@ next 循环变量@H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@H_301_0@ 代码:@H_301_0@ a = 0@H_301_0@ For i = 0 To 100 Step 2@H_301_0@ a = a + i@H_301_0@ Next i@H_301_0@ %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@H_301_0@ 反汇编代码(速度优化)@H_301_0@ 00401A42 MOV EBX,DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>] @H_301_0@ 00401A48 XOR ESI,ESI@H_301_0@ 00401A4A MOV EDI,2@H_301_0@ 00401A4F MOV DWORD PTR SS:[EBP-54],ESI@H_301_0@ 00401A52 LEA EDX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401A55 LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401A58 MOV DWORD PTR SS:[EBP-24],ESI@H_301_0@ 00401A5B MOV DWORD PTR SS:[EBP-34],ESI@H_301_0@ 00401A5E MOV DWORD PTR SS:[EBP-44],ESI@H_301_0@ 00401A61 MOV DWORD PTR SS:[EBP-64],ESI@H_301_0@ 00401A64 MOV DWORD PTR SS:[EBP-74],ESI@H_301_0@ 00401A67 MOV DWORD PTR SS:[EBP-84],ESI@H_301_0@ 00401A6D MOV DWORD PTR SS:[EBP-94],ESI@H_301_0@ 00401A73 MOV DWORD PTR SS:[EBP-4C],ESI //0@H_301_0@ 00401A76 MOV DWORD PTR SS:[EBP-54],EDI //integer@H_301_0@ 00401A79 CALL EBX @H_301_0@ // a = 0 //[ebp-34]@H_301_0@ @H_301_0@ 00401A7B LEA EAX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401A7E LEA ECX,DWORD PTR SS:[EBP-64] @H_301_0@ 00401A81 PUSH EAX // 增量@H_301_0@ 00401A82 LEA EDX,DWORD PTR SS:[EBP-74]@H_301_0@ 00401A85 PUSH ECX // 终值@H_301_0@ 00401A86 LEA EAX,DWORD PTR SS:[EBP-94]@H_301_0@ 00401A8C PUSH EDX // 初值@H_301_0@ 00401A8D LEA ECX,DWORD PTR SS:[EBP-84]@H_301_0@ 00401A93 PUSH EAX //临时终值@H_301_0@ 00401A94 LEA EDX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401A97 PUSH ECX //临时增量@H_301_0@ 00401A98 PUSH EDX // 循环变量@H_301_0@ 00401A99 MOV DWORD PTR SS:[EBP-4C],EDI // 2@H_301_0@ 00401A9C MOV DWORD PTR SS:[EBP-54],EDI // integer@H_301_0@ 00401A9F MOV DWORD PTR SS:[EBP-5C],64 // 100@H_301_0@ 00401AA6 MOV DWORD PTR SS:[EBP-64],EDI // integer@H_301_0@ 00401AA9 MOV DWORD PTR SS:[EBP-6C],ESI // 0@H_301_0@ 00401AAC MOV DWORD PTR SS:[EBP-74],EDI // integer@H_301_0@ 00401AAF CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarForInit>] @H_301_0@ //For i = 0 To 100 Step 2@H_301_0@ @H_301_0@ 00401AB5 MOV EDI,DWORD PTR DS:[<&MSVBVM60.__vbaVarAdd>] @H_301_0@ 00401ABB CMP EAX,ESI@H_301_0@ 00401ABD JE SHORT 工程2.00401AEE@H_301_0@ @H_301_0@ 00401ABF LEA EAX,DWORD PTR SS:[EBP-34] //a@H_301_0@ 00401AC2 LEA ECX,DWORD PTR SS:[EBP-24] //i@H_301_0@ 00401AC5 PUSH EAX@H_301_0@ 00401AC6 LEA EDX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401AC9 PUSH ECX@H_301_0@ 00401ACA PUSH EDX@H_301_0@ 00401ACB CALL EDI@H_301_0@ 00401ACD MOV EDX,EAX@H_301_0@ 00401ACF LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401AD2 CALL EBX@H_301_0@ // a = a + i@H_301_0@ @H_301_0@ 00401AD4 LEA EAX,DWORD PTR SS:[EBP-94] //临时终值@H_301_0@ 00401ADA LEA ECX,DWORD PTR SS:[EBP-84] //临时增量@H_301_0@ 00401AE0 PUSH EAX@H_301_0@ 00401AE1 LEA EDX,DWORD PTR SS:[EBP-24] // 循环变量@H_301_0@ 00401AE4 PUSH ECX@H_301_0@ 00401AE5 PUSH EDX@H_301_0@ 00401AE6 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarForNext>] @H_301_0@ 00401AEC JMP SHORT 工程2.00401ABB@H_301_0@ // next i@H_301_0@ ===========================================================@H_301_0@ 上面出现了我定义的两个名词:临时终值和临时增量,这两个值什么意思呢?@H_301_0@ 也就是当__vbaVarForInit函数执行完后这两个值将分别被赋予终值和增量的值。@H_301_0@ 从上面可以看出,__vbaVarForInit只是执行一次,以后再执行就是__vbaVarForNext@H_301_0@ 了。因此程序必须知道循环变量到那里结束,每次步长多少。这两个值就是保存这些@H_301_0@ 信息的。@H_301_0@ 当满足循环条件时,这两个函数都返回1,不满足时返回0。@H_301_0@ @H_301_0@ ===========================================================@H_301_0@ 到现在为止分析基本的程序结构应该没问题了。在这里把前面没完成的工作@H_301_0@ 补一下:看看 Array函数和 For Each ... Next 语句。@H_301_0@ @H_301_0@ 代码:@H_301_0@ Dim a@H_301_0@ a = Array(5,6,7)@H_301_0@ For Each x In a@H_301_0@ Print x@H_301_0@ Next x @H_301_0@ @H_301_0@ 编译后的汇编代码:@H_301_0@ 00401AC3 XOR ESI,ESI@H_301_0@ 00401AC5 LEA EDX,DWORD PTR SS:[EBP-48]@H_301_0@ 00401AC8 PUSH ESI@H_301_0@ 00401AC9 PUSH 2@H_301_0@ 00401ACB PUSH 1@H_301_0@ 00401ACD PUSH ESI@H_301_0@ 00401ACE PUSH EDX@H_301_0@ 00401ACF PUSH 10@H_301_0@ 00401AD1 PUSH 880@H_301_0@ 00401AD6 MOV DWORD PTR SS:[EBP-24],ESI@H_301_0@ 00401AD9 MOV DWORD PTR SS:[EBP-34],ESI@H_301_0@ 00401ADC MOV DWORD PTR SS:[EBP-44],ESI@H_301_0@ 00401ADF MOV DWORD PTR SS:[EBP-48],ESI@H_301_0@ 00401AE2 MOV DWORD PTR SS:[EBP-58],ESI@H_301_0@ 00401AE5 MOV DWORD PTR SS:[EBP-68],ESI@H_301_0@ 00401AE8 MOV DWORD PTR SS:[EBP-78],ESI@H_301_0@ 00401AEB MOV DWORD PTR SS:[EBP-7C],ESI@H_301_0@ 00401AEE MOV DWORD PTR SS:[EBP-80],ESI@H_301_0@ 00401AF1 MOV DWORD PTR SS:[EBP-84],ESI@H_301_0@ 00401AF7 MOV DWORD PTR SS:[EBP-88],ESI@H_301_0@ 00401AFD CALL DWORD PTR DS:[<&MSVBVM60.__vbaRedim>] //定义一个变体类型的动态数组@H_301_0@
@H_301_0@
//==================================================================================================
4. VB内部函数@H_301_0@ 1) 自定义函数的调用@H_301_0@ @H_301_0@ 这里我们看看和VB的内部函数有关的一些内容。@H_301_0@ 老规矩,先看一段代码:@H_301_0@ Function myadd(ByVal a As Variant,b As Variant)@H_301_0@ myadd = a + b@H_301_0@ End Function@H_301_0@ @H_301_0@ Sub myprint(ByVal a As Variant)@H_301_0@ Print a@H_301_0@ End Sub@H_301_0@ @H_301_0@ Private Sub Command1_Click()@H_301_0@ Dim a,b,c@H_301_0@ @H_301_0@ a = 10@H_301_0@ b = 20@H_301_0@ c = myadd(a,b)@H_301_0@ myprint c@H_301_0@ End Sub @H_301_0@ @H_301_0@ 这段代码里包含了自定义的过程,函数及函数的两种参数传递方式。下面的反汇编代码@H_301_0@ 是过程Command1_Click()的。自定义的函数和过程的反汇编代码和这相仿,可以字节反汇@H_301_0@ 编对比看一下。@H_301_0@ 反汇编代码如下,默认方式(速度优化)编译的,这次给出的是完整的汇编代码:@H_301_0@ @H_301_0@ 00401C50 PUSH EBP@H_301_0@ 00401C51 MOV EBP,ESP@H_301_0@ 00401C53 SUB ESP,0C @H_301_0@ @H_301_0@ 00401C56 PUSH <JMP.&MSVBVM60.__vbaExceptHandler> @H_301_0@ 00401C5B MOV EAX,DWORD PTR FS:[0]@H_301_0@ 00401C61 PUSH EAX@H_301_0@ 00401C62 MOV DWORD PTR FS:[0],ESP //安装局部线程异常@H_301_0@ @H_301_0@ 00401C69 SUB ESP,5C //下面这一段和vb编译器有关@H_301_0@ 00401C6C PUSH EBX //因为vb是基于com技术实现的@H_301_0@ 00401C6D PUSH ESI //更详细的内容可以参考@H_301_0@ 00401C6E PUSH EDI //<<软件加密技术内幕>>一书@H_301_0@ 00401C6F MOV DWORD PTR SS:[EBP-C],ESP@H_301_0@ 00401C72 MOV DWORD PTR SS:[EBP-8],工程2.004010B0@H_301_0@ 00401C79 MOV ESI,DWORD PTR SS:[EBP+8]@H_301_0@ 00401C7C MOV EAX,ESI@H_301_0@ 00401C7E AND EAX,1@H_301_0@ 00401C81 MOV DWORD PTR SS:[EBP-4],EAX@H_301_0@ 00401C84 AND ESI,FFFFFFFE@H_301_0@ 00401C87 PUSH ESI@H_301_0@ 00401C88 MOV DWORD PTR SS:[EBP+8],ESI //me@H_301_0@ 00401C8B MOV ECX,DWORD PTR DS:[ESI]@H_301_0@ 00401C8D CALL DWORD PTR DS:[ECX+4] ;MSVBVM60.Zombie_AddRef@H_301_0@ @H_301_0@ 00401C90 MOV EDI,DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>] @H_301_0@ 00401C96 XOR EBX,EBX@H_301_0@ 00401C98 MOV DWORD PTR SS:[EBP-64],EBX@H_301_0@ 00401C9B LEA EDX,DWORD PTR SS:[EBP-64]@H_301_0@ 00401C9E LEA ECX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401CA1 MOV DWORD PTR SS:[EBP-24],EBX@H_301_0@ 00401CA4 MOV DWORD PTR SS:[EBP-34],EBX@H_301_0@ 00401CA7 MOV DWORD PTR SS:[EBP-44],EBX@H_301_0@ 00401CAA MOV DWORD PTR SS:[EBP-54],EBX@H_301_0@ 00401CAD MOV DWORD PTR SS:[EBP-5C],0A //10@H_301_0@ 00401CB4 MOV DWORD PTR SS:[EBP-64],2 //integer@H_301_0@ 00401CBB CALL EDI @H_301_0@ //a = 10 @H_301_0@ 00401CBD LEA EDX,DWORD PTR SS:[EBP-64]@H_301_0@ 00401CC0 LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401CC3 MOV DWORD PTR SS:[EBP-5C],14 //20@H_301_0@ 00401CCA MOV DWORD PTR SS:[EBP-64],2 //integer@H_301_0@ 00401CD1 CALL EDI@H_301_0@ // b = 20@H_301_0@ 00401CD3 LEA EAX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401CD6 LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401CD9 PUSH EAX //存放函数的返回值@H_301_0@ 00401CDA PUSH ECX //引用参数b@H_301_0@ 00401CDB MOV ECX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401CDE SUB ESP,10 //这个空间复制变量参数a@H_301_0@ 00401CE1 MOV EAX,ESP //变体类型,所以要16个字节@H_301_0@ 00401CE3 MOV EDX,DWORD PTR DS:[ESI]@H_301_0@ 00401CE5 PUSH ESI //me@H_301_0@ 00401CE6 MOV DWORD PTR DS:[EAX],ECX@H_301_0@ 00401CE8 MOV ECX,DWORD PTR SS:[EBP-20]@H_301_0@ 00401CEB MOV DWORD PTR DS:[EAX+4],ECX@H_301_0@ 00401CEE MOV ECX,DWORD PTR SS:[EBP-1C]@H_301_0@ 00401CF1 MOV DWORD PTR DS:[EAX+8],ECX@H_301_0@ 00401CF4 MOV ECX,DWORD PTR SS:[EBP-18]@H_301_0@ 00401CF7 MOV DWORD PTR DS:[EAX+C],ECX@H_301_0@ 00401CFA CALL DWORD PTR DS:[EDX+6F8] //调用函数 myadd@H_301_0@ 00401D00 CMP EAX,EBX@H_301_0@ 00401D02 JGE SHORT 工程2.00401D16@H_301_0@ 00401D04 PUSH 6F8@H_301_0@ 00401D09 PUSH 工程2.00401644@H_301_0@ 00401D0E PUSH ESI@H_301_0@ 00401D0F PUSH EAX@H_301_0@ 00401D10 CALL DWORD PTR DS:[<&MSVBVM60.__vbaHresultCheckObj>] @H_301_0@ 00401D16 LEA EDX,DWORD PTR SS:[EBP-54] @H_301_0@ 00401D19 LEA ECX,DWORD PTR SS:[EBP-44] @H_301_0@ 00401D1C CALL EDI @H_301_0@ //把结果赋值给变量c@H_301_0@ @H_301_0@ 00401D1E MOV ECX,DWORD PTR SS:[EBP-44] //c作为变量参数传递@H_301_0@ 00401D21 SUB ESP,10 //所以这里要分配16个字节@H_301_0@ 00401D24 MOV EAX,ESP@H_301_0@ 00401D26 MOV EDX,DWORD PTR DS:[ESI]@H_301_0@ 00401D28 PUSH ESI //me@H_301_0@ 00401D29 MOV DWORD PTR DS:[EAX],ECX@H_301_0@ 00401D2B MOV ECX,DWORD PTR SS:[EBP-40]@H_301_0@ 00401D2E MOV DWORD PTR DS:[EAX+4],ECX@H_301_0@ 00401D31 MOV ECX,DWORD PTR SS:[EBP-3C]@H_301_0@ 00401D34 MOV DWORD PTR DS:[EAX+8],ECX@H_301_0@ 00401D37 MOV ECX,DWORD PTR SS:[EBP-38]@H_301_0@ 00401D3A MOV DWORD PTR DS:[EAX+C],ECX@H_301_0@ 00401D3D CALL DWORD PTR DS:[EDX+6FC] //调用myprint@H_301_0@ 00401D43 CMP EAX,EBX@H_301_0@ 00401D45 JGE SHORT 工程2.00401D59@H_301_0@ 00401D47 PUSH 6FC@H_301_0@ 00401D4C PUSH 工程2.00401644@H_301_0@ 00401D51 PUSH ESI@H_301_0@ 00401D52 PUSH EAX@H_301_0@ 00401D53 CALL DWORD PTR DS:[<&MSVBVM60.__vbaHresultCheckObj>] @H_301_0@ @H_301_0@ @H_301_0@ 00401D59 MOV DWORD PTR SS:[EBP-4],EBX@H_301_0@ 00401D5C PUSH 工程2.00401D83 //这里压入返回地址@H_301_0@ 00401D61 JMP SHORT 工程2.00401D6D@H_301_0@ 00401D63 LEA ECX,DWORD PTR SS:[EBP-54]@H_301_0@ 00401D66 CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeVar>] @H_301_0@ 00401D6C RETN@H_301_0@ @H_301_0@ 00401D6D MOV ESI,DWORD PTR DS:[<&MSVBVM60.__vbaFreeVar>] @H_301_0@ 00401D73 LEA ECX,DWORD PTR SS:[EBP-24]@H_301_0@ 00401D76 CALL ESI @H_301_0@ 00401D78 LEA ECX,DWORD PTR SS:[EBP-34]@H_301_0@ 00401D7B CALL ESI@H_301_0@ 00401D7D LEA ECX,DWORD PTR SS:[EBP-44]@H_301_0@ 00401D80 CALL ESI@H_301_0@ 00401D82 RETN //上面这里释放变量a,c@H_301_0@ @H_301_0@ 00401D83 MOV EAX,DWORD PTR SS:[EBP+8] //返回到这里做善后处理@H_301_0@ 00401D86 PUSH EAX@H_301_0@ 00401D87 MOV EDX,DWORD PTR DS:[EAX]@H_301_0@ 00401D89 CALL DWORD PTR DS:[EDX+8] ; MSVBVM60.Zombie_Release@H_301_0@ 00401D8C MOV EAX,DWORD PTR SS:[EBP-4]@H_301_0@ 00401D8F MOV ECX,DWORD PTR SS:[EBP-14]@H_301_0@ 00401D92 POP EDI@H_301_0@ 00401D93 POP ESI@H_301_0@ 00401D94 MOV DWORD PTR FS:[0],ECX //恢复局部线程异常@H_301_0@ 00401D9B POP EBX@H_301_0@ 00401D9C MOV ESP,EBP@H_301_0@ 00401D9E POP EBP@H_301_0@ 00401D9F RETN 4@H_301_0@ @H_301_0@ 从这里可以看出,在调用自程序时还要传递一个me参数。对于函数来说,还有一个@H_301_0@ 返回结果要传递过去。@H_301_0@ @H_301_0@ 2) VB的内部函数@H_301_0@ VB的内部函数在反汇编代码中看起来和我们熟悉的函数名并不一样。这一点跟踪过@H_301_0@ VB程序的人一定深有体会。大多数函数名都可以从名字上猜出来。但也有相差太多的。@H_301_0@ 我整理了一份函数列表。不是全部,但包含了大多数内部函数,应该能应付一般的应用。@H_301_0@ 函数列表在这个贴子的附件中。@H_301_0@ VB的运算符大多是用函数实现的。这是一个好消息。这意味着我们不必费力去分析@H_301_0@ 过多的代码而只要能辨别出那些函数名即可。@H_301_0@ VB的内部函数并不都是以Stdcall的方式传递参数,尽管大部分是这样的。分析@H_301_0@ VB程序时要注意这点。@H_301_0@ VB的反汇编代码中大部分的函数都要传递一个存放返回值的变量,而且返回值也会@H_301_0@ 在EAX中或者浮点栈中返回。@H_301_0@ 这里只举一个例子。其他的可以参考我整理的列表。@H_301_0@ @H_301_0@ 这是函数instr,常用的一个:@H_301_0@ @H_301_0@ __vbaInStrVar ;函数 InStr(起始位置,源字符串,目标字符串,比较方式) @H_301_0@ @H_301_0@ LEA EDX,DWORD PTR SS:[EBP-24] @H_301_0@ PUSH 1 ;起始位置,从1开始 @H_301_0@ LEA EAX,DWORD PTR SS:[EBP-34] @H_301_0@ PUSH EDX ;被搜索的字符串 @H_301_0@ PUSH EAX ;要搜的字符串 @H_301_0@ LEA ECX,DWORD PTR SS:[EBP-54] @H_301_0@ PUSH 1 ;比较方式 @H_301_0@ PUSH ECX ;返回的结果 @H_301_0@ CALL DWORD PTR DS:[<&MSVBVM60.__vbaInStrVar>]@H_301_0@ MOV EDX,EAX ;结果同时在eax中返回@H_301_0@ @H_301_0@ @H_301_0@ 3) VB的外部函数调用@H_301_0@ VB对外部函数的调用是如何实现的呢?先看看下面的代码:@H_301_0@ Private Declare Function MessageBeep Lib \"user32\" (ByVal wType As Long) As Long@H_301_0@ Private Sub Command1_Click()@H_301_0@ MessageBeep 0@H_301_0@ End Sub@H_301_0@ 对应的反汇编代码如下:@H_301_0@ @H_301_0@ 00401A2F PUSH 0 //这里压入参数@H_301_0@ 00401A31 CALL 工程2.004016C8 //这个Call我们要继续跟进才知道调用的什么函数@H_301_0@ 00401A36 CALL DWORD PTR DS:[<&MSVBVM60.__vbaSetSystemError>] @H_301_0@ @H_301_0@ @H_301_0@ 004016C8 MOV EAX,DWORD PTR DS:[4022DC] //第一次调用时为0,以后就调用这里@H_301_0@ 004016CD OR EAX,EAX //这个程序里为0@H_301_0@ 004016CF JE SHORT 工程2.004016D3@H_301_0@ 004016D1 JMP EAX@H_301_0@ 004016D3 PUSH 工程2.004016B0 //注意这个地址,这是指向代码段的@H_301_0@ //我们先看看这里有什么@H_301_0@ 004016B0 98 16 40 00 A4 16 40 00 ?@.?@.@H_301_0@ //再跟进@H_301_0@ 00401698 75 73 65 72 33 32 00 00 user32..@H_301_0@ 004016A0 0C 00 00 00 4D 65 73 73 ....Mess@H_301_0@ 004016A8 61 67 65 42 65 65 70 00 ageBeep.@H_301_0@ //是不是看到了要调用的函数了^_^@H_301_0@ //其实不用这么麻烦@H_301_0@ 004016D8 MOV EAX,<JMP.&MSVBVM60.DllFunctionCall>@H_301_0@ 004016DD CALL EAX //执行完这一行看eax,看到什么了@H_301_0@ //EAX 84936A78 Thunk to USER32.MessageBeep@H_301_0@ 004016DF JMP EAX //这里就是真正的调用了@H_301_0@ @H_301_0@ 注意:调用的外部函数名不在程序的导入表里,而是在代码段里。程序是调用@H_301_0@ 函数MSVBVM60.DllFunctionCall来取得外部函数的地址的。@H_301_0@
@H_301_0@
@H_301_0@
//===============================================================================
5. VB中的异常处理 这里我只从跟踪的角度来谈异常处理。很多人说在VB中发生异常是会跟进虚拟机里, 在里面打转。其实VB的异常处理没有那么复杂,可以很容易的出来的。 这里先介绍一个VB的万能断点:MSVBVM60.__vbaExceptHandler,VB在每个过程 的开始都要安装一个线程异常处理过程,在OD中对这个函数下断点百分百有效。需要注意 的事当你找到自己需要的地方时要及时清除这个断点,否则会在你不期望的时候中断 下面依旧以一段代码为例说明: Dim a,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更深一 层的论述。还有就是在末尾提到的那些资源。你应该学会自己获取需要的知识。^_^
原文链接:https://www.f2er.com/vb/260225.html