I am working on a WCF service that is hosted as a windows service which uses named pipes - NamedPipeServerStream (Users privilege) to establish secured connection between server and client processes. To check the authenticity of the client process, I need to verify the digital signature of the client process executable and so I am trying to get the executable path of the client by using its process id.
I use Windows 7 Professional SP1 (64 bit) OS and Visual Studio 2015 Community Edition for developement. Both the server (windows service) and client processes (other exe) are built in Release x64 mode only.
When some client process is connected to the server, I am trying to get the client process exe path but it is throwing "Access Denied" error in the following line of code:
return Process.GetProcessById(processId).MainModule.FileName;
Hence to resolve this issue, I had googled around and tried some other experimental trials as described below that too does not seem to work out.
Experimental Trials
OpenProcess(ProcessAccessFlags.PROCESS_QUERY_INFORMATION, false, processId);
OpenProcess(ProcessAccessFlags.PROCESS_QUERY_LIMITED_INFORMATION, false, processId);
However, I tried all the above methods in a sample windows console application which is working fine without any errors and the same is not working in the windows service. Also I tried to convert the console application into a dll and referred it in the server to get the client process info but failed --> again Access denied
I am completely clueless about what is happening and how to resolve it. Your suggestions would be really helpful.
EDIT : Please find the code snippet for OpenProcess and the ProcessAccessFlags as below:
public static string GetProcessExecutablePath(int processId)
{
try
{
string exePath = string.Empty;
//If running on Vista or later use the new function
if (Environment.OSVersion.Version.Major >= 6)
{
return GetProcessExecutablePathAboveVista(processId);
}
return Process.GetProcessById(processId).MainModule.FileName;
}
catch (Exception ex)
{
return "Exception in GetProcessExecutablePath(): " + ex.Message + ": " + ex.InnerException;
}
}
private static string GetProcessExecutablePathAboveVista(int processId)
{
var buffer = new StringBuilder(1024);
IntPtr hprocess = NativeMethods.OpenProcess(NativeMethods.ProcessAccessFlags.PROCESS_QUERY_LIMITED_INFORMATION,
false, processId);
if (hprocess != IntPtr.Zero)
{
try
{
int size = buffer.Capacity;
if (NativeMethods.QueryFullProcessImageName(hprocess, 0, buffer, out size))
{
return buffer.ToString();
}
else
{
return "Failed in QueryFullProcessImageName(): " + Marshal.GetLastWin32Error();;
}
}
catch (Exception ex)
{
return "Exception in: " + ex.Message;
}
finally
{
NativeMethods.CloseHandle(hprocess);
}
}
else
{
return "Handle is Zero: " + Marshal.GetLastWin32Error();
}
}
NativeMethods.cs
[Flags]
public enum ProcessAccessFlags
{
PROCESS_TERMINATE = 0x0001,
PROCESS_CREATE_THREAD = 0x0002,
PROCESS_VM_OPERATION = 0x0008,
PROCESS_VM_READ = 0x0010,
PROCESS_VM_WRITE = 0x0020,
PROCESS_DUP_HANDLE = 0x0040,
PROCESS_CREATE_PROCESS = 0x0080,
PROCESS_SET_QUOTA = 0x0100,
PROCESS_SET_INFORMATION = 0x0200,
PROCESS_QUERY_INFORMATION = 0x0400,
PROCESS_SUSPEND_RESUME = 0x0800,
PROCESS_QUERY_LIMITED_INFORMATION = 0x1000,
SYNCHRONIZE = 0x100000,
DELETE = 0x00010000,
READ_CONTROL = 0x00020000,
WRITE_DAC = 0x00040000,
WRITE_OWNER = 0x00080000,
STANDARD_RIGHTS_REQUIRED = 0x000F0000,
PROCESS_ALL_ACCESS = STANDARD_RIGHTS_REQUIRED | SYNCHRONIZE | 0xFFFF
}
[DllImport("Kernel32.dll", EntryPoint = "OpenProcess", SetLastError = true)]
public static extern IntPtr OpenProcess(ProcessAccessFlags dwDesiredAccess, bool bInheritHandle, int dwProcessId);
[DllImport("Kernel32.dll", EntryPoint = "QueryFullProcessImageName", SetLastError = true)]
public static extern bool QueryFullProcessImageName(IntPtr hprocess, int dwFlags, StringBuilder lpExeName, out int size);
[DllImport("Kernel32.dll", EntryPoint = "CloseHandle", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool CloseHandle(IntPtr hHandle);
For Windows starting from Vista to get process image file name by pid you may use NtQuerySystemInformation(SystemProcessInformation, ...)
to obtain array of SYSTEM_PROCESS_INFORMATION
structures for each process. This structure has PVOID UniqueProcessId
to find pid you're looking for and UNICODE_STRING ImageName
to get image file name, see
https://msdn.microsoft.com/ru-ru/library/windows/desktop/ms724509(v=vs.85).aspx
https://www.geoffchappell.com/studies/windows/km/ntoskrnl/api/ex/sysinfo/process.htm
User contributions licensed under CC BY-SA 3.0