Visual Basic内嵌汇编语言解决方案

   VB简单易用,但功能有时候受限制。VC、Delphi都可以直接在程序中写汇编代码,可恼的是,VB不行。我在网上也看过许多有关于VB嵌入汇编的方法,不过有些方法,过于复杂,而且也没相应的介绍。我这里提供一种方法,也许大家以后可能有用!

    基本思路:汇编代码,可以存在一个byte类型的数组中,然后通过某种手段,把系统控制权,转交给这段汇编代码,我们的汇编代码段,就得到了执行。但如何让这段汇编代码,获得系统的控制权限呢?查查WIN API手册,就可以知道有CallWindowProc这个函数。这个函数本是用于调用用户自己定义的窗口过程的,其原形如下:

Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As   Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As Long) As Long

    它有5个参数。lpPrevWnFunc是一个long型,等于用户自己窗口过程的地址,其余3个都是窗口过程所必须的参数,详见MSDN.

    我们只需要关心第一个参数:lpPrevWndFunc,窗口过程地址。如果,我们把自己的汇编代码地址,传进去会怎么样?当然,CallWindowProc就把这个地址,当成窗口过程地址,然后,调用这段汇编代码了。我们的汇编代码便得到执……

    当然,也得装摸做样的吧,将其余4个参数传进去,就传4个0算了,因为这4个参数,我们更本不用,但又是CallWindowProc必须的,不要忘了,我们传进去的lpPrevWndFunc,并非真正的窗口过程地址,而是自己的汇编码地址。

    具体一点,比如,我们要嵌入一段什么也不干的汇编代码:

Dim AsmCode() as byte
redim AsmCode(8)
'生成机器代码
AsmCode(0) = &H58 'POP EAX
AsmCode(1) = &H59 'POP ECX
AsmCode(2) = &H59 'POP ECX
AsmCode(3) = &H59 'POP ECX
AsmCode(4) = &H59 'POP ECX
AsmCode(5) = &H50 'PUSH EAX
'你可以在这里添加你想执行的Asm代码...
'.....如果添加的话,后面的数组偏移需要做相应改动
'你添加的代码在这里结束
'将控制权交还主程序
AsmCode(6) = &HC3 'RET
'.....

    然后:

CallDllFunction = CallWindowProc(VarPtr(AsmCode(0), 0, 0, 0, 0)

    VarPtr函数,用于取变量地址。返回一个long 型值。

    为什么前面要执行几个pop和一个push呢?因为我们是以一段汇编代码首地址,伪装成一个窗口过程的,系统调用CallWindowProc时,实际上除lpPrevWndFunc,我们还传入了4个参数,就是上面的的4个0,而CallWindoProc函数在调用lpPrevWndFunc这段汇编代码程序时,把其余4个参数是压入了堆栈的。相当于执行了以下代码:

xxxx00A4H: push 0
xxxx00A6H: push 0
xxxx00A8H: push 0
xxxx00AAH: push 0
xxxx00ACH: call VarPtr(AsmCode(0))(这段代码我们是看不见的,是CallWindoProc在内部做的处理)
xxxx00AFH: ......

    因为我们根本没有用到这4个参数,所以我们只需要将它弹出。所以,我们执行了4个POP ECX,就是把这4个不用的参数弹出,以保持堆栈指针的正确性。但为什么还要,第一句的:POP EAX,还是因为CallWindowProc把lpPrevWndFunc当成一个窗口过程的原故,因为作为一个正常的窗口过程,在执行Call语句的时候,得把Call语句的下一条指令地址push到堆栈中,用于子程序ret.在上面这段代码就是执行了:push xxxx00afh.事实上,在CallWindowProc中,实际上隐含执行这么几句,我们必须关心的代码:

push 0;参数入栈
push 0
push 0
push 0
push xxxx00afh;(当执行call 时,自动执行)

    为了能让窗口过程执行结束后堆栈指针保持平衡,当然要执行相应的pop指令,第一个pop eax是把子程序返回的地址暂时保存在寄存器eax中,然后弹出4个不用的参数。

    接着把保存在eax中返回地址,压回堆栈。当执行ret时,就能正确返回到CallWindowProc中了。

  Option Explicit
  
'
  'This   shows   how   to   incorporate   machine   code   into   VB
  '''''''''''''''''''''''''''''''''''''''''''''''''''
  'The   example   fills   the   array   with   a   few   machine   instructions   and   then   copies
  'them   to   a   procedure   address.   The   modified   procedure   is   then   called   thru
  'CallWindowProc.   The   result   of   this   specific   machine   code   is   your   CPU   Vendor   Name.
  '
  '##########################################################################
  'Apparently   it   gets   a   Stack   Pointer   Error,   but   I   don't   know   why;   if   anybody
  'can   fix   that   please   let   me   know                                                     UMGEDV@AOL.COM
  'The   Error   is   not   present   in   the   native   compiled   version;   so   I   think   it   got
  'something   to   do   with   the   P-Code   Calling   Convention   (strange   though)
  '##########################################################################
  '
  'Sub   Dummy   serves   to   reserve   some   space   to   copy   the   machine   instructions   into.
  '
  '
  'Tested   on   Intel   and   AMD   CPU's   (uncompiled   and   compiled)
  '
  '
  Private Declare Function CallWindowProc Lib "user32" Alias "CallWindowProcA" (ByVal lpPrevWndFunc As Long, ByVal hWnd As Long, ByVal Msg As Long, ByVal wParam As Long, ByVal lParam As LongAs Long
  
Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (lpvDest As Any, lpvSource As Any, ByVal cbCopy As Long)
  
Private x     As Long
    
  
Public Function GetCpuName() As String
        
      
Dim MachineCode(0 To 35)           As Byte
      
Dim VarAddr                                 As Long
      
Dim FunctAddr                             As Long
      
Dim EAX                                         As Long
      
Dim CPUName(1 To 12)                   As Byte
        
      
'set   up   machine   code
            
          MachineCode(
0= &H55             'push   ebp
            
          MachineCode(
1= &H8B             'move   ebp,esp
          MachineCode(2= &HEC
            
          MachineCode(
3= &H57             'push   edi
            
          MachineCode(
4= &H52             'push   edx
            
          MachineCode(
5= &H51             'push   ecx
            
          MachineCode(
6= &H53             'push   ebx
            
          MachineCode(
7= &H8B             'move   eax,dword   ptr   [ebp+8]
          MachineCode(8= &H45
          MachineCode(
9= &H8
            
          MachineCode(
10= &HF             'cpuid
          MachineCode(11= &HA2
            
          MachineCode(
12= &H8B           'mov   edi,dword   ptr   [ebp+12]
          MachineCode(13= &H7D
          MachineCode(
14= &HC
            
          MachineCode(
15= &H89           'move   dword   ptr   [edi],ebx
          MachineCode(16= &H1F
            
          MachineCode(
17= &H8B           'mov   edi,dword   ptr   [ebp+16]
          MachineCode(18= &H7D
          MachineCode(
19= &H10
            
          MachineCode(
20= &H89           'move   dword   ptr   [edi],ecx
          MachineCode(21= &HF
            
          MachineCode(
22= &H8B           'mov   edi,dword   ptr   [ebp+20]
          MachineCode(23= &H7D
          MachineCode(
24= &H14
            
          MachineCode(
25= &H89           'move   dword   ptr   [edi],edx
          MachineCode(26= &H17
            
          MachineCode(
27= &H58           'pop   ebx
    
          MachineCode(
28= &H59           'pop   ecx
    
          MachineCode(
29= &H5A           'pop   edx
    
          MachineCode(
30= &H55           'pop   edi
            
          MachineCode(
31= &HC9           'leave
    
          MachineCode(
32= &HC2           'ret   16           I   tried   everything   from   0   to   24
          MachineCode(33= &H10           '                       but   all   produce   the   stack   error
          MachineCode(34= &H0
            
          
'tell   cpuid   what   we   want
          EAX = 0
            
          
'get   address   of   Machine   Code
          VarAddr = VarPtr(MachineCode(0))
            
          
'get   address   of   Sub   Dummy
          FunctAddr = GetAddress(AddressOf Dummy)
            
          
'copy   the   Machine   Code   to   where   it   can   be   called
          CopyMemory ByVal FunctAddr, ByVal VarAddr, 35             '35   bytes   machine   code
            
          
'call   it
          On Error Resume Next         'apparently   it   gets   a   stack   pointer   error   when   in   P-Code   but   i   dont   know   why
              CallWindowProc FunctAddr, EAX, VarPtr(CPUName(1)), VarPtr(CPUName(9)), VarPtr(CPUName(5))
              
'Debug.Print   Err;   Err.Description
              'MsgBox   Err   &   Err.Description
          On Error GoTo 0
            
          GetCpuName 
= StrConv(CPUName(), vbUnicode)         'UnicodeName
            
  
End Function
    
  
Private Function GetAddress(Address As LongAs Long
    
          GetAddress 
= Address
    
  
End Function
    
  
Private Sub Dummy()
    
      
'the   code   below   just   reserves   some   space   to   copy   the   machine   code   into
      'it   is   never   executed
    
          x 
= 0
          x 
= 1
          x 
= 2
          x 
= 3
          x 
= 4
          x 
= 5
          x 
= 6
          x 
= 7
          x 
= 8
          x 
= 9
          x 
= 10
          x 
= 0
          x 
= 1
          x 
= 2
          x 
= 3
          x 
= 4
          x 
= 5
          x 
= 6
          x 
= 7
          x 
= 8
          x 
= 9
          x 
= 10
          
  
End Sub

posted @ 2008-07-08 21:00  Athrun  阅读(648)  评论(0编辑  收藏  举报