Как проверить является ли процесс системным?

1,00
р.
Как программно можно проверить нужный мне процесс, является ли он системным ?


Ответ
Если приложение запускается с правами администратора, можно воспользоваться Restart Manager API:
using System using System.Collections.Generic using System.ComponentModel using System.Runtime.InteropServices using System.Text using System.Diagnostics using System.Windows.Forms
namespace WindowsFormsTest1 { public partial class Form1 : Form {
[DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmStartSession(out UInt32 pSessionHandle, UInt32 dwSessionFlags, string strSessionKey)
[DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmRegisterResources(UInt32 dwSessionHandle, UInt32 nFiles, string[] rgsFilenames, UInt32 nApplications, ref RM_UNIQUE_PROCESS rgApplications, UInt32 nServices, string[] rgsServiceNames)
[DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmGetList(UInt32 dwSessionHandle, out UInt32 pnProcInfoNeeded, ref UInt32 pnProcInfo, [In, Out] RM_PROCESS_INFO[] rgAffectedApps, ref UInt32 lpdwRebootReasons)
[DllImport("Rstrtmgr.dll", CharSet = CharSet.Unicode, PreserveSig = true, SetLastError = true, ExactSpelling = true)] public static extern UInt32 RmEndSession(UInt32 dwSessionHandle)
public const UInt32 RmRebootReasonNone = 0x0 public const int ERROR_MORE_DATA = 234
/// /// Преобразование DateTime в структуру FILETIME /// public static System.Runtime.InteropServices.ComTypes.FILETIME FileTimeFromDateTime(DateTime date) { long ftime = date.ToFileTime() System.Runtime.InteropServices.ComTypes.FILETIME ft = new System.Runtime.InteropServices.ComTypes.FILETIME() ft.dwHighDateTime = (int)(ftime >> 32) ft.dwLowDateTime = (int)ftime return ft }
/// /// Получение типа процесса /// public static RM_APP_TYPE GetProcessType(Process proc) { uint handle string key = Guid.NewGuid().ToString()
uint res = RmStartSession(out handle, (uint)0, key) if (res != 0) { throw new ApplicationException("Could not begin restart session. ") }
try { uint pnProcInfoNeeded = 0, pnProcInfo = 0, lpdwRebootReasons = RmRebootReasonNone
RM_UNIQUE_PROCESS uniqueprocess = new RM_UNIQUE_PROCESS() uniqueprocess.dwProcessId = proc.Id System.Runtime.InteropServices.ComTypes.FILETIME ft = FileTimeFromDateTime(proc.StartTime) uniqueprocess.ProcessStartTime = ft
res = RmRegisterResources(handle, 0, null, 1, ref uniqueprocess, 0, null)
if (res != 0) { throw new ApplicationException("Could not register resource.") }
res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, null, ref lpdwRebootReasons) if (res == ERROR_MORE_DATA) { RM_PROCESS_INFO[] processInfo = new RM_PROCESS_INFO[pnProcInfoNeeded] pnProcInfo = pnProcInfoNeeded
// Get the list. res = RmGetList(handle, out pnProcInfoNeeded, ref pnProcInfo, processInfo, ref lpdwRebootReasons) if (res == 0) { if (pnProcInfo == 0) throw new ApplicationException("Process not found")
return processInfo[0].ApplicationType } else { throw new ApplicationException("Could not list processes") } } else if (res != 0) { throw new ApplicationException("Failed to get size of result.") } } finally { RmEndSession(handle) } throw new ApplicationException("Process not found") }
public Form1() { InitializeComponent() }
private void button1_Click(object sender, EventArgs e) { //пример использования Process p=Process.GetProcessesByName(textBox1.Text)[0] MessageBox.Show(GetProcessType(p).ToString()) /*Для системных процессов выведет RmCritical*/ } }
/* Определения структур */
[StructLayout(LayoutKind.Sequential)] public struct RM_UNIQUE_PROCESS { // The product identifier (PID). public int dwProcessId // The creation time of the process. public System.Runtime.InteropServices.ComTypes.FILETIME ProcessStartTime }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct RM_PROCESS_INFO { const int CCH_RM_MAX_APP_NAME = 255 const int CCH_RM_MAX_SVC_NAME = 63
// Contains an RM_UNIQUE_PROCESS structure that uniquely identifies the // application by its PID and the time the process began. public RM_UNIQUE_PROCESS Process [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_APP_NAME + 1)] // If the process is a service, this parameter returns the // long name for the service. public string strAppName [MarshalAs(UnmanagedType.ByValTStr, SizeConst = CCH_RM_MAX_SVC_NAME + 1)] // If the process is a service, this is the short name for the service. public string strServiceShortName // Contains an RM_APP_TYPE enumeration value. public RM_APP_TYPE ApplicationType // Contains a bit mask that describes the current status of the application. public uint AppStatus // Contains the Terminal Services session ID of the process. public uint TSSessionId // TRUE if the application can be restarted by the // Restart Manager otherwise, FALSE. [MarshalAs(UnmanagedType.Bool)] public bool bRestartable }
public enum RM_APP_TYPE { // The application cannot be classified as any other type. RmUnknownApp = 0, // A Windows application run as a stand-alone process that // displays a top-level window. RmMainWindow = 1, // A Windows application that does not run as a stand-alone // process and does not display a top-level window. RmOtherWindow = 2, // The application is a Windows service. RmService = 3, // The application is Windows Explorer. RmExplorer = 4, // The application is a stand-alone console application. RmConsole = 5, // A system restart is required to complete the installation because // a process cannot be shut down. RmCritical = 1000 } }
Код основан на данном примере: https://code.msdn.microsoft.com/windowsapps/How-to-know-the-process-704839f4
Метод GetProcessType возвращает тип процесса, для системных процессов он равен значению RM_APP_TYPE.RmCritical.
Если приложение не имеет прав администратора, все проще: попытка получить дескриптор системного процесса просто упадет с ошибкой "Отказано в доступе". Нужно лишь ловить Win32Exception.

Другие способы
С использованием (нерекомендуемой) функции NtQueryInformationProcess из Native API:
const uint ProcessBreakOnTermination = 29
[DllImport("NTDLL.DLL")] static extern int NtQueryInformationProcess(IntPtr hProcess, uint pic, ref uint pi, int cb, out int pSize)
public static bool IsProcessCritical(Process pr) {
uint val = 0 int size int res = NtQueryInformationProcess(pr.Handle, ProcessBreakOnTermination, ref val, sizeof(uint), out size) if (res != 0 || size != sizeof(uint)) throw new Win32Exception("NtQueryInformationProcess failed")
return (val != 0) }
Начиная с Windows 8.1 можно использовать функцию IsProcessCritical - пример.