PoshCode Logo PowerShell Code Repository

Handles by titty twisted 2 weeks ago
embed code: <script type="text/javascript" src="http://PoshCode.org/embed/6836"></script>download | new post

Original github link https://github.com/gregzakh/alt-ps/blob/master/Get-Handles.ps1

  1. function Get-Handles {
  2.   <#
  3.     .SYNOPSIS
  4.         Enumarates handles of the specified process.
  5.     .EXAMPLE
  6.         PS C:\> Get-Handles 3828
  7.     .NOTES
  8.         Author: greg zakharov
  9.  
  10.         PROCESS_DUP_HANDLE = 0x40
  11.         STATUS_INFO_LENGTH_MISMATCH = 0xC0000004
  12.         STATUS_SUCCESS = 0x00000000
  13.  
  14.         SystemHandleInformation = 16
  15.         ObjectNameInformation = 1
  16.         ObjectTypeInformation = 2
  17.   #>
  18.   param(
  19.     [Parameter(Mandatory=$true)]
  20.     [ValidateScript({($script:proc = Get-Process -Id $_ -ea 0) -ne $null})]
  21.     [Int32]$Id
  22.   )
  23.  
  24.   begin {
  25.     @(
  26.       [Runtime.InteropServices.Marshal],
  27.       [Runtime.InteropServices.GCHandle],
  28.       [Runtime.InteropServices.CharSet],
  29.       [Runtime.InteropServices.CallingConvention],
  30.       [Reflection.BindingFlags]
  31.     ) | ForEach-Object {
  32.       $keys = ($ta= [PSObject].Assembly.GetType(
  33.         'System.Management.Automation.TypeAccelerators'
  34.       ))::Get.Keys
  35.       $collect = @()
  36.     }{
  37.       if ($keys -notcontains $_.Name) { $ta::Add($_.Name, $_) }
  38.       $collect += $_.Name
  39.     }
  40.  
  41.     function private:New-DllImport {
  42.       param(
  43.         [Parameter(Mandatory=$true, Position=0)]
  44.         [ValidateNotNullOrEmpty()]
  45.         [String]$Module,
  46.  
  47.         [Parameter(Mandatory=$true, Position=1)]
  48.         [ValidateNotNull()]
  49.         [Hashtable]$Signature,
  50.  
  51.         [Parameter(Position=2)]
  52.         [String]$Type = ${Module}
  53.       )
  54.  
  55.       begin {
  56.         $mod = if (!($m = $ExecutionContext.SessionState.PSVariable.Get(
  57.           'PowerShellDllImport'
  58.         ))) {
  59.           $mb = ([AppDomain]::CurrentDomain.DefineDynamicAssembly(
  60.             (New-Object Reflection.AssemblyName('PowerShellDllImport')), 'Run'
  61.           )).DefineDynamicModule('PowerShellDllImport', $false)
  62.  
  63.           Set-Variable PowerShellDllImport -Value $mb -Option Constant `
  64.                                              -Scope Global -Visibility Private
  65.           $mb # first execution
  66.         }
  67.         else { $m.Value }
  68.  
  69.         ($dllimport = [Runtime.InteropServices.DllImportAttribute]).GetFields() |
  70.         Where-Object { $_.Name -cmatch '\A(C|En|S)' } | ForEach-Object {
  71.           Set-Variable "_$($_.Name)" $_
  72.         }
  73.       }
  74.       process {}
  75.       end {
  76.         try { $pin = $mod.GetType("${Type}Handles") }
  77.         catch {}
  78.         finally {
  79.           if (!$pin) {
  80.             $pin = $mod.DefineType("${Type}Handles", 'Public, BeforeFieldInit')
  81.  
  82.             foreach ($func in $Signature.Keys) {
  83.               <#
  84.                 arr[0] - return type
  85.                 arr[1] - parameters
  86.                 arr[2] - other (SetLastError, CharSet and etc.)
  87.               #>
  88.               $arr = $Signature[$func]
  89.               $fun = $pin.DefineMethod(
  90.                 $func, 'Public, Static, PinvokeImpl', [Type]$arr[0], [Type[]]$arr[1]
  91.               )
  92.  
  93.               # parameters
  94.               $arr[1] | ForEach-Object { $i = 1 }{
  95.                 if ($_.IsByRef) { [void]$fun.DefineParameter($i, 'Out', $null) }
  96.               }
  97.               $ErrorValue = if ($arr[2]) { $true } else { $false }
  98.               $EntryPoint = if ($arr[3]) { $EntryPoint } else { $func }
  99.  
  100.               $atr = New-Object Reflection.Emit.CustomAttributeBuilder(
  101.                 $dllimport.GetConstructor([String]), $Module,
  102.                 [Reflection.PropertyInfo[]]@(), [Object[]]@(),
  103.                 [Reflection.FieldInfo[]]@(
  104.                   $_SetlastError, $_CallingConvention, $_CharSet, $_EntryPoint
  105.                 ), [Object[]]@(
  106.                   $ErrorValue, [CallingConvention]::WinApi, [CharSet]::Auto,
  107.                   $EntryPoint
  108.                 )
  109.               )
  110.               $fun.SetCustomAttribute($atr)
  111.             }
  112.             $pin = $pin.CreateType()
  113.           } # if
  114.           $pin
  115.         }
  116.       }
  117.     }
  118.  
  119.     function private:Move-Next([IntPtr]$ptr) {
  120.       $hes = switch ([IntPtr]::Size) {4 {0x10} 8 {0x18}} # next entry
  121.       $mov = switch ([IntPtr]::Size) {4 {$ptr.ToInt32()} 8 {$ptr.ToInt64()}}
  122.       [IntPtr]($mov + $hes)
  123.     }
  124.  
  125.     $kernel32 = New-DllImport kernel32 -Signature @{
  126.       CloseHandle = [Boolean], @([IntPtr]), $true
  127.       OpenProcess = [IntPtr], @([UInt32], [Boolean], [Int32]), $true
  128.       GetCurrentProcess = [IntPtr], @(), $true
  129.     }
  130.  
  131.     $ntdll = New-DllImport ntdll -Signature @{
  132.       NtDuplicateObject = [Int32], @(
  133.         [IntPtr], [IntPtr], [IntPtr], [IntPtr].MakeByRefType(),
  134.         [UInt32], [UInt32], [UInt32]
  135.       )
  136.       NtQueryObject = [Int32], @(
  137.         [IntPtr], [UInt32], [IntPtr], [UInt32], [UInt32].MakeByRefType()
  138.       )
  139.       NtQuerySystemInformation = [Int32], @(
  140.         [UInt32], [IntPtr], [UInt32], [UInt32].MakeByRefType()
  141.       )
  142.     }
  143.  
  144.     $page, $sz = 0x400, 0x10000 # page size and minimum buffer size
  145.     # UNICODE_STRING and its size
  146.     $usz = [Marshal]::SizeOf((
  147.       $UNICODE_STRING = [Activator]::CreateInstance(
  148.         [Object].Assembly.GetType(
  149.           'Microsoft.Win32.Win32Native+UNICODE_STRING'
  150.         )
  151.       )
  152.     ))
  153.   }
  154.   process {
  155.     $ret = 0 # dummy
  156.  
  157.     try {
  158.       if ((
  159.         $hndl = $kernel32::OpenProcess(0x40, $false, $proc.Id
  160.       )) -eq [IntPtr]::Zero) {
  161.         throw New-Object InvalidOperationException
  162.       }
  163.       # SYSTEM_HANDLE_INFORMATION
  164.       $shi = [Marshal]::AllocHGlobal($sz)
  165.       while ($ntdll::NtQuerySystemInformation(
  166.         16, $shi, $sz, [ref]$ret
  167.       ) -eq 0xC0000004) {
  168.         $shi = [Marshal]::ReAllocHGlobal(
  169.           $shi, [IntPtr]($sz *= 2)
  170.         )
  171.       }
  172.       # number of handles
  173.       $noh = [Marshal]::ReadInt32($shi)
  174.       $mov = switch ([IntPtr]::Size) {4 {$shi.ToInt32()} 8 {$shi.ToInt64()}}
  175.       # first handle
  176.       $tmp = [IntPtr]($mov + [Marshal]::SizeOf([Type][IntPtr]))
  177.       # granted access field offset on both x86 and x64
  178.       $gao = switch ([IntPtr]::Size) {4 {0x0C} 8 {0x10}}
  179.       # walk around
  180.       $handles = for ($i = 0; $i -lt $noh; $i++) {
  181.         # SYSTEM_HANDLE_TABLE_ENTRY_INFO
  182.         $hte = New-Object PSObject -Property @{
  183.           UniqueProcessId  = [Marshal]::ReadInt32($tmp)
  184.           ObjectTypeIndex  = [Marshal]::ReadByte($tmp, 0x04)
  185.           HandleAttributes = [Marshal]::ReadByte($tmp, 0x05)
  186.           HandleValue      = [Marshal]::ReadInt16($tmp, 0x06)
  187.           Object           = [Marshal]::ReadIntPtr($tmp, 0x08)
  188.           GrantedAccess    = [Marshal]::ReadInt32($tmp, $gao)
  189.         }
  190.         # temporary vars
  191.         [IntPtr]$duple = [IntPtr]::Zero # duplicated handle (should be released)
  192.         [IntPtr]$obj   = [IntPtr]::Zero # object type
  193.         [IntPtr]$name  = [IntPtr]::Zero # name info
  194.  
  195.         $ret = 0 # flush previous $ret data
  196.         if ($hte.UniqueProcessId -ne $Id) {
  197.           $tmp = Move-Next $tmp
  198.           continue
  199.         }
  200.         # duplicate for query
  201.         if ($ntdll::NtDuplicateObject(
  202.           $hndl, [IntPtr]$hte.HandleValue, $kernel32::GetCurrentProcess(),
  203.           [ref]$duple, 0, 0, 0
  204.         ) -ne 0) {
  205.           $tmp = Move-Next $tmp
  206.           continue
  207.         }
  208.  
  209.         try {
  210.           # getting handle type
  211.           $obj = [Marshal]::AllocHGlobal($page)
  212.           if ($ntdll::NtQueryObject($duple, 2, $obj, $page, [ref]$ret) -ne 0) {
  213.             throw New-Object InvalidOperationException
  214.           }
  215.  
  216.           [Byte[]]$bytes = 0..($usz - 1) | ForEach-Object {$ofb = 0}{
  217.             [Marshal]::ReadByte($obj, $ofb)
  218.             $ofb++
  219.           }
  220.  
  221.           $gch = [GCHandle]::Alloc($bytes, 'Pinned')
  222.           $uni = [Marshal]::PtrToStructure(
  223.             $gch.AddrOfPinnedObject(), [Type]$UNICODE_STRING.GetType()
  224.           )
  225.           $gch.Free()
  226.           $obj_type = $uni.GetType().GetField('Buffer', [BindingFlags]36).GetValue($uni)
  227.  
  228.           if ($hte.GrantedAccess -eq 0x12019F) {
  229.             throw New-Object InvalidOperationException
  230.           }
  231.           # getting handle name
  232.           $ret = 0
  233.           $name = [Marshal]::AllocHGlobal($page)
  234.           if ($ntdll::NtQueryObject($duple, 1, $name, $page, [ref]$ret) -ne 0) {
  235.             $name = [Marshal]::ReAllocHGlobal($name, [IntPtr]$ret)
  236.             if ($ntdll::NtQueryObject($duple, 1, $name, $page, [ref]$ret) -ne 0) {
  237.               throw New-Object InvalidOperationException
  238.             }
  239.           }
  240.  
  241.           $uni = [Marshal]::PtrToStructure($name, [Type]$UNICODE_STRING.GetType())
  242.           $obj_name = $uni.GetType().GetField('Buffer', [BindingFlags]36).GetValue($uni)
  243.           # print available data
  244.           if (![String]::IsNullOrEmpty($obj_name)) {
  245.             New-Object PSObject -Property @{
  246.               Handle = '0x{0:X}' -f $hte.HandleValue
  247.               Type   = $obj_type
  248.               Name   = $obj_name
  249.             }
  250.           }
  251.         }
  252.         catch {}
  253.         finally {
  254.           if ($name -ne [IntPtr]::Zero) { [Marshal]::FreeHGlobal($name) }
  255.           if ($obj -ne [IntPtr]::Zero) { [Marshal]::FreeHGlobal($obj) }
  256.         }
  257.  
  258.         [void]$kernel32::CloseHandle($duple)
  259.         $tmp = Move-Next $tmp
  260.       }
  261.     }
  262.     catch { $_.Exception }
  263.     finally {
  264.       if ($shi) { [Marshal]::FreeHGlobal($shi) }
  265.       if ($hndl) { [void]$kernel32::CloseHandle($hndl) }
  266.     }
  267.   }
  268.   end {
  269.     if ($handles) { $handles | Format-List }
  270.     $collect | ForEach-Object { [void]$ta::Remove($_) }
  271.   }
  272. }

Submit a correction or amendment below (
click here to make a fresh posting)
After submitting an amendment, you'll be able to view the differences between the old and new posts easily.

Syntax highlighting:


Remember me