getDelegationType
function getDelegateType {
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $func,
[Parameter(Position = 1)] [Type] $delType = [Void]
)
$type = [AppDomain]::CurrentDomain.
DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')),
[System.Reflection.Emit.AssemblyBuilderAccess]::Run).
DefineDynamicModule('InMemoryModule', $false).
DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass',
[System.MulticastDelegate])
$type.
DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $func).
SetImplementationFlags('Runtime, Managed')
$type.
DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $delType, $func).
SetImplementationFlags('Runtime, Managed')
return $type.CreateType()
}
Notes and other stuff
Creating new delegate type for GetUserName method in Advapi32.dll
Getting to understand the parameters in PowerShell. First using Add-Type to create a delegate type for me.
Add-Type creates the delegation type when the assembly is compiled, but we will need to create this manually.
# pinvoke C#
$Advapi32 = @"
using System;
using System.Runtime.InteropServices;
public class Advapi32 {
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool GetUserName(System.Text.StringBuilder sb, ref Int32 length);
}
"@
Add-Type $Advapi32
Now we can view our current loaded assemblies.
# Get loaded assembly
[System.AppDomain]::CurrentDomain.GetAssemblies() | Sort-Object -Property FullName | Format-Table FullName
View parameter types for GetUserName method.
# getting the parameters for delatetype
([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.FullName.Contains('wtw02iqk')}) | ForEach-Object {
$_.GetTypes() | ForEach-Object {
$_.GetMethod('GetUserName').GetParameters()
} 2> $null
}
Using getDelegateType function to create new delegate type for GetUserName
function getProcAddress {
Param (
[OutputType([IntPtr])]
[Parameter( Position = 0, Mandatory = $true)]
[String]
$moduleName,
[Parameter( Position = 1, Mandatory = $true)]
[String]
$functionName
)
# Get reference to System.dll in the GAC
$sysassembly = [System.AppDomain]::CurrentDomain.GetAssemblies() | Where-Object {
$_.GlobalAssemblyCache -and $_.Location.Split('\\')[-1] -eq 'System.dll'
}
$types = $sysassembly.GetTypes()
$unsafenativemethods = ForEach ($type in $types) {
$type | Where-Object {$_.FullName -like '*NativeMethods' -and $_.Fullname -like '*Win32*' -and $_.Fullname -like '*Un*'}
}
# Get reference to GetModuleHandle and GetProcAddress methods
$modulehandle = $unsafenativemethods.GetMethods() | Where-Object {$_.Name -like '*Handle' -and $_.Name -like '*Module*'}
$procaddress = $unsafenativemethods.GetMethods() | Where-Object {$_.Name -like '*Address' -and $_.Name -like '*Proc*'} | Select-Object -First 1
# Get handle on module specified
$module = $modulehandle.Invoke($null, @($moduleName))
$procaddress.Invoke($null, @($module, $functionName))
}
function getDelegateType {
Param (
[Parameter(Position = 0, Mandatory = $True)] [Type[]] $func,
[Parameter(Position = 1)] [Type] $delType = [Void]
)
$type = [AppDomain]::CurrentDomain.
DefineDynamicAssembly((New-Object System.Reflection.AssemblyName('ReflectedDelegate')),
[System.Reflection.Emit.AssemblyBuilderAccess]::Run).
DefineDynamicModule('InMemoryModule', $false).
DefineType('MyDelegateType', 'Class, Public, Sealed, AnsiClass, AutoClass',
[System.MulticastDelegate])
$type.
DefineConstructor('RTSpecialName, HideBySig, Public', [System.Reflection.CallingConventions]::Standard, $func).
SetImplementationFlags('Runtime, Managed')
$type.
DefineMethod('Invoke', 'Public, HideBySig, NewSlot, Virtual', $delType, $func).
SetImplementationFlags('Runtime, Managed')
return $type.CreateType()
}
$GetUserNameAddr = getProcAddress Advapi32.dll GetUserNameA
$GetUserNameDelegationType = getDelegateType @([System.Text.StringBuilder], [Int].MakeByRefType())
$GetUserName = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($GetUserNameAddr, $GetUserNameDelegationType)
$size = 64
$str = New-Object System.Text.StringBuilder -ArgumentList $size
$GetUserName.Invoke($str, [Ref]$size)
$str.ToString()
Other examples
LoadLibrary
Getting to understand the delegate type:
Add-Type creates the delegation type when the assembly is compiled, but we will need to create this manually.
public class rfc {
[DllImport("kernel32")]
public static extern IntPtr LoadLibrary(string name);
}
$n32 = [System.Text.Encoding]::Unicode.GetString([Convert]::FromBase64String($a))
Add-Type $n32
([AppDomain]::CurrentDomain.GetAssemblies() | Where-Object { $_.FullName.Contains('h2a3zadd')}) | ForEach-Object {
$_.GetTypes() | ForEach-Object {
$_.GetMethod('LoadLibrary').GetParameters()
} 2> $null
}
Confirming our delegate type:
Final code to call LoadLibrary
$LoadLibraryAddr = getProcAddress 'kernel32.dll' 'LoadLibraryA'
# HMODULE LoadLibraryA(
# [in] LPCSTR lpLibFileName
# );
$LoadLibraryDelegate = getDelegateType @([System.String]) IntPtr
$LoadLibrary = [System.Runtime.InteropServices.Marshal]::GetDelegateForFunctionPointer($LoadLibraryAddr, $LoadLibraryDelegate)
$LoadLibrary.Invoke("a"+"msi."+"dll")