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

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来取得外部函数的地址的。

附件:vb函数.rar