王朝网络
分享
 
 
 

浅谈VB6逆向工程(2) by MengLong@RCT

王朝vb·作者佚名  2006-12-16
宽屏版  字体: |||超大  

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 的值了。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
>>返回首页<<
推荐阅读
 
 
频道精选
 
静静地坐在废墟上,四周的荒凉一望无际,忽然觉得,凄凉也很美
© 2005- 王朝网络 版权所有