#c_sharp #net #windows #winapi
Как программно можно проверить нужный мне процесс, является ли он системным ?
Ответы
Ответ 1
Если приложение запускается с правами администратора, можно воспользоваться 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 - пример.Ответ 2
Если вы откроете диспетчер задач, то увидите владельца процесса => следуя этому ответу Можно получить владельца процесса через WMI: public string GetProcessOwner(int processId) { string query = "Select * From Win32_Process Where ProcessID = " + processId; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); ManagementObjectCollection processList = searcher.Get(); foreach (ManagementObject obj in processList) { string[] argList = new string[] { string.Empty, string.Empty }; int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { // return DOMAIN\user return argList[1] + "\\" + argList[0]; } } return "NO OWNER"; } public string GetProcessOwner(string processName) { string query = "Select * from Win32_Process Where Name = \"" + processName + "\""; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); ManagementObjectCollection processList = searcher.Get(); foreach (ManagementObject obj in processList) { string[] argList = new string[] { string.Empty, string.Empty }; int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { // return DOMAIN\user string owner = argList[1] + "\\" + argList[0]; return owner; } } return "NO OWNER"; } Это более лучшее решение, чем явно перечислять системные процессы, которые могут добавлять при установке спец. компонентов=> список составить тяжело. Как меня поправляют в комментариях, есть еще всякие сервисы, где отсутствует учетка, так же есть некотые системные учетки, например MS SQL работает из специфичной учетки, если я не ошибаюсь.Ответ 3
Начнем с того, что у нас будет какая-то информация о процессах (не забываем подключить пространство имен using System.Diagnostics;): Process[] processList = Process.GetProcesses(); foreach (Process process in processList) { // В process хранится информация о процессе } Метод GetProcesses - возвращает массив компонентов Process для каждого ресурса процесса на локальном компьютере. Собственно, у процесса Process есть свойство Id в котором находится уникальный идентификатор связанного процесса. После выполнения этого кода у нас есть данные о процессах, и можно перейти к другой части, получение описания процесса и владельца процесса. Добавим ссылку на сборку System.Management кликаем на проекте, затем через Add->Reference... ставим галочку и прописываем using System.Management; Напишем такой метод: public static List> GetProcessExtraInformation(int processId) { // запрос получения всех процессов связанных с переданным идентификатором processId string query = "Select * From Win32_Process Where ProcessID = " + processId; ManagementObjectSearcher searcher = new ManagementObjectSearcher(query); ManagementObjectCollection processList = searcher.Get(); // здесь будет результат List > result = new List >(); foreach (ManagementObject obj in processList) { var description = @"Не могу получить информацию о процессе"; // Получим описание процесса, если таковое имеется if (obj["ExecutablePath"] != null) { try { FileVersionInfo info = FileVersionInfo.GetVersionInfo(obj["ExecutablePath"].ToString()); description = info.FileDescription; } catch { } } // Получить владельца процесса в argList var owner = @"Не могу получить владельца процесса"; string[] argList = new string[] { string.Empty, string.Empty }; int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList)); if (returnVal == 0) { owner = argList[1] + "\\" + argList[0]; // Домен и владелец } result.Add(new KeyValuePair (processId, string.Format("Description: '{0}'\nOwner: '{1}'", description, owner))); } return result; } Да, начальный код перепишем вот так: Process[] processList = Process.GetProcesses(); foreach (Process process in processList) { // В process хранится информация о процессе var processInfo = GetProcessExtraInformation(process.Id); foreach (var info in processInfo) { Console.WriteLine(string.Format("Id: {0}\n{1}", info.Key, info.Value)); } Console.WriteLine(); } Console.ReadLine(); В результате получим что-то на подобии вот этого: Модернизировал ответ из источника: How do I determine the owner of a process in C#? и дополнил некоторыми деталями результат. Исходя из полученных данных, можно предположить, что процесс с владельцем SYSTEM - является системным процессом. Также, следует обратить внимание на домены. Учетная запись локальной системы — это встроенная учетная запись, обладающая очень высокими правами доступа. Она имеет обширные права и выступает в качестве компьютера сети. Фактическое имя этой учетной записи — «NT AUTHORITY\SYSTEM». Про учетные записи и службы можно почитать к примеру здесь: Настройка учетных записей служб Windows в разделе Использование стартовых учетных записей для запуска служб SQL Server Ответ 4
Если я не ошибаюсь нет явного способа опеределить, является ли процесс системным, зато можно сделать список системных процессов и проверять вхождение. Вот список навскидку: Listsp = new List { "svchost", "csrss", "System", "wininit", "irstrtsv","scrncap","lsass","System", "wininit","taskmgr","dwm","spoolsv","smss", "SearchIndexer","lsm","taskhost","svchost","explorer", "winlogon","services","conhost" };
Комментариев нет:
Отправить комментарий