VB.NETでマシン語を使う2
2005年12月14日
VB.NETによるDynaCallの原型になるテストプログラムが完成した。テストでは、MessageBoxAを呼び出すことに成功している。
実行結果は以下の通り

"OK"を押すと
"キャンセル"を押すと
の様にコンソールに出力される。
option explicit
Imports System
Imports System.Runtime.InteropServices
Imports Microsoft.VisualBasic
Module Main
Declare Function EnumWindows Lib "user32" (x As Integer, y As Integer) As Integer
Declare Function LoadLibrary Lib "kernel32" Alias "LoadLibraryA" (ByVal lpLibFileName As String) As Integer
Declare Function GetProcAddress Lib "kernel32" Alias "GetProcAddress" (ByVal ModuleHandle As Integer, ByVal ProcName As String) As Integer
Declare Function FreeLibrary Lib "kernel32" (ByVal hDll As Integer) As Integer
Sub Main()
'Load DLL and resolve Proc Address
Dim hDll as integer =LoadLibrary("user32")
Dim MessageBoxA as integer=GetProcAddress(hDll,"MessageBoxA")
'Prepare buffer for getting return code from API
Dim Res(1) as integer
Dim gch as GCHandle=GCHandle.Alloc(Res, GCHandleType.Pinned)
'Prepare the parameters
dim Params(3) as integer
Params(0)=0
dim str1 as AnsiString=new AnsiString("DynaCall.NET")
dim str2 as AnsiString=new AnsiString("テスト")
Params(1)=str1.address
Params(2)=str2.address
Params(3)=vbOkCancel
'Call the machine code through EnumWindws
EnumWindows(TheCode(Params,gch.AddrOfPinnedObject().ToInt32()),MessageBoxA)
Console.WriteLine("eax: "+hex(Res(0)))
Console.WriteLine("edx: "+hex(Res(1)))
FreeLibrary(hDll)
End Sub
private GchAsmCode as GCHandle
private AsmCode() as byte
private AsmCodeSize as integer
Private Function TheCode(Params() as integer,AddrOfRes as integer) as integer
Dim i as integer
'Initialize buffer
On error resume next
GchAsmCode.free()
On error goto 0
AsmCodeSize=0
AddByte(&H58) 'pop eax //contains return address
AddByte(&H58) 'pop eax //contains hWnd
AddByte(&H58) 'pop eax //contains lParam (address of API)
AddByte(&H83,&Hec,&H0c) 'sub esp,0000000c //return to original stack position
for i=Params.Length-1 to 0 step -1
AddByte(&H68)
AddInt(Params(i)) 'push Params(i) //create the stack for API
next i
AddByte(&Hff,&Hd0) 'call eax //call API
AddByte(&Hbb):AddInt(AddrOfRes) 'mov ebx,AddrOfRes
AddByte(&H89,&H03) 'mov [ebx],eax //put the return code (eax)
AddByte(&H89,&H53,&h04) 'mov [ebx+4],edx //put the return code (edx)
AddByte(&H33,&Hc0) 'xor eax,eax //eax=0 (return code is 0)
AddByte(&Hc2,&H08,&H00) 'ret 0008 //remove 8 bytes from stack and return
GchAsmCode = GCHandle.Alloc(AsmCode, GCHandleType.Pinned)
return GchAsmCode.AddrOfPinnedObject().ToInt32()
End Function
Private Sub AddByte(b1 as byte)
Redim Preserve AsmCode(AsmCodeSize)
AsmCode(AsmCodeSize)=b1
AsmCodeSize=AsmCodeSize+1
End Sub
Private Sub AddByte(b1 as byte,b2 as byte)
AddByte(b1)
AddByte(b2)
End Sub
Private Sub AddByte(b1 as byte,b2 as byte,b3 as byte)
AddByte(b1)
AddByte(b2)
AddByte(b3)
End Sub
Private Sub AddByte(b1 as byte,b2 as byte,b3 as byte,b4 as byte)
AddByte(b1)
AddByte(b2)
AddByte(b3)
AddByte(b4)
End Sub
Private Sub AddInt(i1 as integer)
Dim T as string=right("00000000"+hex(i1),8)
AddByte(cByte("&H"+mid(T,7,2)))
AddByte(cByte("&H"+mid(T,5,2)))
AddByte(cByte("&H"+mid(T,3,2)))
AddByte(cByte("&H"+mid(T,1,2)))
End Sub
Private Class AnsiString
Private gch as GCHandle
Private buff(0) as byte
Public Sub New(T as string)
dim i as integer, b as integer
dim buffLen as integer=0
for i=1 to len(T)
b=asc(mid(T,i,1))
if 0<=b and b<=255 then
Redim Preserve buff(buffLen)
buff(buffLen)=b
buffLen=buffLen+1
else
if b<0 then b=b+65536
Redim Preserve buff(buffLen+1)
buff(buffLen)=b \ 256
buff(buffLen+1)=b mod 256
buffLen=buffLen+2
end if
next i
Redim Preserve buff(buffLen)
buff(buffLen)=0
gch=GCHandle.Alloc(buff, GCHandleType.Pinned)
End Sub
Public Function Address()
Return gch.AddrOfPinnedObject().ToInt32()
End Function
Protected Overrides Sub Finalize()
On error resume next
gch.Free()
end sub
End Class
End Module実行結果は以下の通り

"OK"を押すと
eax: 1 edx: 1870001
"キャンセル"を押すと
eax: 2 edx: 1870001
の様にコンソールに出力される。