To perform a dynamic lookup of function addresses, the operating system provides two special Win32 APIs called GetModuleHandle and GetProcAddress.
Searching preload assemblies with GetModuleHandle and GetProcAddress
$assemblies = [AppDomain]::CurrentDomain.GetAssemblies()
$assemblies |
ForEach-Object {
$_.GlobalAssemblyCache
$_.Location
$_.GetTypes() |
ForEach-Object {
$_ | Get-Member -static | Where-Object {
$_.TypeName.Contains('Unsafe') -and $_.Name.Contains('GetProcAddress') -or $_.Name.Contains('GetModuleHandle')
} | Format-Table *
} 2> $null
}
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))
}