Search code examples
c#processelevated-privileges

Process.GetProcesses() WHERE process.IsElevated?


I'd like to monitor elevated processes running on a machine while a non-administrative user is logged in.

Basically, I want to run the following made-up code from C#:

var elevatedWindows = Process.GetProcesses().Where(p => p.IsElevated || p.ChildWindows.Any(cw => cw.IsElevated));

So far, the only thing I've found to give me the information I want appears to be a BUG in the .NET System.Diagnostics.Process class, as described here:

http://www.codeproject.com/Articles/302856/Bugs-in-System-Diagnostics-Process-Class

If I understand this correctly, the article says that if my program is not running with elevated permissions, it will generate a WIN32 exception with NativeErrorCode equal to 5 if you try to get an elevated process's StartTime or HasExited properties. I feel like this could be an easy workaround for my issue - try to get StartTime or HasExited from a non-elevated program and if it produces that error, it is an elevated process.

Problem is, I can't seem to get this to work reliably, HasExited errors unreliably when I've manually right-clicked notepad and selected "Run as Administrator", and used GetProcessesByName("notepad")

Even more troublesome is I can't isolate individual Explorer Windows. Explorer.exe is always running, and can be elevated, but even if it is running WITHOUT elevation you can still manually start the process as elevated a number of different ways, none of which effect the parent explorer.exe process.

So I guess I need to find WindowHandles from the spawned processes, or their child threads, and somehow see if the window is elevated?

Any help would be appreciated.


Solution

  • Not sure to understand what you mean by "elevated window". The process is elevated, not its windows. Starting a new Explorer view spawns a new process.

    That said, you could use Interop to determine whether a process is elevated or not:

    Code :

    public enum ElevationType
    {
        Default = 1,
        Full = 2,
        Limited = 3
    }
    
    // Do add some exception handling...etc.
    public static ElevationType GetProcessElevationTypeByTokenHandle(IntPtr hTok)
    {
        if (hTok.IsNotNull)
        {
            // Get token information struct length
            // See https://msdn.microsoft.com/en-us/library/windows/desktop/aa379626(v=vs.85).aspx for constants
            int ret = 0;
            GetTokenInformation(hTok, TokenInformationClass.TokenElevationType, IntPtr.Zero, 0, ret);
            IntPtr tokenInformation = Marshal.AllocHGlobal(ret);
    
            // Get token information struct
            // With then TokenElevationType constant, it will returns a TOKEN_ELEVATION_TYPE value
            // See https://msdn.microsoft.com/en-us/library/windows/desktop/bb530718(v=vs.85).aspx
            GetTokenInformation(hTok, TokenInformationClass.TokenElevationType, tokenInformation, ret, null);
    
            // Get a valid structure
            var value = Marshal.ReadInt32(tokenInformation, 0);
            Marshal.FreeHGlobal(tokenInformation);
            return (ElevationType)value;
        }
        else
        {
            return ElevationType.Default;
        }
    }