VB6逆向工程浅析

VB程序逆向 1、VB介绍 Visual Basic 是一种具有良好图形用户界面的程序设计语言。 Visual的意思是“可视的”,也就是直观的编程方法,在编程时不需要编写大量代码去描述界面元素的外观和位置,只需把预先建立的对象拖放到窗体上。Basic是指BASIC语言,VB使用了BASIC语言作为代码。 VB采用面向对象和事件驱动的程序设计机制,这种机制下,VB程序往往是多线程的,在分析过程中定位主线程和事件处理过程尤为重要。 在编译方式上,VB既有直接编译生成的可执行程序,也有间接编译生成的可执行程序,不同的编 阅读详情

VB6逆向工程浅析  

2007-12-03 10:55:27|  分类: 破解|举报|字号 订阅

前言 

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类型的变量

2. 复杂变量的内部实现

这里所提到的复杂变量(我自己的叫法 ),是指枚举,数组和记录类型的变量。


1) 枚举类型的实现

先定义一个枚举类型如下:
Enum myweek
sun
mon
tues
wednes
thurs
fri
satur
End Enum
然后再编写一段使用枚举类型的代码:
Dim a As myweek
Dim b As Integer

a = sun
b = a
Print b

默认设置编译这段代码,接着我们看看编译器生成了什么。
; 37 : Dim a As myweek
; 38 : Dim b As Integer
; 39 : 
; 40 : a = sun
; 41 : b = a

xor ecx, ecx // a = sun ,即 a = 0
call DWORD PTR 
__imp_@__vbaI2I4 // b = a

; 42 : Print b

push eax // b
push esi
push OFFSET FLAT:___vba@006255A0
call DWORD PTR __imp____vbaPrintObj //Print

***************************************************
可以看出,枚举类型在代码里是直接用常量数值代替的。


2) 数组类型的实现

数组的概念比较复杂,为了研究方便,这里只讨论一维数组,并且不是嵌套的。 
先看看静态数组的定义与实现。

代码:
Dim a(3 To 6) As Integer

反汇编代码:

004019FF PUSH 2
00401A01 LEA EAX,DWORD PTR SS:[EBP-2C] // 数组变量
00401A04 XOR ESI,ESI
00401A06 PUSH 工程1.00401694 // 指向代码段
00401A0B PUSH EAX 
00401A0C MOV DWORD PTR SS:[EBP-34],ESI
00401A0F CALL DWORD PTR DS:[<&MSVBVM60.__vbaAryConstruct2>] // 构造一个数组

指行到这里时看[ebp-2c]的内容:
0063F3E4 01 00 92 00 02 00 00 00 .? ...
0063F3EC 00 00 00 00 C0 0F 51 00 ....?Q.
0063F3F4 04 00 00 00 03 00 00 00 ... ...

这些数据除了63F3F0处的地址是__vbaAryConstruct2函数填进去的,其余的都是从
401694处拷贝过来的。因此__vbaAryConstruct2函数的作用可以这样理解:先从401694
处拷贝24个字节到ebp-2c处,然后分配一块空间,把指向新分配的空间的指针填到63F3F0
处。
那么上面这些数据到底是什么意思呢?看下面的分析.


00401A18 PUSH 工程1.00401A30 //指向退出地址
00401A1D LEA EDX,DWORD PTR SS:[EBP-34]
00401A20 LEA ECX,DWORD PTR SS:[EBP-2C] //要释放的数组变量
00401A23 PUSH EDX
00401A24 PUSH 0
00401A26 MOV DWORD PTR SS:[EBP-34],ECX
00401A29 CALL DWORD PTR DS:[<&MSVBVM60.__vbaAryDestruct>] // 释放一个数组

为了弄清楚上面提到的那些内存数据的含义,我分别定义了不同大小不同类型的数组来比较,
下面是dump出来的典型数据:

Dim a(3 To 6) 
0063F3E4 01 00 92 08 10 00 00 00 .? ...
0063F3EC 00 00 00 00 2C 01 41 00 ...., A.
0063F3F4 04 00 00 00 03 00 00 00 ... ...

Dim a(3 To 6) As String 
0063F3E4 01 00 92 01 04 00 00 00 .? ...
0063F3EC 00 00 00 00 C0 0F 51 00 ....?Q.
0063F3F4 04 00 00 00 03 00 00 00 ... ...

Dim a(3 To 6) As Integer 
0063F3E4 01 00 92 00 02 00 00 00 .? ...
0063F3EC 00 00 00 00 C0 0F 51 00 ....?Q.
0063F3F4 04 00 00 00 03 00 00 00 ... ...

我总结的数组变量内存数据的说明:
0063F3E4 处的两个字节代表数组的维数
0063F3E6 处的一个字节 92 代表静态数组
0063F3E7 处的一个字节随着不同类型的变量有不同的变化。
08 : 变体类型 
01 : String
00 : Integer,byte,long,single,double,date 
0063F3E8 处的两个字节表示一个数组元素所占的内存空间字节数。
0063F3EC 处的4个字节总是0,可能是为了对齐。
0063F3F0 处的两个字节代表分配的空间的地址指针,即数组数据。
0063F3F4 处的两个字节代表静态数组元素的个数。
0063F3F8 处的两个字节代表数组的起始下标。

上面大概的对数组变量的数据做了说明,为了验证一下,再看一个3维数组的定义:

Dim a(1 To 2, 3 To 5, 6 To 9) As Integer

0063F3D4 03 00 92 00 02 00 00 00 .? ...
0063F3DC 00 00 00 00 C0 0F 51 00 ....?Q.
0063F3E4 04 00 00 00 06 00 00 00 ... ...
0063F3EC 03 00 00 00 03 00 00 00 ... ...
0063F3F4 02 00 00 00 01 00 00 00 ... ...

可以看出,静态数组的信息在编译时就被编码到了代码段里。
静态数组的构造用 __vbaAryConstruct2
静态数组的释放用 __vbaAryDestruct

///////////////////////////////////////////////////////////

动态数组又是怎样实现的呢?
代码:
Dim a() As Date
ReDim a(2 To 5)

反汇编代码:
004019CF PUSH 2 //起始下标
004019D1 PUSH 5 //结束下标
004019D3 PUSH 1 //数组维数
004019D5 LEA EAX,DWORD PTR SS:[EBP-18]
004019D8 PUSH 7 //变量类型
004019DA PUSH EAX //我们重定义的数组变量
004019DB XOR ESI,ESI
004019DD PUSH 8 //数组元素所占内存空间的字节数
004019DF PUSH 80 //动态数组标记
004019E4 MOV DWORD PTR SS:[EBP-18],ESI
004019E7 CALL DWORD PTR DS:[<&MSVBVM60.__vbaRedim>] // ReDim
004019ED ADD ESP,1C
004019F0 MOV DWORD PTR SS:[EBP-4],ESI
004019F3 PUSH 工程1.00401A05
004019F8 LEA ECX,DWORD PTR SS:[EBP-18] //数组变量
004019FB PUSH ECX
004019FC PUSH 0
004019FE CALL DWORD PTR DS:[<&MSVBVM60.__vbaAryDestruct>] //释放数组

当执行到 004019ED 时,我们查看[ebp-18]处的内存数据,可以看到是

0063F3F8 D0 0F 51 00 ?Q.豇

这是一个指针,我们接着 follow dword in dump,可以看到数据如下:

00510FD0 01 00 80 00 08 00 00 00 . . ...
00510FD8 00 00 00 00 2C 01 41 00 ...., A.
00510FE0 04 00 00 00 02 00 00 00 ... ...

这个结构和静态数组的结构没有什么不同! ^_^
同时也可以看出,动态数组是动态分配的,这和静态数组信息被编译到代码段里不同。

总结:
动态数组的ReDim(重定义)用 __vbaRedim (注:这是可变参数的函数)
动态数组的释放用 __vbaAryDestruct

///////////////////////////////////////////////////////////
再看一下常用的数组操作: 
先看两个函数,Lbound和Ubound。它们的实现分别如下:

===================================== 
__vbaLbound ;函数 Lbound ,取数组下标下界

LEA EAX,DWORD PTR SS:[EBP-2C] ;参数1,数组
PUSH EAX
PUSH 1 ;参数2,数组维数
CALL DWORD PTR DS:[<&MSVBVM60.__vbaLboun>; MSVBVM60.__vbaLbound
;结果在eax中返回 
===================================== 
__vbaUbound ;函数 Ubound ,取数组下标上界

LEA ECX,DWORD PTR SS:][EBP-2C] ;参数1,数组
PUSH ECX
PUSH 1 ;参数2,数组维数
CALL DWORD PTR DS:[<&MSVBVM60.__vbaUboun>;MSVBVM60.__vbaUbound
;结果在eax中返回
=====================================
这两个函数再操作动态数组时常使用,这里先记住他们的实现方法。

还有一个常使用的函数:Erase ,这个函数用来重新初始化静态数组的元素,或者
释放动态数组的存储空间。

LEA EAX,DWORD PTR SS:][EBP-18] ;数组变量的地址 
PUSH EAX 
PUSH EDI ;0 
CALL DWORD PTR DS:[<&MSVBVM60.__vbaErase>] ;函数Erase


下面编写一段简单的代码分析一下:
Dim a() As Integer
ReDim a(2 To 5)
a(2) = &HAA
Erase a

Dim b(1 To 3) As Integer
b(1) = &H55
Erase b

反汇编代码如下:
00401A4F PUSH 2
00401A51 LEA EAX,DWORD PTR SS:[EBP-30]
00401A54 XOR EDI,EDI
00401A56 PUSH 工程1.004016B8
00401A5B PUSH EAX
00401A5C MOV DWORD PTR SS:[EBP-18],EDI
00401A5F MOV DWORD PTR SS:[EBP-38],EDI
00401A62 CALL DWORD PTR DS:[<&MSVBVM60.__vbaAryConstruct2>]

/////////////////////////////////////上面这段是 Dim b(1 To 3) As Integer

00401A68 PUSH 2
00401A6A PUSH 5
00401A6C PUSH 1
00401A6E LEA ECX,DWORD PTR SS:[EBP-18]
00401A71 PUSH 2
00401A73 PUSH ECX
00401A74 PUSH 2
00401A76 PUSH 80
00401A7B CALL DWORD PTR DS:[<&MSVBVM60.__vbaRedim>]

//////////////////////////////////////上面这段是 Dim a() As Integer
////////////////////////////////////// ReDim a(2 To 5)

00401A81 MOV ECX,DWORD PTR SS:[EBP-18]
00401A84 ADD ESP,1C
00401A87 CMP ECX,EDI
00401A89 JE SHORT 工程1.00401AB0
00401A8B CMP WORD PTR DS:[ECX],1
00401A8F JNZ SHORT 工程1.00401AB0
00401A91 MOV EDX,DWORD PTR DS:[ECX+14] //取出下标
00401A94 MOV EAX,DWORD PTR DS:[ECX+10]
00401A97 MOV ESI,2
00401A9C SUB ESI,EDX
00401A9E CMP ESI,EAX
00401AA0 JB SHORT 工程1.00401AAB
00401AA2 CALL DWORD PTR DS:[<&MSVBVM60.__vbaGenerateBoundsError>]
00401AA8 MOV ECX,DWORD PTR SS:[EBP-18]
00401AAB LEA EAX,DWORD PTR DS:[ESI+ESI] //乘以2,即整数所占存储空间
00401AAE JMP SHORT 工程1.00401AB9
00401AB0 CALL DWORD PTR DS:[<&MSVBVM60.__vbaGenerateBoundsError>]
00401AB6 MOV ECX,DWORD PTR SS:[EBP-18]

////////////////////////////////////////上面这段包含了对生成的动态数组的检验

00401AB9 MOV EDX,DWORD PTR DS:[ECX+C] //取出变量a的值地址
00401ABC MOV ESI,DWORD PTR DS:[<&MSVBVM60.__vbaErase>] 
00401AC2 MOV WORD PTR DS:[EDX+EAX],0AA //对第一个元素赋值

////////////////////////////////////////到这里是 a(2) = &HAA

00401AC8 LEA EAX,DWORD PTR SS:[EBP-18]
00401ACB PUSH EAX
00401ACC PUSH EDI
00401ACD CALL ESI

////////////////////////////////////////到这里是 Erase a

00401ACF MOV ECX,DWORD PTR SS:[EBP-24]//取得变量b的值地址
00401AD2 LEA EAX,DWORD PTR SS:[EBP-38]
00401AD5 LEA EDX,DWORD PTR SS:[EBP-30]
00401AD8 PUSH EAX
00401AD9 MOV WORD PTR DS:[ECX],55

////////////////////////////////////////到这里是 b(1) = &H55
00401ADE PUSH EDI
00401ADF MOV DWORD PTR SS:[EBP-38],EDX
00401AE2 CALL ESI

////////////////////////////////////////到这里是 Erase b

00401AE4 MOV DWORD PTR SS:[EBP-4],EDI
00401AE7 PUSH 工程1.00401B09
00401AEC MOV ESI,DWORD PTR DS:[<&MSVBVM60.__vbaAryDestruct>] 
00401AF2 LEA ECX,DWORD PTR SS:[EBP-18]
00401AF5 XOR EDI,EDI
00401AF7 PUSH ECX
00401AF8 PUSH EDI
00401AF9 CALL ESI //释a

00401AFB LEA EAX,DWORD PTR SS:[EBP-38]
00401AFE LEA EDX,DWORD PTR SS:[EBP-30]
00401B01 PUSH EAX
00401B02 PUSH EDI
00401B03 MOV DWORD PTR SS:[EBP-38],EDX
00401B06 CALL ESI //释放b

关于数组就先分析这些,后面还要分析的是 For Each .. Next语句和 Array函数,
不过这两个都比较复杂些,先放到后面去。


3)结构类型的实现

VB的记录变量其实就是一些子域的顺序排列。

这句话怎么理解呢?看看下面的代码:

Private Type daterec
year As Integer
month As String * 3
day As Integer
End Type

Dim a As daterec

a.year = 2004
a.month = "Jan"
a.day = 21

反汇编代码如下:
004019DF XOR EAX,EAX
004019E1 LEA ECX,DWORD PTR SS:[EBP-1E]
004019E4 MOV DWORD PTR SS:[EBP-20],EAX
004019E7 PUSH 工程1.004014CC //"Jan" 
004019EC MOV DWORD PTR SS:[EBP-1C],EAX
004019EF PUSH ECX
004019F0 PUSH 3
004019F2 MOV WORD PTR SS:[EBP-18],AX
004019F6 MOV WORD PTR SS:[EBP-20],7D4 // a.year = 2004
004019FC CALL DWORD PTR DS:[<&MSVBVM60.__vbaLsetFixstr>]//a.month = "Jan"
00401A02 MOV WORD PTR SS:[EBP-18],15 // a.day = 15

执行到这里时看内存[ebp-20]:
0063F3F0 D4 07 4A 00 61 00 6E 00 ?J.a.n.
0063F3F8 15 00 6F 17 F4 F8 63 00 .o 豇c.

从 0063F3F0 到 0063F3F9 就是记录变量 a 的值了。

3. VB6的控制结构

下面要提到的vb的控制结构语句有:if语句,select case语句,while语句,do语句,
for语句。

1)if语句

if语句的典型语法是:

If 条件1 Then
语句块1 
ElseIf 条件2 Then
语句块2 
Else
语句块3 
End If
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% 
代码:
Dim a //注意:这里定义的是变体变量。
//如果不用变体变量,编译器将优化掉太多的代码。
//当你熟悉变体类型后,其他的将很容易分析 ^_^
a = 5

If a < 5 Then
MsgBox ("a < 5")
ElseIf a = 5 Then
MsgBox ("a = 5")
Else
MsgBox ("a > 5")
End If
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
反汇编代码:
00401A72 XOR ESI,ESI
00401A74 MOV EDI,5
00401A79 MOV DWORD PTR SS:[EBP-74],ESI
00401A7C LEA EDX,DWORD PTR SS:[EBP-74]
00401A7F LEA ECX,DWORD PTR SS:[EBP-24]
00401A82 MOV DWORD PTR SS:[EBP-24],ESI
00401A85 MOV DWORD PTR SS:[EBP-34],ESI ----> 这些变量是为 MsgBox 使用的
00401A88 MOV DWORD PTR SS:[EBP-44],ESI |
00401A8B MOV DWORD PTR SS:[EBP-54],ESI |
00401A8E MOV DWORD PTR SS:[EBP-64],ESI ---
00401A91 MOV DWORD PTR SS:[EBP-6C],EDI // 5
00401A94 MOV DWORD PTR SS:[EBP-74],2 //整数类型
00401A9B CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]//赋值
//到这里 a = 5 //[ebp-24]
00401AA1 LEA EAX,DWORD PTR SS:[EBP-24]
00401AA4 LEA ECX,DWORD PTR SS:[EBP-74] 
00401AA7 MOV EBX,8002
00401AAC PUSH EAX
00401AAD PUSH ECX
00401AAE MOV DWORD PTR SS:[EBP-6C],EDI // 5
00401AB1 MOV DWORD PTR SS:[EBP-74],EBX // 8002 
00401AB4 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarTstLt>] // a < 5 ?
00401ABA TEST AX,AX
00401ABD JE SHORT 工程2.00401AE4 //不小于则跳走

00401ABF MOV ECX,80020004
00401AC4 MOV EAX,0A
00401AC9 MOV DWORD PTR SS:[EBP-5C],ECX
00401ACC MOV DWORD PTR SS:[EBP-64],EAX
00401ACF MOV DWORD PTR SS:[EBP-4C],ECX
00401AD2 MOV DWORD PTR SS:[EBP-54],EAX
00401AD5 MOV DWORD PTR SS:[EBP-3C],ECX
00401AD8 MOV DWORD PTR SS:[EBP-44],EAX
00401ADB MOV DWORD PTR SS:[EBP-6C],工程2.004016C4; UNICODE "a < 5"
00401AE2 JMP SHORT 工程2.00401B63

00401AE4 LEA ECX,DWORD PTR SS:[EBP-24]
00401AE7 LEA EDX,DWORD PTR SS:[EBP-74]
00401AEA PUSH ECX
00401AEB PUSH EDX
00401AEC MOV DWORD PTR SS:[EBP-6C],EDI // 5
00401AEF MOV DWORD PTR SS:[EBP-74],EBX // 8002
00401AF2 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarTstEq>]// a = 5 ?
00401AF8 TEST AX,AX
00401AFB MOV ECX,80020004
00401B00 MOV EAX,0A
00401B05 MOV DWORD PTR SS:[EBP-5C],ECX
00401B08 MOV DWORD PTR SS:[EBP-64],EAX
00401B0B MOV DWORD PTR SS:[EBP-4C],ECX
00401B0E MOV DWORD PTR SS:[EBP-54],EAX
00401B11 MOV DWORD PTR SS:[EBP-3C],ECX
00401B14 MOV DWORD PTR SS:[EBP-44],EAX
00401B17 JE SHORT 工程2.00401B5C //不相等则跳走

00401B19 LEA EDX,DWORD PTR SS:[EBP-74]
00401B1C LEA ECX,DWORD PTR SS:[EBP-34]
00401B1F MOV DWORD PTR SS:[EBP-6C],工程2.004016D4; UNICODE "a = 5"
00401B26 MOV DWORD PTR SS:[EBP-74],8
00401B2D CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarDup>]
00401B33 LEA EAX,DWORD PTR SS:[EBP-64]
00401B36 LEA ECX,DWORD PTR SS:[EBP-54]
00401B39 PUSH EAX
00401B3A LEA EDX,DWORD PTR SS:[EBP-44]
00401B3D PUSH ECX
00401B3E PUSH EDX
00401B3F LEA EAX,DWORD PTR SS:[EBP-34]
00401B42 PUSH ESI
00401B43 PUSH EAX
00401B44 CALL DWORD PTR DS:[<&MSVBVM60.#595>]; MSVBVM60.rtcMsgBox
00401B4A LEA ECX,DWORD PTR SS:[EBP-64]
00401B4D LEA EDX,DWORD PTR SS:[EBP-54]
00401B50 PUSH ECX
00401B51 LEA EAX,DWORD PTR SS:[EBP-44]
00401B54 PUSH EDX
00401B55 LEA ECX,DWORD PTR SS:[EBP-34]
00401B58 PUSH EAX
00401B59 PUSH ECX
00401B5A JMP SHORT 工程2.00401B9D
// 其他条件满足则执行这里
00401B5C MOV DWORD PTR SS:[EBP-6C],工程2.004016E4; UNICODE "a > 5"
00401B63 LEA EDX,DWORD PTR SS:[EBP-74]
00401B66 LEA ECX,DWORD PTR SS:[EBP-34]
00401B69 MOV DWORD PTR SS:[EBP-74],8
00401B70 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarDup>]
00401B76 LEA EDX,DWORD PTR SS:[EBP-64]
00401B79 LEA EAX,DWORD PTR SS:[EBP-54]
00401B7C PUSH EDX
00401B7D LEA ECX,DWORD PTR SS:[EBP-44]
00401B80 PUSH EAX
00401B81 PUSH ECX
00401B82 LEA EDX,DWORD PTR SS:[EBP-34]
00401B85 PUSH ESI
00401B86 PUSH EDX
00401B87 CALL DWORD PTR DS:[<&MSVBVM60.#595>]; MSVBVM60.rtcMsgBox

流程大概如此。上面出现了一些VB内部函数,如果你不太熟悉那些函数的意义,可以
到DFCG上下载一份我整理的vb内部函数。
===========================================================
2)select case 语句

select case 语句的语法如下:

Select Case 测试表达式
Case 表达式列表1
语句块1
Case 表达式列表2
语句块2
......
Case Else
语句块n
End Select
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
代码:
Dim a, b
a = 5 
Select Case a
Case 3
b = "3"
Case 5
b = "5"
Case Else
b = "0"
End Select
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
反汇编代码(速度优化编译)
00401A2F XOR ESI,ESI // 用来初始化变量
00401A31 LEA EDX,DWORD PTR SS:[EBP-44]
00401A34 MOV DWORD PTR SS:[EBP-44],ESI
00401A37 LEA ECX,DWORD PTR SS:[EBP-24]
00401A3A MOV DWORD PTR SS:[EBP-24],ESI
00401A3D MOV DWORD PTR SS:[EBP-34],ESI
00401A40 MOV DWORD PTR SS:[EBP-54],ESI
00401A43 MOV DWORD PTR SS:[EBP-3C],5 // 5
00401A4A MOV DWORD PTR SS:[EBP-44],2 // 类型
00401A51 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]
// a = 5 //[ebp-24]

00401A57 MOV EBX,DWORD PTR DS:[<&MSVBVM60.__vbaVarCopy>]
00401A5D LEA EDX,DWORD PTR SS:[EBP-24]
00401A60 LEA ECX,DWORD PTR SS:[EBP-54]
00401A63 CALL EBX // 生成一个临时变量 //[ebp-54]
// Select Case a


00401A65 MOV EDI,DWORD PTR DS:[<&MSVBVM60.__vbaVarTstEq>
00401A6B LEA EAX,DWORD PTR SS:][EBP-54]
00401A6E LEA ECX,DWORD PTR SS:[EBP-44]
00401A71 PUSH EAX
00401A72 PUSH ECX
00401A73 MOV DWORD PTR SS:[EBP-3C],3 // 3
00401A7A MOV DWORD PTR SS:[EBP-44],8002
00401A81 CALL EDI 
00401A83 TEST AX,AX
00401A86 JE SHORT 工程2.00401A91 // 不等于3则跳
// Case 3
00401A88 MOV DWORD PTR SS:[EBP-3C],工程2.004016B4 // '3'
00401A8F JMP SHORT 工程2.00401ABC

00401A91 LEA EDX,DWORD PTR SS:[EBP-54]
00401A94 LEA EAX,DWORD PTR SS:[EBP-44]
00401A97 PUSH EDX
00401A98 PUSH EAX
00401A99 MOV DWORD PTR SS:[EBP-3C],5 // 5
00401AA0 MOV DWORD PTR SS:[EBP-44],8002
00401AA7 CALL EDI
00401AA9 TEST AX,AX
00401AAC MOV DWORD PTR SS:[EBP-3C],工程2.004016BC // '5'
00401AB3 JNZ SHORT 工程2.00401ABC // 不等于5则跳
// Case 5

00401AB5 MOV DWORD PTR SS:[EBP-3C],工程2.004016C4 // '0'
00401ABC LEA EDX,DWORD PTR SS:[EBP-44]
00401ABF LEA ECX,DWORD PTR SS:[EBP-34]
00401AC2 MOV DWORD PTR SS:[EBP-44],8 // String类型
00401AC9 CALL EBX // 为变量 b 赋值
// Case Else
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
当然这段代码在逆向时也可以用if语句来表达。逆向出来的不如select case
语句那样直观。在我看来用if语句表达应该是这样的:
dim a,b
if a = 3 then
b = '3'
else if a = 5 then
b = '5'
else
b = '0'
end if
=========================================================== 
3)while语句

while语句的典型语法是:

While 条件
语句块
Wend
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
代码:
Dim a, b
a = 3
b = 0
While a > 0
b = b + a
a = a - 1
Wend
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
反汇编代码(速度优化编译)
00401A1F MOV ESI,DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]
00401A25 XOR EDI,EDI // 初始化变量 
00401A27 MOV EBX,2
00401A2C MOV DWORD PTR SS:[EBP-54],EDI
00401A2F LEA EDX,DWORD PTR SS:[EBP-54]
00401A32 LEA ECX,DWORD PTR SS:[EBP-24]
00401A35 MOV DWORD PTR SS:[EBP-24],EDI
00401A38 MOV DWORD PTR SS:[EBP-34],EDI
00401A3B MOV DWORD PTR SS:[EBP-44],EDI
00401A3E MOV DWORD PTR SS:[EBP-4C],3 // 3
00401A45 MOV DWORD PTR SS:[EBP-54],EBX // integer类型
00401A48 CALL ESI 
// a = 3 //[ebp-24]

00401A4A LEA EDX,DWORD PTR SS:[EBP-54]
00401A4D LEA ECX,DWORD PTR SS:[EBP-34]
00401A50 MOV DWORD PTR SS:[EBP-4C],EDI // 0
00401A53 MOV DWORD PTR SS:[EBP-54],EBX // integer类型
00401A56 CALL ESI
// b = 0 //[ebp-34]

00401A58 MOV EDI,DWORD PTR DS:[<&MSVBVM60.__vbaVarAdd>] 
00401A5E MOV EBX,DWORD PTR DS:[<&MSVBVM60.__vbaVarSub>]

00401A64 LEA EAX,DWORD PTR SS:[EBP-24]
00401A67 LEA ECX,DWORD PTR SS:[EBP-54] // 0
00401A6A PUSH EAX
00401A6B PUSH ECX
00401A6C MOV DWORD PTR SS:[EBP-4C],0
00401A73 MOV DWORD PTR SS:[EBP-54],8002
00401A7A CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarTstGt>] 
00401A80 TEST AX,AX
00401A83 JE SHORT 工程2.00401ABF // a 不大于0则退出循环
// while a > 0

00401A85 LEA EDX,DWORD PTR SS:[EBP-34] 
00401A88 LEA EAX,DWORD PTR SS:[EBP-24]
00401A8B PUSH EDX // b
00401A8C LEA ECX,DWORD PTR SS:[EBP-44] 
00401A8F PUSH EAX // a
00401A90 PUSH ECX
00401A91 CALL EDI 
00401A93 MOV EDX,EAX // b + a
00401A95 LEA ECX,DWORD PTR SS:[EBP-34] // b 
00401A98 CALL ESI 
// b = b + a

00401A9A LEA EDX,DWORD PTR SS:[EBP-24] // a
00401A9D LEA EAX,DWORD PTR SS:[EBP-54]
00401AA0 PUSH EDX
00401AA1 LEA ECX,DWORD PTR SS:[EBP-44]
00401AA4 PUSH EAX
00401AA5 PUSH ECX
00401AA6 MOV DWORD PTR SS:[EBP-4C],1 // 1
00401AAD MOV DWORD PTR SS:[EBP-54],2 // integer类型
00401AB4 CALL EBX
00401AB6 MOV EDX,EAX // a - 1
00401AB8 LEA ECX,DWORD PTR SS:[EBP-24]
00401ABB CALL ESI
// a = a - 1

00401ABD JMP SHORT 工程2.00401A64 //注意:这里往回跳
// Wend
=========================================================== 
4)do语句

这个语句的格式比较多,典型的格式如下:

Do 
语句块
Loop Until 循环条件
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
Dim a, b
a = 3
b = 0
Do
b = a + b
a = a - 1
Loop Until a <= 0 
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
反汇编代码(速度优化)
00401A1F MOV ESI,DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>]
00401A25 XOR EDI,EDI
00401A27 MOV EBX,2
00401A2C MOV DWORD PTR SS:[EBP-54],EDI
00401A2F LEA EDX,DWORD PTR SS:[EBP-54]
00401A32 LEA ECX,DWORD PTR SS:[EBP-24]
00401A35 MOV DWORD PTR SS:[EBP-24],EDI
00401A38 MOV DWORD PTR SS:[EBP-34],EDI
00401A3B MOV DWORD PTR SS:[EBP-44],EDI
00401A3E MOV DWORD PTR SS:[EBP-4C],3 //3
00401A45 MOV DWORD PTR SS:[EBP-54],EBX //integer
00401A48 CALL ESI 
// a = 3 //[ebp-24]

00401A4A LEA EDX,DWORD PTR SS:[EBP-54]
00401A4D LEA ECX,DWORD PTR SS:[EBP-34]
00401A50 MOV DWORD PTR SS:[EBP-4C],EDI //0
00401A53 MOV DWORD PTR SS:[EBP-54],EBX //integer
00401A56 CALL ESI
// b = 0 //[ebp-34]

00401A58 MOV EBX,DWORD PTR DS:[<&MSVBVM60.__vbaVarAdd>] 
00401A5E LEA EAX,DWORD PTR SS:[EBP-24] // a
00401A61 LEA ECX,DWORD PTR SS:[EBP-34] // b
00401A64 PUSH EAX
00401A65 LEA EDX,DWORD PTR SS:[EBP-44]
00401A68 PUSH ECX
00401A69 PUSH EDX
00401A6A CALL EBX
00401A6C MOV EDX,EAX
00401A6E LEA ECX,DWORD PTR SS:[EBP-34]
00401A71 CALL ESI
// b = a + b

00401A73 LEA EAX,DWORD PTR SS:[EBP-24] // a
00401A76 LEA ECX,DWORD PTR SS:[EBP-54] 
00401A79 PUSH EAX
00401A7A LEA EDX,DWORD PTR SS:[EBP-44]
00401A7D PUSH ECX
00401A7E PUSH EDX
00401A7F MOV DWORD PTR SS:[EBP-4C],1 // 1
00401A86 MOV DWORD PTR SS:[EBP-54],2 // integer
00401A8D CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarSub>] 
00401A93 MOV EDX,EAX
00401A95 LEA ECX,DWORD PTR SS:[EBP-24] // a
00401A98 CALL ESI
// a = a - 1
00401A9A LEA EAX,DWORD PTR SS:[EBP-24]
00401A9D LEA ECX,DWORD PTR SS:[EBP-54]
00401AA0 PUSH EAX
00401AA1 PUSH ECX
00401AA2 MOV DWORD PTR SS:[EBP-4C],EDI // 0
00401AA5 MOV DWORD PTR SS:[EBP-54],8002
00401AAC CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarTstLe>] 
00401AB2 TEST AX,AX
00401AB5 JE SHORT 工程2.00401A5E
loop until a <= 0 
===========================================================
5)for语句

for语句的典型语法如下:

for 循环变量 = 初值 to 终值 [step 步长]
循环体
next 循环变量
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
代码:
a = 0
For i = 0 To 100 Step 2
a = a + i
Next i
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
反汇编代码(速度优化)
00401A42 MOV EBX,DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>] 
00401A48 XOR ESI,ESI
00401A4A MOV EDI,2
00401A4F MOV DWORD PTR SS:[EBP-54],ESI
00401A52 LEA EDX,DWORD PTR SS:[EBP-54]
00401A55 LEA ECX,DWORD PTR SS:[EBP-34]
00401A58 MOV DWORD PTR SS:[EBP-24],ESI
00401A5B MOV DWORD PTR SS:[EBP-34],ESI
00401A5E MOV DWORD PTR SS:[EBP-44],ESI
00401A61 MOV DWORD PTR SS:[EBP-64],ESI
00401A64 MOV DWORD PTR SS:[EBP-74],ESI
00401A67 MOV DWORD PTR SS:[EBP-84],ESI
00401A6D MOV DWORD PTR SS:[EBP-94],ESI
00401A73 MOV DWORD PTR SS:[EBP-4C],ESI //0
00401A76 MOV DWORD PTR SS:[EBP-54],EDI //integer
00401A79 CALL EBX 
// a = 0 //[ebp-34]

00401A7B LEA EAX,DWORD PTR SS:[EBP-54]
00401A7E LEA ECX,DWORD PTR SS:[EBP-64] 
00401A81 PUSH EAX // 增量
00401A82 LEA EDX,DWORD PTR SS:[EBP-74]
00401A85 PUSH ECX // 终值
00401A86 LEA EAX,DWORD PTR SS:[EBP-94]
00401A8C PUSH EDX // 初值
00401A8D LEA ECX,DWORD PTR SS:[EBP-84]
00401A93 PUSH EAX //临时终值
00401A94 LEA EDX,DWORD PTR SS:[EBP-24]
00401A97 PUSH ECX //临时增量
00401A98 PUSH EDX // 循环变量
00401A99 MOV DWORD PTR SS:[EBP-4C],EDI // 2
00401A9C MOV DWORD PTR SS:[EBP-54],EDI // integer
00401A9F MOV DWORD PTR SS:[EBP-5C],64 // 100
00401AA6 MOV DWORD PTR SS:[EBP-64],EDI // integer
00401AA9 MOV DWORD PTR SS:[EBP-6C],ESI // 0
00401AAC MOV DWORD PTR SS:[EBP-74],EDI // integer
00401AAF CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarForInit>] 
//For i = 0 To 100 Step 2

00401AB5 MOV EDI,DWORD PTR DS:[<&MSVBVM60.__vbaVarAdd>] 
00401ABB CMP EAX,ESI
00401ABD JE SHORT 工程2.00401AEE

00401ABF LEA EAX,DWORD PTR SS:[EBP-34] //a
00401AC2 LEA ECX,DWORD PTR SS:[EBP-24] //i
00401AC5 PUSH EAX
00401AC6 LEA EDX,DWORD PTR SS:[EBP-44]
00401AC9 PUSH ECX
00401ACA PUSH EDX
00401ACB CALL EDI
00401ACD MOV EDX,EAX
00401ACF LEA ECX,DWORD PTR SS:[EBP-34]
00401AD2 CALL EBX
// a = a + i

00401AD4 LEA EAX,DWORD PTR SS:[EBP-94] //临时终值
00401ADA LEA ECX,DWORD PTR SS:[EBP-84] //临时增量
00401AE0 PUSH EAX
00401AE1 LEA EDX,DWORD PTR SS:[EBP-24] // 循环变量
00401AE4 PUSH ECX
00401AE5 PUSH EDX
00401AE6 CALL DWORD PTR DS:[<&MSVBVM60.__vbaVarForNext>] 
00401AEC JMP SHORT 工程2.00401ABB
// next i
===========================================================
上面出现了我定义的两个名词:临时终值和临时增量,这两个值什么意思呢?
也就是当__vbaVarForInit函数执行完后这两个值将分别被赋予终值和增量的值。
从上面可以看出,__vbaVarForInit只是执行一次,以后再执行就是__vbaVarForNext
了。因此程序必须知道循环变量到那里结束,每次步长多少。这两个值就是保存这些
信息的。
当满足循环条件时,这两个函数都返回1,不满足时返回0。

===========================================================
到现在为止分析基本的程序结构应该没问题了。在这里把前面没完成的工作
补一下:看看 Array函数和 For Each ... Next 语句。

代码:
Dim a
a = Array(5, 6, 7)
For Each x In a
Print x
Next x

编译后的汇编代码:
00401AC3 XOR ESI,ESI
00401AC5 LEA EDX,DWORD PTR SS:[EBP-48]
00401AC8 PUSH ESI
00401AC9 PUSH 2
00401ACB PUSH 1
00401ACD PUSH ESI
00401ACE PUSH EDX
00401ACF PUSH 10
00401AD1 PUSH 880
00401AD6 MOV DWORD PTR SS:[EBP-24],ESI
00401AD9 MOV DWORD PTR SS:[EBP-34],ESI
00401ADC MOV DWORD PTR SS:[EBP-44],ESI
00401ADF MOV DWORD PTR SS:[EBP-48],ESI
00401AE2 MOV DWORD PTR SS:[EBP-58],ESI
00401AE5 MOV DWORD PTR SS:[EBP-68],ESI
00401AE8 MOV DWORD PTR SS:[EBP-78],ESI
00401AEB MOV DWORD PTR SS:[EBP-7C],ESI
00401AEE MOV DWORD PTR SS:[EBP-80],ESI
00401AF1 MOV DWORD PTR SS:[EBP-84],ESI
00401AF7 MOV DWORD PTR SS:[EBP-88],ESI
00401AFD CALL DWORD PTR DS:[<&MSVBVM60.__vbaRedim>] //定义一个变体类型的动态数组

4. VB内部函数
1) 自定义函数的调用

这里我们看看和VB的内部函数有关的一些内容。
老规矩,先看一段代码:
Function myadd(ByVal a As Variant, b As Variant)
myadd = a + b
End Function

Sub myprint(ByVal a As Variant)
Print a
End Sub

Private Sub Command1_Click()
Dim a, b, c

a = 10
b = 20
c = myadd(a, b)
myprint c
End Sub

这段代码里包含了自定义的过程,函数及函数的两种参数传递方式。下面的反汇编代码
是过程Command1_Click()的。自定义的函数和过程的反汇编代码和这相仿,可以字节反汇
编对比看一下。
反汇编代码如下,默认方式(速度优化)编译的,这次给出的是完整的汇编代码:

00401C50 PUSH EBP
00401C51 MOV EBP,ESP
00401C53 SUB ESP,0C

00401C56 PUSH <JMP.&MSVBVM60.__vbaExceptHandler> 
00401C5B MOV EAX,DWORD PTR FS:[0]
00401C61 PUSH EAX
00401C62 MOV DWORD PTR FS:[0],ESP //安装局部线程异常

00401C69 SUB ESP,5C //下面这一段和vb编译器有关
00401C6C PUSH EBX //因为vb是基于com技术实现的
00401C6D PUSH ESI //更详细的内容可以参考
00401C6E PUSH EDI //<<软件加密技术内幕>>一书
00401C6F MOV DWORD PTR SS:[EBP-C],ESP
00401C72 MOV DWORD PTR SS:[EBP-8],工程2.004010B0
00401C79 MOV ESI,DWORD PTR SS:[EBP+8]
00401C7C MOV EAX,ESI
00401C7E AND EAX,1
00401C81 MOV DWORD PTR SS:[EBP-4],EAX
00401C84 AND ESI,FFFFFFFE
00401C87 PUSH ESI
00401C88 MOV DWORD PTR SS:[EBP+8],ESI //me
00401C8B MOV ECX,DWORD PTR DS:[ESI]
00401C8D CALL DWORD PTR DS:[ECX+4] ;MSVBVM60.Zombie_AddRef

00401C90 MOV EDI,DWORD PTR DS:[<&MSVBVM60.__vbaVarMove>] 
00401C96 XOR EBX,EBX
00401C98 MOV DWORD PTR SS:[EBP-64],EBX
00401C9B LEA EDX,DWORD PTR SS:[EBP-64]
00401C9E LEA ECX,DWORD PTR SS:[EBP-24]
00401CA1 MOV DWORD PTR SS:[EBP-24],EBX
00401CA4 MOV DWORD PTR SS:[EBP-34],EBX
00401CA7 MOV DWORD PTR SS:[EBP-44],EBX
00401CAA MOV DWORD PTR SS:[EBP-54],EBX
00401CAD MOV DWORD PTR SS:[EBP-5C],0A //10
00401CB4 MOV DWORD PTR SS:[EBP-64],2 //integer
00401CBB CALL EDI 
//a = 10 
00401CBD LEA EDX,DWORD PTR SS:[EBP-64]
00401CC0 LEA ECX,DWORD PTR SS:[EBP-34]
00401CC3 MOV DWORD PTR SS:[EBP-5C],14 //20
00401CCA MOV DWORD PTR SS:[EBP-64],2 //integer
00401CD1 CALL EDI
// b = 20
00401CD3 LEA EAX,DWORD PTR SS:[EBP-54]
00401CD6 LEA ECX,DWORD PTR SS:[EBP-34]
00401CD9 PUSH EAX //存放函数的返回值
00401CDA PUSH ECX //引用参数b
00401CDB MOV ECX,DWORD PTR SS:[EBP-24]
00401CDE SUB ESP,10 //这个空间复制变量参数a
00401CE1 MOV EAX,ESP //变体类型,所以要16个字节
00401CE3 MOV EDX,DWORD PTR DS:[ESI]
00401CE5 PUSH ESI //me
00401CE6 MOV DWORD PTR DS:[EAX],ECX
00401CE8 MOV ECX,DWORD PTR SS:[EBP-20]
00401CEB MOV DWORD PTR DS:[EAX+4],ECX
00401CEE MOV ECX,DWORD PTR SS:[EBP-1C]
00401CF1 MOV DWORD PTR DS:[EAX+8],ECX
00401CF4 MOV ECX,DWORD PTR SS:[EBP-18]
00401CF7 MOV DWORD PTR DS:[EAX+C],ECX
00401CFA CALL DWORD PTR DS:[EDX+6F8] //调用函数 myadd
00401D00 CMP EAX,EBX
00401D02 JGE SHORT 工程2.00401D16
00401D04 PUSH 6F8
00401D09 PUSH 工程2.00401644
00401D0E PUSH ESI
00401D0F PUSH EAX
00401D10 CALL DWORD PTR DS:[<&MSVBVM60.__vbaHresultCheckObj>] 
00401D16 LEA EDX,DWORD PTR SS:[EBP-54] 
00401D19 LEA ECX,DWORD PTR SS:[EBP-44] 
00401D1C CALL EDI 
//把结果赋值给变量c

00401D1E MOV ECX,DWORD PTR SS:[EBP-44] //c作为变量参数传递
00401D21 SUB ESP,10 //所以这里要分配16个字节
00401D24 MOV EAX,ESP
00401D26 MOV EDX,DWORD PTR DS:[ESI]
00401D28 PUSH ESI //me
00401D29 MOV DWORD PTR DS:[EAX],ECX
00401D2B MOV ECX,DWORD PTR SS:[EBP-40]
00401D2E MOV DWORD PTR DS:[EAX+4],ECX
00401D31 MOV ECX,DWORD PTR SS:[EBP-3C]
00401D34 MOV DWORD PTR DS:[EAX+8],ECX
00401D37 MOV ECX,DWORD PTR SS:[EBP-38]
00401D3A MOV DWORD PTR DS:[EAX+C],ECX
00401D3D CALL DWORD PTR DS:[EDX+6FC] //调用myprint
00401D43 CMP EAX,EBX
00401D45 JGE SHORT 工程2.00401D59
00401D47 PUSH 6FC
00401D4C PUSH 工程2.00401644
00401D51 PUSH ESI
00401D52 PUSH EAX
00401D53 CALL DWORD PTR DS:[<&MSVBVM60.__vbaHresultCheckObj>]


00401D59 MOV DWORD PTR SS:[EBP-4],EBX
00401D5C PUSH 工程2.00401D83 //这里压入返回地址
00401D61 JMP SHORT 工程2.00401D6D
00401D63 LEA ECX,DWORD PTR SS:[EBP-54]
00401D66 CALL DWORD PTR DS:[<&MSVBVM60.__vbaFreeVar>] 
00401D6C RETN

00401D6D MOV ESI,DWORD PTR DS:[<&MSVBVM60.__vbaFreeVar>] 
00401D73 LEA ECX,DWORD PTR SS:[EBP-24]
00401D76 CALL ESI 
00401D78 LEA ECX,DWORD PTR SS:[EBP-34]
00401D7B CALL ESI
00401D7D LEA ECX,DWORD PTR SS:[EBP-44]
00401D80 CALL ESI
00401D82 RETN //上面这里释放变量a,b,c

00401D83 MOV EAX,DWORD PTR SS:[EBP+8] //返回到这里做善后处理
00401D86 PUSH EAX
00401D87 MOV EDX,DWORD PTR DS:[EAX]
00401D89 CALL DWORD PTR DS:[EDX+8] ; MSVBVM60.Zombie_Release
00401D8C MOV EAX,DWORD PTR SS:[EBP-4]
00401D8F MOV ECX,DWORD PTR SS:[EBP-14]
00401D92 POP EDI
00401D93 POP ESI
00401D94 MOV DWORD PTR FS:[0],ECX //恢复局部线程异常
00401D9B POP EBX
00401D9C MOV ESP,EBP
00401D9E POP EBP
00401D9F RETN 4

从这里可以看出,在调用自程序时还要传递一个me参数。对于函数来说,还有一个
返回结果要传递过去。

2) VB的内部函数
VB的内部函数在反汇编代码中看起来和我们熟悉的函数名并不一样。这一点跟踪过
VB程序的人一定深有体会。大多数函数名都可以从名字上猜出来。但也有相差太多的。
我整理了一份函数列表。不是全部,但包含了大多数内部函数,应该能应付一般的应用。
函数列表在这个贴子的附件中。
VB的运算符大多是用函数实现的。这是一个好消息。这意味着我们不必费力去分析
过多的代码而只要能辨别出那些函数名即可。
VB的内部函数并不都是以Stdcall的方式传递参数,尽管大部分是这样的。分析
VB程序时要注意这点。
VB的反汇编代码中大部分的函数都要传递一个存放返回值的变量,而且返回值也会
在EAX中或者浮点栈中返回。
这里只举一个例子。其他的可以参考我整理的列表。

这是函数instr,常用的一个:

__vbaInStrVar ;函数 InStr(起始位置,源字符串,目标字符串,比较方式)

LEA EDX,DWORD PTR SS:[EBP-24] 
PUSH 1 ;起始位置,从1开始 
LEA EAX,DWORD PTR SS:[EBP-34] 
PUSH EDX ;被搜索的字符串 
PUSH EAX ;要搜的字符串 
LEA ECX,DWORD PTR SS:[EBP-54] 
PUSH 1 ;比较方式 
PUSH ECX ;返回的结果 
CALL DWORD PTR DS:[<&MSVBVM60.__vbaInStrVar>]
MOV EDX,EAX ;结果同时在eax中返回


3) VB的外部函数调用
VB对外部函数的调用是如何实现的呢?先看看下面的代码:
Private Declare Function MessageBeep Lib "user32" (ByVal wType As Long) As Long
Private Sub Command1_Click()
MessageBeep 0
End Sub
对应的反汇编代码如下:

00401A2F PUSH 0 //这里压入参数
00401A31 CALL 工程2.004016C8 //这个Call我们要继续跟进才知道调用的什么函数
00401A36 CALL DWORD PTR DS:[<&MSVBVM60.__vbaSetSystemError>]


004016C8 MOV EAX,DWORD PTR DS:[4022DC] //第一次调用时为0,以后就调用这里
004016CD OR EAX,EAX //这个程序里为0
004016CF JE SHORT 工程2.004016D3
004016D1 JMP EAX
004016D3 PUSH 工程2.004016B0 //注意这个地址,这是指向代码段的
//我们先看看这里有什么
004016B0 98 16 40 00 A4 16 40 00 ?@.?@.
//再跟进
00401698 75 73 65 72 33 32 00 00 user32..
004016A0 0C 00 00 00 4D 65 73 73 ....Mess
004016A8 61 67 65 42 65 65 70 00 ageBeep.
//是不是看到了要调用的函数了^_^
//其实不用这么麻烦
004016D8 MOV EAX,<JMP.&MSVBVM60.DllFunctionCall>
004016DD CALL EAX //执行完这一行看eax,看到什么了
//EAX 84936A78 Thunk to USER32.MessageBeep
004016DF JMP EAX //这里就是真正的调用了

注意:调用的外部函数名不在程序的导入表里,而是在代码段里。程序是调用
函数MSVBVM60.DllFunctionCall来取得外部函数的地址的。

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的实现,看看流行的编译器技术等等。

我设计VB6的三存架构模式:一、DataAccess层 VB6的三层架构的相关资料在网络上只有很少的资料,流传开来的我知道的只有两种模式:1.集合模式:该模式在广为流传,但是效率很差且并也没有DataAccess层,BusinessRule和DataAccess混在一起.2.Type数组模式:效较较集合有所提升,但是灵活性较差,字段没有Null状态,且由于Type数组是值类型,实际调用时有可能放于栈空间,如果Type数组过大可能溢出.经过分 阅读详情

相关推荐

逆向工程中的艺术:从PEiD查壳到VB程序脱壳的实战解析

本文深入解析逆向工程中VB程序脱壳技术,重点介绍PEiD查壳工具的高级应用和UPX脱壳实战流程。通过详细的操作步骤和案例分析,帮助安全研究人员掌握VB程序脱壳的核心技术,包括内存转储、IAT修复等关键环节,提升逆向工程效率。

weixin_29280219的博客 432

VB6反编译详解(一)-软件逆向-看雪

/没有用的填充东西。//没有用的填充东西。//没有用的填充东西。//没有用的填充东西。//没有用的填充东西。//没有用的填充东西。//OBEJCT数量1?//执行工程名字的字符串。//没有用的填充东西。

3923

VB RezQ V3.1:价值1200元的VB6反编译软件深度解析

VB RezQ V3.1是一款专为VB6开发者和维护人员设计的反编译工具。它能够读取VB6编译后的可执行文件(.exe)和动态链接库文件(.dll),将它们还原为接近源代码的格式,包括窗体、类模块和标准模块等。这对于理解遗留VB6程序的工作机制、进行代码的迁移或升级具有重大意义。反编译(Decompilation)是将编译后的二进制代码转换回接近源代码的过程。

weixin_36019375的博客 1811

【免费下载】 VB6.0反编译工具:解锁旧时代代码的秘密

VB6.0反编译工具:解锁旧时代代码的秘密 【下载地址】VB6.0反编译工具资源下载 VB6.0反编译工具资源下载 项目地址: https://gitcode.com/open-source-toolkit/7a039 ...

gitblog_09768的博客 1577

用VB6实现ionCube Decoder:源码还原与逆向工程实战

源码加密是保护PHP代码安全的重要手段,而逆向工程则是理解和恢复被保护代码的核心技术路径。ionCube作为PHP生态中最常见的加密方案,通过将脚本编译为字节码并绑定许可证实现防护,其文件结构和解码原理却并非无迹可寻。从文件头识别、payload偏移定位到密钥流生成,解码器本质上是分析加密格式与还原算法参数的过程。这一技术不仅适用于旧版ionCube文件的源码恢复,也为遗留系统维护、安全审计和代码可移植性分析提供了关键支撑。对于缺乏现代工具链的开发者,VB6凭借轻量级GUI和二进制读写能力,依然能搭建出实用

weixin_33552698的博客 293

从VB6古董画图软件到现代逆向工程:一次完整的数字考古实践

软件逆向工程是理解程序内部工作原理、分析遗留系统或进行安全评估的关键技术。其核心原理是通过静态分析(如查看文件结构、导入表、编译器信息)和动态分析(如监控API调用、内存状态)来反推软件的逻辑与数据流。这项技术的价值在于能帮助开发者安全地分析未知软件、迁移老旧系统、学习编程思想或进行漏洞研究。典型的应用场景包括分析无源码的遗留工具、理解恶意软件行为、兼容性调试以及软件考古。本文以分析一个用VB6编写的简易画图程序为例,详细展示了如何通过查壳工具、API监视器等手段,结合虚拟机隔离环境,安全地完成一次从静态探

weixin_34354173的博客 312

VBexe反编译源码下载:深入探索VB程序逆向工程的艺术

VBexe反编译源码下载:深入探索VB程序逆向工程的艺术 去发现同类优质开源项目:https://gitcode.com/ 在当今软件开发领域,逆向工程成为了一项重要的技术手段。它不仅可以帮助我们理解程序的运行机制,还能在合法范围内,对软件进行深入分析和恢复。今天,我将向您推荐一款实用的开源项目——VBexe反编译源码下载,帮助您轻松实现对VB编译后exe文件的逆向工程。 项目介绍 VBexe反编...

gitblog_06722的博客 966

VB反编译工具:源代码与逆向工程

反编译技术是一种将编译后的程序代码(通常是二进制形式)转换回高级语言代码的过程。这一技术在软件工程、安全分析以及学习对手产品的设计和功能方面发挥着重要作用。Visual Basic(VB)作为一种经典的编程语言,它的应用程序在使用反编译技术后,可以被还原成可读的源代码,进而允许开发者理解程序逻辑,修改或优化现有软件。反编译工具的核心之一是对编译后的二进制文件的指令集进行解码。在这一过程中,工具将基于PE文件格式中定义的操作码(Opcode)进行解析。

weixin_36204513的博客 2068

【免费下载】 VB Decompiler Pro v7.7:解锁VB程序的秘密武器

VB Decompiler Pro v7.7:解锁VB程序的秘密武器 【下载地址】VBDecompilerProv7.7带注册码 本仓库提供VB Decompiler Pro v7.7版本的资源文件下载,该版本附带注册码,方便用户快速使用。VB Decompiler Pro是一款功能强大的VB反编译工具,能够帮助开发者轻...

gitblog_09793的博客 1340

VB6.0反编译工具

VB6.0反编译工具 OCX.EXE.DLL都可以反编译!

手把手教你搞定JBI投稿:从Statement of Significance到Declaration Statement的保姆级避坑指南

本文提供了一份详细的JBI投稿指南,重点解析Statement of Significance和Declaration of Interests的撰写技巧,帮助研究者避开常见格式陷阱。通过实战案例和检查清单,确保投稿符合JBI的学术严谨性和临床转化价值要求,提升稿件通过率。

weixin_29278805的博客 617

逆向VB6程序全过程

本文记录了逆向一个VB6未加壳程序的全过程,通过VB Decompiler 等工具实现获取静态未加密序列号。

dd_jzt的博客 805

SPARTAN6 + Verilog - FPGA step by step 从0开始学习(1)

SPARTAN6 + Verilog - FPGA step by step 从0开始学习(1)Step 1 软件安装Step 2 硬件获取Step 3 开始从头到脚建一个工程Step 3.1 新建一个工程 从0开始学习FPGA,最好的办法就是先建一个最简单的模块,并且跑起来,然后再慢慢展开。下面这个例子是要按照一定的周期点亮核心板上的一个led。 Step 1 软件安装 这个从0开始学习是用的xilinx的SPARTAN6。SPARTAN6集成开发环境用ISE,不能用Vivado,各自对应的版本不同。安装

xfacexx点点记录 5508

VB6反编译软件 VB RezQ V2.4a 正式版下载介绍

VB6反编译软件 VB RezQ V2.4a 正式版介绍 去发现同类优质开源项目:https://gitcode.com/ 这里是VB6反编译软件 VB RezQ V2.4a 正式版的资源介绍页。该软件是一款强大的VB6源代码还原工具,可以帮助开发者恢复和修改丢失或损坏的VB6项目源代码。 此版本为正式版,价值1200元,包含注册许可文件。软件经过严格测试,确保功能的完整性和稳定性,让您能够高效地...

gitblog_06719的博客 466

公文流转系统

公文录入区 | QLineEdit(文号/标题)、QComboBox(公文类型/紧急程度)、QTextEdit(正文)、QListWidget(附件列表)、QPushButton(上传附件/保存草稿/提交审批) |// 按时间范围获取。QStringList userNames = {"张三", "李四", "王五", "赵六", "钱七", "孙八", "周九", "吴十", "郑十一", "王十二"};

寒寒豆豆软件公司的博客 549

UE5 推荐的资产命名规范

在开发阶段中,随着 虚幻引擎(UE)(Unreal Engine (UE)) 项目日益复杂,内容浏览器(Content Browser) 中的 资产(Assets) 列表会不断扩充。这会导致资产出现各种变体版本,也会导致资产名称因过于相似而造成混淆。比如,你有一个文件夹名为"Soldier",这个文件夹中有蓝图、纹理和模型,它们的名称中都带"Soldier"一词,但在简单列表中,很难区别它们。

一碗清深的博客 3373

浅谈VB6逆向工程

前言 VB的编译有两种方式,一种是P-Code方式,一种是本机代码。P_Code方式是VB 从早期版本保留下来的,也是比较难逆向的一种。而本机代码方式编译的程序已经 和VC很接近了。这里只探讨以本机代码方式编译的程序。由于微软在VB的实现方面 的资料很少,使人觉得VB的逆向比较难。其实掌握一些规律,VB的程序还是很容易 入门的。 这里所提到的知识都是个人的经验,没有什么官方的资料

penjie0418的专栏 1785

把数据库算力拉满的 ABAP CDS Table Function:从语法、权限到可运行样例的全景解析

文章摘要: 本文针对ABAP开发者探讨了CDS Table Function的应用场景与实现细节。当CDS View无法处理复杂计算(如窗口函数、递归等)时,可通过Table Function将逻辑下推到HANA数据库执行。关键点包括:1)CDS实体声明与AMDP实现的协作关系;2)多租户环境下的Client处理机制(@ClientHandling.type注解);3)激活与传输的阶段性特点可能导致的"暂不可用"问题;4)基于SFLIGHT的完整示例,展示如何定义Client依赖函数、实

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 299

VB6.0《第二行代码》3-游戏安全,逆向工程-用VB6.0显示HP内存值

课程名称:《第二行代码》逆向天地玄门 课程简介:用OD和CE进行逆向反汇编分析,最终用 VB6.0来操作分析出来的反汇编数据编写一款自动化的软件,仅供学习研究。 3、《第二行代码》-逆向工程,用VB6.0显示指针HPhttps://www.bilibili.com/video/BV1tL411s7bG/ ...

追逐光芒,追随内心 255

【异常】Claude Code 第三方API 400报错(thinking type should be enabled or disabled)解决方案

摘要: Claude Code接入第三方API端点时出现400参数错误,主要因新版默认启用的Adaptive Thinking功能与旧版接口参数格式不兼容(需thinking: {type: "adaptive"},但第三方仅支持布尔值)。解决方案为修改本地settings.json配置文件,添加"CLAUDE_CODE_DISABLE_ADAPTIVE_THINKING": "1"环境变量并重启客户端,即可恢复思考模式功能。Adaptive Th

奶爸的编程之路,也就一周冷个三天 1万+

C#面试题及详细答案120道(01-10)-- 基础语法与数据类型

C#与.NET部分重点解析了7个核心问题:1)C#与.NET的依存关系;2)值类型与引用类型的内存差异;3)装箱拆箱的性能损耗;4)string/String与int/Int32的实质等价性;5)const与readonly的初始化区别;6)可空类型的应用场景;7)ref与out关键字的参数传递机制。内容包含原理对比、代码示例和优化建议,适合开发者系统掌握C#核心概念。(1

大剑师兰特的GIS世界 1954

【免费下载】 VB6.0反编译工具:深入解析与重构的经典利器

VB6.0反编译工具:深入解析与重构的经典利器 【下载地址】VB6.0反编译工具 本仓库提供了一个强大的VB6.0反编译工具,支持对OCX、EXE、DLL等文件进行反编译。无论你是开发者还是研究人员,这个工具都能帮助你深入分析和理解VB6.0编写的程序 ...

gitblog_09773的博客 745

运行 ui5 serve 命令行报错的处理方法

如果大家运行 ui5 serve 命令行,报如下的错误消息: ui5 不是内部或外部命令,也不是可运行的程序: 只需要执行命令行,全局安装 ui5 cli(command line interface)这个命令行工具即可: npm install --global @ui5/cli 这个 ui5 cli 的入口执行文件,实际安装在了我 Node.js 的安装目录下: 更多Jerry的原创文章,尽在:“汪子熙”: ...

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 1340

VB6.0《第二行代码》2-游戏安全,逆向工程-用CE找HP的内存指针

课程名称:《第二行代码》逆向工程-逆向天地玄门课程简介:用OD和CE进行逆向反汇编分析,最终用 VB6.0来操作分析出来的反汇编数据编写一款自动化的软件,仅供学习研究。 2、《第二行代码》-逆向工程,用CE找HP的内存指针https://www.bilibili.com/video/BV11Q4y1Q7QZ/ ...

追逐光芒,追随内心 202

Statistics and Machine Learning Toolbox

Statistics and Machine Learning Toolbox(带书签),MATLAB统计学习工具

迈瑞BS系列全自动生化分析仪LIS协议接口手册(内含HL7和ASTM)

迈瑞BS系列全自动生化分析仪LIS协议接口手册,内含HL7和ASTM)

VB6.0《第二行代码》4-游戏安全,逆向工程-用CE找多级指针HP的基址和偏移量并且用VB超级模块读取

4、《第二行代码》-逆向工程,用CE找多级指针HP的基址和偏移量并且用VB超级模块读取https://www.bilibili.com/video/BV1Xf4y1F7sD/ 使用超级模块读取多级指针特别方便,写法如下: Label2.Caption = VB超级模块.ReadLong("天地玄门.exe", "天地玄门.exe*602F4C + 132") 或者 Label2.Caption = ReadLong("天地玄门.exe", "天地玄门.exe*6...

追逐光芒,追随内心 1240

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

上一篇: VB快速逆向法(特征码法)
下一篇: 手工把一个PE文件装载起来了
vbsourcecode
博客等级 码龄17年 19粉丝 3原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值