Q. Is there an easy way to get the security principal for every running process (managed and unmanaged) on my machine using C#?

Asked by Norman Headlam. Answered by the Wonk on February 6, 2003

A.

[download the code sample for this answer]

 

This task breaks down into three sub-tasks:

 

In the world of unmanaged code, enumerating the list of running processes is matter of calling EnumProcesses, which provides a bit list of process IDs. In .NET, things are a bit simpler using the Process class from the System.Diagnostics namespace:

 

using System.Diagnostics;

...

foreach( Process process in Process.GetProcesses() ) {...}

}

Each Process object provides the name of the process, whether it's being responsive or not and all kinds of other useful information *except* the identity under which the process is running, to get that you need to be able to get at the process token, which is available by calling the unmanaged OpenProcessToken API, which must be brought it via interop:

using System.Runtime.InteropServices;

...

[Flags]

enum TOKEN_ACCESS : uint {

  TOKEN_QUERY = 0x0008,

  ...

};

 

[DllImport("Advapi32.dll", SetLastError = true)]

extern static int OpenProcessToken(IntPtr processHandle, TOKEN_ACCESS desiredAccess, out IntPtr tokenHandle);

 

[DllImport("kernel32.dll", SetLastError = true)]

extern static bool CloseHandle(IntPtr handle);

In addition to the OpenProcessToken, you’ll want the CloseHandle API so that you can close the token again when you’re done:

try {

  IntPtr token = IntPtr.Zero;

  if( OpenProcessToken(process.Handle, TOKEN_ACCESS.TOKEN_QUERY, out token) == 0 ) {

    throw new ApplicationException("Can't open process token for: " + process.ProcessName);

  }

  ...

  CloseHandle(token);

}

catch( Exception ex ) {...}

By default, your code won’t have permissions to open all processes, so you’ll want to wrap a try-catch block around the call to OpenProcessToken if you want to continue enumerating the processes you do have permission to open. However, since most processes you can’t open with OpenProcessToken are those running as SYSTEM, that’s a good heuristic to find those processes (although some processes running under SYSTEM you will be able to open). If you absolutely need every process identity without exception or guesswork, you’ll need to run this code under an NT Service running as System.

Once you’ve got the token, getting the associated identity is matter of creating an instance of the WindowsIdentity class, from the System.Security.Principal namespace, passing in the process token as the constructor argument:

WindowsIdentity who = new WindowsIdentity(token);

Once you’ve got a WindowsIdentity, you can use it for impersonation or just to find out the user name.

How I Figured This Out

I figured this security problem out like all security problems are figured out – I asked Keith Brown, the Prince of Darkness and master of Windows security, for a hint and he pointed me at all kinds of interesting things. If you haven’t made friends with Keith yet, you should. I don’t know how anyone gets any secure code shipped without Keith…

Feedback

I have feedback on this Ask The Wonk answer