pwsh/Get-PsHandle.ps1
using namespace System.Runtime.InteropServices Set-Alias -Name pshandle -Value Get-PsHandle function Get-PsHandle { [CmdletBinding()]param($PSBoundParameters) begin { New-Delegate kernel32 { bool CloseHandle([ptr]) } New-Delegate ntdll { int NtDuplicateObject([ptr, ptr, ptr, ptr_, uint, bool, uint]) int NtQueryInformationProcess([ptr, uint, ptr, uint, buf]) int NtQueryObject([ptr, uint, buf, uint, buf]) } $to_i = "ToInt$((32, 64)[($x = ($sz = [IntPtr]::Size) / 4 - 1)])" $page = [Byte[]]::new(0x1000) function Expand-UniString([IntPtr]$h, [UInt32]$o) { if (!$ntdll.NtQueryObject.Invoke($h, $o, $page, $page.Length, $null)) { try { $uni = [GCHandle]::Alloc($page, [GCHandleType]::Pinned) $str = $uni.AddrOfPinnedObject() [Marshal]::PtrToStringUni([Marshal]::ReadIntPtr([ptr].Mov($str, $sz))) } catch { Write-Verbose $_ } finally { if ($uni) { $uni.Free() } } } } } process {} end { New-PsProxy $PSBoundParameters -Callback { try { $ptr = [Marshal]::AllocHGlobal(($bufsz = 0x1000)) while ($ntdll.NtQueryInformationProcess.Invoke($_.Handle, 51, $ptr, $bufsz, $null)) { $ptr = [Marshal]::ReAllocHGlobal($ptr, [IntPtr]($bufsz *= 2)) } $tmp, $hndl = $ptr, $_.Handle $handles = (0..([Marshal]::ReadIntPtr($tmp).$to_i() - 1)).ForEach{ $HandleValue = [Marshal]::ReadIntPtr([ptr].Mov($tmp, (0x08, 0x10)[$x])) [IntPtr]$duple = [IntPtr]::Zero if ($ntdll.NtDuplicateObject.Invoke( $hndl, $HandleValue, [IntPtr]-1, [ref]$duple, 0, $false, 0x02 ) -eq 0) { $page.Clear() $__type = Expand-UniString $duple 2 $page.Clear() $__name = Expand-UniString $duple 1 if (!$kernel32.CloseHandle.Invoke($duple)) { Write-Verbose "Cannot close $($duple.$to_i()) duple." } [PSCustomObject]@{ Value = '0x{0:X}' -f $HandleValue.$to_i() Type = $__type Name = $__name } } $tmp = [ptr].Mov($tmp, (0x1C, 0x28)[$x]) } } catch { Write-Verbose $_ } finally { if ($ptr) { [Marshal]::FreeHGlobal($ptr) } } if ($handles) { $handles.Where{![String]::IsNullOrEmpty($_.Name)} } } # proxy } } Export-ModuleMember -Alias pshandle -Function Get-PsHandle |