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.
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:
OpenProcess
to get a process handleOpenProcessToken
to open the access token associated with your processGetTokenInformation
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;
}
}