VB.NETでマシン語を使う
2005年12月14日
現在のSFCは、Win32APIの殆どをVB.NET内で宣言する形になっている。これは、DynaWrapから脱却するための一つの方法であったのだが、逆にWin32API以外の関数をDLLから呼び出して実行することは出来ない(DynaWrapなら可能)。
そこで、やはり最終的にはDynaCall様の物をVB.NET内に構築して実行する形にしたいと思っている。これには、DynaCallの様なインラインアセンブラが必要である。
前に一度述べたように、こちらのページではインラインマシン語の使い方を紹介している。ただし、ver 2.0の.NET frameworkが必要で、これはまだβバージョンである。正式なver 2.0の登場が待てないので、別の形でインラインマシン語を利用する方法を考えてみた。
前の記事では、Win32APIのEnumWindowsを利用すると、メモリ上に構築されたコードに制御が移ることを確認した。従って、マシン語のコードをメモリ上に構築し、同じ様に呼び出せばよいということである。かくしてできたテストプログラムが以下の通り
作成したマシン語コードの中で別の関数(dcSub())を呼び出すことを試してみた。将来的には、複雑な操作はそういった関数の中で行い、マシン語でしかできない操作のみをこのコード内で行うように設定できるはずである。実行結果は、以下の通り
うまく行っているようである。
そこで、やはり最終的にはDynaCall様の物をVB.NET内に構築して実行する形にしたいと思っている。これには、DynaCallの様なインラインアセンブラが必要である。
前に一度述べたように、こちらのページではインラインマシン語の使い方を紹介している。ただし、ver 2.0の.NET frameworkが必要で、これはまだβバージョンである。正式なver 2.0の登場が待てないので、別の形でインラインマシン語を利用する方法を考えてみた。
前の記事では、Win32APIのEnumWindowsを利用すると、メモリ上に構築されたコードに制御が移ることを確認した。従って、マシン語のコードをメモリ上に構築し、同じ様に呼び出せばよいということである。かくしてできたテストプログラムが以下の通り
Imports System Imports System.Runtime.InteropServices Imports Microsoft.VisualBasic Module Main Delegate Sub d_DcSub() Delegate Function d_EnumWindowsProc(hwnd As Integer, lParam As Integer) As Boolean Declare Function EnumWindows Lib "user32" (x As d_EnumWindowsProc, y As d_DcSub) As Integer Declare Function EnumWindows Lib "user32" (x As Integer, y As Integer) As Integer Sub Main(ByVal CmdArgs() As String) 'Get the pointer of DcSub Dim dGate1 as d_DcSub=AddressOf DcSub EnumWindows(AddressOf EnumWindowsProc,dGate1) Dim p_DcSub as integer=fPointer Console.WriteLine("p_DcSub="+hex(p_DcSub)) 'Get address of DynaCall Dim dcAddress as integer=DynaCall Console.WriteLine("DynaCall address: "+hex(dcAddress)) 'Call the DynaCall through EnumWindws EnumWindows(dcAddress,p_DcSub) End Sub private fPointer as integer=0 Function EnumWindowsProc(hwnd As Integer, lParam As Integer) As Boolean fPointer=lParam Return false End Function Private Sub DcSub() Console.WriteLine("DcSub OK") End Sub private gch as GCHandle private AsmCode() as byte private AsmCodeSize as integer=0 Private Function DynaCall() as integer AddCode(&h58) 'pop eax //contains return address AddCode(&h58) 'pop eax //contains hWnd AddCode(&h58) 'pop eax //contains lParam (address of DcSub) AddCode(&h83,&hec,&h0c) 'sub esp,0000000c //return to original stack position AddCode(&hff,&hd0) 'call eax //call DcSub() AddCode(&h33,&hc0) 'xor eax,eax //eax=0 AddCode(&hc2,&h08,&h00) 'ret 0008 //remove 8 bytes from stack and return eax gch = GCHandle.Alloc(AsmCode, GCHandleType.Pinned) return gch.AddrOfPinnedObject().ToInt32() End Function Private Sub AddCode(b1 as byte) Redim Preserve AsmCode(AsmCodeSize) AsmCode(AsmCodeSize)=b1 AsmCodeSize=AsmCodeSize+1 End Sub Private Sub AddCode(b1 as byte,b2 as byte) AddCode(b1) AddCode(b2) End Sub Private Sub AddCode(b1 as byte,b2 as byte,b3 as byte) AddCode(b1) AddCode(b2) AddCode(b3) End Sub Private Sub AddCode(b1 as byte,b2 as byte,b3 as byte,b4 as byte) AddCode(b1) AddCode(b2) AddCode(b3) AddCode(b4) End Sub End Module
作成したマシン語コードの中で別の関数(dcSub())を呼び出すことを試してみた。将来的には、複雑な操作はそういった関数の中で行い、マシン語でしかできない操作のみをこのコード内で行うように設定できるはずである。実行結果は、以下の通り
p_DcSub=15B26E DynaCall address: 49A6470 DcSub OK
うまく行っているようである。