2017-11-27 13:11:20 -05:00
using System ;
using System.Collections.Generic ;
using System.Diagnostics ;
using System.Linq ;
2018-12-14 17:10:31 -05:00
#if (NET20 || NET35 || NET40 || NET45)
2017-11-27 13:11:20 -05:00
using System.Management ;
2017-11-27 18:50:18 -05:00
# endif
2017-11-27 13:11:20 -05:00
using System.Runtime.InteropServices ;
using Vanara.Security ;
using Vanara.Security.AccessControl ;
using static Vanara . PInvoke . AdvApi32 ;
namespace Vanara.Extensions
{
2018-04-05 16:17:33 -04:00
/// <summary>Values which define a processes integrity level.</summary>
2017-11-27 13:11:20 -05:00
public enum ProcessIntegrityLevel
{
Untrusted ,
Undefined ,
Low ,
Medium ,
High ,
System
}
2018-04-05 16:17:33 -04:00
/// <summary>Extension methods for <see cref="Process"/> for privilegs, status, elevation and relationships.</summary>
2017-11-27 13:11:20 -05:00
public static partial class ProcessExtension
{
public static void DisablePrivilege ( this Process process , SystemPrivilege privilege )
{
2018-10-26 14:24:07 -04:00
using ( var hObj = SafeHTOKEN . FromProcess ( process , TokenAccess . TOKEN_ADJUST_PRIVILEGES | TokenAccess . TOKEN_QUERY ) )
2017-11-27 13:11:20 -05:00
{
hObj . AdjustPrivilege ( privilege , PrivilegeAttributes . SE_PRIVILEGE_DISABLED ) ;
}
}
public static void EnablePrivilege ( this Process process , SystemPrivilege privilege )
{
2018-10-26 14:24:07 -04:00
using ( var hObj = SafeHTOKEN . FromProcess ( process , TokenAccess . TOKEN_ADJUST_PRIVILEGES | TokenAccess . TOKEN_QUERY ) )
2017-11-27 13:11:20 -05:00
{
hObj . AdjustPrivilege ( privilege , PrivilegeAttributes . SE_PRIVILEGE_ENABLED ) ;
}
}
2018-12-14 17:10:31 -05:00
#if (NET35 || NET40 || NET45)
2017-11-27 13:11:20 -05:00
/// <summary>Gets the child processes.</summary>
/// <param name="p">The process.</param>
/// <param name="includeDescendants">if set to <c>true</c> include descendants of child processes as well.</param>
/// <returns>A <see cref="IEnumerable{Process}"/> reference for enumerating child processes.</returns>
public static IEnumerable < Process > GetChildProcesses ( this Process p , bool includeDescendants = false )
{
if ( p = = null ) throw new ArgumentNullException ( nameof ( p ) ) ;
var l = new List < Tuple < int , int > > ( ) ;
var scope = p . MachineName = = "." ? new ManagementScope ( ) : new ManagementScope ( $"\\\\{p.MachineName}\\root\\cimv2" ) ;
using ( var mos = new ManagementObjectSearcher ( scope , new ObjectQuery ( "select ProcessId, ParentProcessId from win32_process" ) ) )
{
foreach ( var obj in mos . Get ( ) . Cast < ManagementObject > ( ) )
l . Add ( new Tuple < int , int > ( Convert . ToInt32 ( obj [ "ProcessId" ] ) , Convert . ToInt32 ( obj [ "ParentProcessId" ] ) ) ) ;
}
return GetChildProcesses ( p . Id , l . GroupBy ( i = > i . Item2 ) . ToDictionary ( g = > g . Key , g = > g . ToList ( ) ) , p . MachineName , includeDescendants ) ;
}
# endif
/// <summary>
/// The function gets the integrity level of the current process. Integrity level is only available on Windows Vista and newer operating systems, thus
/// GetProcessIntegrityLevel throws an exception if it is called on systems prior to Windows Vista.
/// </summary>
/// <returns>Returns the integrity level of the current process.</returns>
/// <exception cref="System.ComponentModel.Win32Exception">
/// When any native Windows API call fails, the function throws a Win32Exception with the last error code.
/// </exception>
/// <exception cref="System.ArgumentNullException"><paramref name="p"/> must be a valid <see cref="Process"/>.</exception>
public static ProcessIntegrityLevel GetIntegrityLevel ( this Process p )
{
if ( p = = null )
throw new ArgumentNullException ( nameof ( p ) ) ;
// Open the access token of the current process with TOKEN_QUERY.
2018-10-26 14:24:07 -04:00
var hObject = SafeHTOKEN . FromProcess ( p , TokenAccess . TOKEN_QUERY | TokenAccess . TOKEN_DUPLICATE ) ;
2017-11-27 13:11:20 -05:00
// Marshal the TOKEN_MANDATORY_LABEL struct from native to .NET object.
2017-11-28 19:11:08 -05:00
var tokenIL = hObject . GetInfo < TOKEN_MANDATORY_LABEL > ( TOKEN_INFORMATION_CLASS . TokenIntegrityLevel ) ;
2017-11-27 13:11:20 -05:00
// Integrity Level SIDs are in the form of S-1-16-0xXXXX. (e.g. S-1-16-0x1000 stands for low integrity level SID). There is one and only one subauthority.
2019-08-16 11:56:43 -04:00
switch ( GetSidSubAuthority ( tokenIL . Label . Sid , 0 ) )
2017-11-27 13:11:20 -05:00
{
case 0 :
return ProcessIntegrityLevel . Untrusted ;
case 0x1000 :
return ProcessIntegrityLevel . Low ;
case var iVal when iVal > = 0x2000 & & iVal < 0x3000 :
return ProcessIntegrityLevel . Medium ;
case var iVal when iVal > = 0x4000 :
return ProcessIntegrityLevel . System ;
case var iVal when iVal > = 0x3000 :
return ProcessIntegrityLevel . High ;
default :
return ProcessIntegrityLevel . Undefined ;
}
}
2018-12-14 17:10:31 -05:00
#if (NET20 || NET35 || NET40 || NET45)
2017-11-27 13:11:20 -05:00
/// <summary>
/// Gets the parent process.
/// </summary>
/// <returns>A <see cref="Process"/> object for the process that called the specified process. <c>null</c> if no parent can be established.</returns>
/// <exception cref="System.ArgumentNullException"><paramref name="p"/> must be a valid <see cref="Process"/>.</exception>
public static Process GetParentProcess ( this Process p )
{
if ( p = = null )
throw new ArgumentNullException ( nameof ( p ) ) ;
try
{
using ( var mo = new ManagementObject ( $"win32_process.handle='{p.Id}'" ) )
{
mo . Get ( ) ;
return Process . GetProcessById ( Convert . ToInt32 ( mo [ "ParentProcessId" ] ) , p . MachineName ) ;
}
}
catch { }
return null ;
}
2017-11-27 18:50:18 -05:00
# endif
2017-11-27 13:11:20 -05:00
/// <summary>Gets the privileges for this process.</summary>
/// <param name="process">The process.</param>
/// <returns>
/// An enumeration of <see cref="PrivilegeAndAttributes"/> instances that include the process privileges and their associated attributes (enabled,
/// disabled, removed, etc.).
/// </returns>
public static IEnumerable < PrivilegeAndAttributes > GetPrivileges ( this Process process )
{
2018-10-26 14:24:07 -04:00
using ( var hObj = SafeHTOKEN . FromProcess ( process , TokenAccess . TOKEN_QUERY | TokenAccess . TOKEN_DUPLICATE ) )
2017-11-27 13:11:20 -05:00
{
return hObj . GetPrivileges ( ) . Select ( la = > new PrivilegeAndAttributes ( la . Luid . GetPrivilege ( process . MachineName ) , la . Attributes ) ) ;
}
}
/// <summary>Determines whether the specified privilege is had by the process.</summary>
/// <param name="process">The process.</param>
/// <param name="priv">The privilege.</param>
/// <returns><c>true</c> if the process has the specified privilege; otherwise, <c>false</c>.</returns>
public static bool HasPrivilege ( this Process process , SystemPrivilege priv ) = > HasPrivileges ( process , true , priv ) ;
/// <summary>Determines whether the specified privileges are had by the process.</summary>
/// <param name="process">The process.</param>
/// <param name="requireAll">if set to <c>true</c> require all privileges to be enabled in order to return <c>true</c>.</param>
/// <param name="privs">The privileges to check.</param>
/// <returns><c>true</c> if the process has the specified privilege; otherwise, <c>false</c>.</returns>
public static bool HasPrivileges ( this Process process , bool requireAll , params SystemPrivilege [ ] privs )
{
2018-10-26 14:24:07 -04:00
using ( var hObj = SafeHTOKEN . FromProcess ( process , TokenAccess . TOKEN_QUERY | TokenAccess . TOKEN_DUPLICATE ) )
2017-11-27 13:11:20 -05:00
return hObj . HasPrivileges ( requireAll , privs ) ;
}
/// <summary>
/// The function gets the elevation information of the current process. It dictates whether the process is elevated or not. Token elevation is only
/// available on Windows Vista and newer operating systems, thus IsProcessElevated throws a C++ exception if it is called on systems prior to Windows
/// Vista. It is not appropriate to use this function to determine whether a process is run as administrator.
/// </summary>
/// <returns>Returns true if the process is elevated. Returns false if it is not.</returns>
/// <exception cref="System.ComponentModel.Win32Exception">
/// When any native Windows API call fails, the function throws a Win32Exception with the last error code.
/// </exception>
/// <exception cref="System.ArgumentNullException"><paramref name="p"/> must be a valid <see cref="Process"/>.</exception>
/// <remarks>
/// TOKEN_INFORMATION_CLASS provides TokenElevationType to check the elevation type (TokenElevationTypeDefault / TokenElevationTypeLimited /
/// TokenElevationTypeFull) of the process. It is different from TokenElevation in that, when UAC is turned off, elevation type always returns
/// TokenElevationTypeDefault even though the process is elevated (Integrity Level == High). In other words, it is not safe to say if the process is
/// elevated based on elevation type. Instead, we should use TokenElevation.
/// </remarks>
public static bool IsElevated ( this Process p )
{
if ( p = = null )
throw new ArgumentNullException ( nameof ( p ) ) ;
try
{
// Open the access token of the current process with TOKEN_QUERY.
2018-10-26 14:24:07 -04:00
using ( var hObject = SafeHTOKEN . FromProcess ( p , TokenAccess . TOKEN_QUERY | TokenAccess . TOKEN_DUPLICATE ) )
2017-11-27 13:11:20 -05:00
return hObject . IsElevated ;
}
catch { }
return false ;
}
/// <summary>
/// The function checks whether the primary access token of the process belongs to user account that is a member of the local Administrators group,
/// even if it currently is not elevated.
/// </summary>
/// <param name="proc">The process to check.</param>
/// <returns>
/// Returns true if the primary access token of the process belongs to user account that is a member of the local Administrators group. Returns false
/// if the token does not.
/// </returns>
public static bool IsRunningAsAdmin ( this Process proc ) = > UAC . IsRunningAsAdmin ( proc ) ;
public static void RemovePrivilege ( this Process process , SystemPrivilege privilege )
{
2018-10-26 14:24:07 -04:00
using ( var hObj = SafeHTOKEN . FromProcess ( process , TokenAccess . TOKEN_ADJUST_PRIVILEGES | TokenAccess . TOKEN_QUERY ) )
2017-11-27 13:11:20 -05:00
{
hObj . AdjustPrivilege ( privilege , PrivilegeAttributes . SE_PRIVILEGE_REMOVED ) ;
}
}
private static IEnumerable < Process > GetChildProcesses ( int pid , Dictionary < int , List < Tuple < int , int > > > allProcs , string machineName , bool allChildren = true )
{
if ( allProcs = = null ) throw new ArgumentNullException ( nameof ( allProcs ) ) ;
foreach ( var val in allProcs [ pid ] )
{
var cpid = val . Item1 ;
if ( allChildren & & allProcs . ContainsKey ( cpid ) )
foreach ( var cval in GetChildProcesses ( cpid , allProcs , machineName ) )
yield return cval ;
Process retProc = null ;
try { retProc = Process . GetProcessById ( cpid , machineName ) ; } catch { }
if ( retProc ! = null ) yield return retProc ;
}
}
}
}