基本思路:汇编代码,可以存在一个byte类型的数组中,然后通过某种手段,把系统控制权,转交给这段汇编代码,我们的汇编代码段,就得到了执行。但如何让这段汇编代码,获得系统的控制权限呢?查查WIN API手册,就可以知道有CallWindowProc这个函数。这个函数本是用于调用用户自己定义的窗口过程的,其原形如下:
它有5个参数。lpPrevWnFunc是一个long型,等于用户自己窗口过程的地址,其余3个都是窗口过程所必须的参数,详见MSDN.
我们只需要关心第一个参数:lpPrevWndFunc,窗口过程地址。如果,我们把自己的汇编代码地址,传进去会怎么样?当然,CallWindowProc就把这个地址,当成窗口过程地址,然后,调用这段汇编代码了。我们的汇编代码便得到执……
当然,也得装摸做样的吧,将其余4个参数传进去,就传4个0算了,因为这4个参数,我们更本不用,但又是CallWindowProc必须的,不要忘了,我们传进去的lpPrevWndFunc,并非真正的窗口过程地址,而是自己的汇编码地址。
具体一点,比如,我们要嵌入一段什么也不干的汇编代码:
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
'.....
然后:
VarPtr函数,用于取变量地址。返回一个long 型值。
为什么前面要执行几个pop和一个push呢?因为我们是以一段汇编代码首地址,伪装成一个窗口过程的,系统调用CallWindowProc时,实际上除lpPrevWndFunc,我们还传入了4个参数,就是上面的的4个0,而CallWindoProc函数在调用lpPrevWndFunc这段汇编代码程序时,把其余4个参数是压入了堆栈的。相当于执行了以下代码:
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 xxxx00afh;(当执行call 时,自动执行)
为了能让窗口过程执行结束后堆栈指针保持平衡,当然要执行相应的pop指令,第一个pop eax是把子程序返回的地址暂时保存在寄存器eax中,然后弹出4个不用的参数。
接着把保存在eax中返回地址,压回堆栈。当执行ret时,就能正确返回到CallWindowProc中了。
'
' 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 Long ) As 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 Long ) As 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