0

CreateThread WinApi を使用して、powershell でスクリプト コードを実行するスレッドを作成したいと考えています。私はこのコードを使用しますが、エラーが発生しました:

function local:Get-ProcAddress {
Param (
    [OutputType([IntPtr])]

    [Parameter( Position = 0, Mandatory = $True )]
    [String]
    $Module,

    [Parameter( Position = 1, Mandatory = $True )]
    [String]
    $Procedure
)

# Get a reference to System.dll in the GAC
$SystemAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
    Where-Object { $_.GlobalAssemblyCache -And $_.Location.Split('\\')[-1].Equals('System.dll') }
$UnsafeNativeMethods = $SystemAssembly.GetType('Microsoft.Win32.UnsafeNativeMethods')
# Get a reference to the GetModuleHandle and GetProcAddress methods
$GetModuleHandle = $UnsafeNativeMethods.GetMethod('GetModuleHandle')
$GetProcAddress = $UnsafeNativeMethods.GetMethod('GetProcAddress')
# Get a handle to the module specified
$Kern32Handle = $GetModuleHandle.Invoke($null, @($Module))
$tmpPtr = New-Object IntPtr
$HandleRef = New-Object System.Runtime.InteropServices.HandleRef($tmpPtr, $Kern32Handle)

# Return the address of the function
$GetProcAddress.Invoke($null, @([Runtime.InteropServices.HandleRef]$HandleRef, $Procedure))
}
function local:Get-DelegateType {
Param (
    [OutputType([Type])]

    [Parameter( Position = 0)]
    [Type[]]
    $Parameters = (New-Object Type[](0)),

    [Parameter( Position = 1 )]
    [Type]
    $ReturnType = [Void]
)

$Domain = [AppDomain]::CurrentDomain
$DynAssembly = New-Object Reflection.AssemblyName('ReflectedDelegate')
$AssemblyBuilder = $Domain.DefineDynamicAssembly($DynAssembly, [System.Reflection.Emit.AssemblyBuilderAccess]::Run)
$ModuleBuilder = $AssemblyBuilder.DefineDynamicModule('InMemoryModule', $false)
$TypeBuilder = $ModuleBuilder.DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass', [System.MulticastDelegate])
$ConstructorBuilder = $TypeBuilder.DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $Parameters)
$ConstructorBuilder.SetImplementationFlags('Runtime, Managed')
$MethodBuilder = $TypeBuilder.DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $ReturnType, $Parameters)
$MethodBuilder.SetImplementationFlags('Runtime, Managed')

$TypeBuilder.CreateType()
}

createthread winapi を定義します。

# CreateThread
$CreateThreadAddr = Get-ProcAddress kernel32.dll CreateThread
$CreateThreadDelegate = Get-DelegateType @([IntPtr], [UInt32], [IntPtr], [IntPtr], [UInt32], [IntPtr]) ([IntPtr])
$CreateThread = [Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($CreateThreadAddr, $CreateThreadDelegate)

私はこの方法で createthread winapi を呼び出します:

$ThreadProcScript = {
Param (
    [Parameter()]
    [IntPtr]$lpParameter

)
calc.exe
return [Int32]0

}
$Delegate = Get-DelegateType @([IntPtr]) ([int32])
$Callback = $ThreadProcScript -as $Delegate
$CreateThread.Invoke(0,0,$Callback ,0,0,0)

しかし、エラーが発生しました:「MyDelegateType」型の「MyDelegateType」値を「System.IntPtr」型に変換できません。このエラーを修正するにはどうすればよいですか? powershellでcreate thread winapiを使用する別の方法はありますか?

4

1 に答える 1

4

管理対象オブジェクトを IntPtr に変換することは、オブジェクトを「固定」することで可能ですが、「安全でない」コードでのみ許可されているため、これは非常に厄介な作業です。'fixed' ステートメントを使用して C# で実行できます。GCHandle.AddrOfPinnedObject()メソッドは、PowerShell から直接呼び出すことができる代替手段ですが、お勧めできません。

ただし、PowerShell で実行しようとすると、完全に一般的な "winapi" プログラミング (またはアンマネージ CreateThread の使用) が非常に複雑になることを警告します。スレッドに対する高度な .NET 相互運用機能と PowerShell の制限を理解する必要がありますが、どちらも部分的にしか文書化されていません。Windows API の代わりに .NET の System.Thread クラスを使用すると、「安全でない」コードを必要とせずにこの部分を解決できますが、そのアプローチでさえ、PowerShellでは実行しないことをお勧めします。 PowerShell で winapi プログラミングを「したい」。

汎用目的の軽量 (スレッド) ベースのジョブに必要なものを抽象化するのに役立つ最新の Powershell モジュールについては、GitHub のPoshRSJobを参照してください。おそらく、WINAPI 関数を自分で呼び出そうとするよりも、デバッグに多くの時間を節約できます。https://learn-powershell.net/2015/03/31/introducing-poshrsjob-as-an-alternative-to-powershell-jobs/の紹介記事

于 2016-09-11T12:10:18.150 に答える