DelegateType Reflection

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")

Last updated