Использование CreateThread winapi в скрипте Powershell
Я хочу создать поток, который запускает код скрипта в powershell, используя CreateThread WinApi. Я использую этот код, но произошла ошибка:
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". Как я могу исправить эту ошибку? и есть ли другой способ использовать создание потока winapi в powershell?
1 ответ
Преобразование управляемого объекта в IntPtr возможно путем "закрепления" объекта, но это очень сложная задача, поскольку это разрешено только в "небезопасном" коде. Вы можете сделать это в C#, используя оператор "fixed". Метод GCHandle.AddrOfPinnedObject() является альтернативой, которую можно вызывать непосредственно из PowerShell, но я не могу рекомендовать его вам.
Однако я предупрежу вас, что полное общепринятое программирование "winapi" (или даже использование неуправляемого CreateThread) оказывается очень сложным, если вы попытаетесь сделать это в PowerShell. Вам необходимо понять расширенные возможности взаимодействия.NET и ограничения PowerShell для потоков, которые документированы лишь частично. Использование класса.NET System.Thread вместо Windows API поможет с этим без требования "небезопасного" кода, но даже такой подход я бы рекомендовал вам не делать в PowerShell без объяснения более высокого уровня, чем просто "желающее" программирование на Winapi в PowerShell.
Современный модуль Powershell, который помогает абстрагировать то, что необходимо для легких (потоковых) заданий общего назначения, см. В PoshRSJob на GitHub. Это, вероятно, сэкономит вам много времени на отладку по сравнению с попыткой вызова функций WINAPI самостоятельно. Вступительная статья на https://learn-powershell.net/2015/03/31/introducing-poshrsjob-as-an-alternative-to-powershell-jobs/