How to Get Elevated Process Path in .Net
As you know retrieving process path in .Net is quite straightforward. For example if you have process instance someProcess
you can get the process path by accessing someProcess.MainModule.FileName
However for elevated processes the previous code snippet throws Win32Exception.
As you have probably guessed the reason is related to the bugs I mentioned in my
previous post. In this case too the Process class is using PROCESS_QUERY_INFORMATION
access right to open the desired process. The difference from the previous case is that in order to get the main module and process path the code really needs PROCESS_QUERY_INFORMATION
so we cannot simply change it with PROCESS_QUERY_LIMITED_INFORMATION
.
Fortunately Microsoft has introduced a new function for getting process path QueryFullProcessImageName which does work with PROCESS_QUERY_LIMITED_INFORMATION
access right. To call the function we need to open the process ourselves and pass the handle.
private static string GetExecutablePath(Process Process)
{
//If running on Vista or later use the new function
if (Environment.OSVersion.Version.Major >= 6)
{
return GetExecutablePathAboveVista(Process.Id);
}
return Process.MainModule.FileName;
}
private static string GetExecutablePathAboveVista(int ProcessId)
{
var buffer = new StringBuilder(1024);
IntPtr hprocess = OpenProcess(ProcessAccessFlags.PROCESS_QUERY_LIMITED_INFORMATION,
false, ProcessId);
if (hprocess != IntPtr.Zero)
{
try
{
int size = buffer.Capacity;
if (QueryFullProcessImageName(hprocess, 0, buffer, out size))
{
return buffer.ToString();
}
}
finally
{
CloseHandle(hprocess);
}
}
throw new Win32Exception(Marshal.GetLastWin32Error());
}
[DllImport("kernel32.dll")]
private static extern bool QueryFullProcessImageName(IntPtr hprocess, int dwFlags,
StringBuilder lpExeName, out int size);
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess,
bool bInheritHandle, int dwProcessId);
[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool CloseHandle(IntPtr hHandle);
You can also turn the above code snippet into an extension method too. If you want Microsoft to add a new property for easily getting the process path vote for this suggestion at the connect website: Add Path property to Process class so that it works with elavated processes too.