Узнайте, является ли процесс системным процессом - PullRequest
0 голосов
/ 17 ноября 2018

Я пытаюсь выяснить, какие программы запущены пользователем во время работы моей программы, и вывести их в файл.Теперь я сталкиваюсь с ситуацией, когда при извлечении всех процессов с использованием Process.GetProcesses() меня встречает список из примерно 269 процессов, который составляет примерно все, что показывает диспетчер задач, включая процессы Windows, например 77 процессов svchost.

Теперь я хочу отфильтровать некоторые системные процессы (по крайней мере, те, которые отображаются как «Windows-процессы» в диспетчере задач).Есть ли способ сделать это или мне придется вести список имен процессов (или каталогов файлов) всех процессов Windows?

Ответы [ 3 ]

0 голосов
/ 17 ноября 2018

Просто отфильтруйте результат:

Process.GetProcesses().Where(x => x.MainWindowHandle != IntPtr.Zero)

Проверка пути может обойтись

0 голосов
/ 18 ноября 2018

Краткий ответ:

Решение в диспетчере задач жестко запрограммировано на основе следующего списка (взятого из версии для Windows 10):

%windir%\explorer.exe
%windir%\system32\ntoskrnl.exe
%windir%\system32\WerFault.exe
%windir%\system32\backgroundTaskHost.exe
%windir%\system32\backgroundTransferHost.exe
%windir%\system32\winlogon.exe
%windir%\system32\wininit.exe
%windir%\system32\csrss.exe
%windir%\system32\lsass.exe
%windir%\system32\smss.exe
%windir%\system32\services.exe
%windir%\system32\taskeng.exe
%windir%\system32\taskhost.exe
%windir%\system32\dwm.exe
%windir%\system32\conhost.exe
%windir%\system32\svchost.exe
%windir%\system32\sihost.exe



Длинный ответ:

Потребовалось некоторое время, чтобы добраться до этого списка - ниже находится путь к просветлению ;-)



Оригинальный ответ:

Чтобы ответить на ваш вопрос Узнать, является ли процесс системным процессом не так просто, как кажется.Чтобы получить эту информацию, вы должны получить владельца процесса, который в системах Windows обычно выполняется для идентификаторов безопасности .

идентификатора безопасности(SID) - это уникальное значение переменной длины, используемое для идентификации доверенного лица.Каждая учетная запись имеет уникальный SID, выданный органом, таким как контроллер домена Windows, и сохраненным в базе данных безопасности.Каждый раз, когда пользователь входит в систему, система извлекает SID для этого пользователя из базы данных и помещает его в маркер доступа для этого пользователя.Система использует SID в маркере доступа для идентификации пользователя во всех последующих взаимодействиях с безопасностью Windows.Когда SID использовался в качестве уникального идентификатора для пользователя или группы, он никогда не сможет снова использоваться для идентификации другого пользователя или группы.

Вы наверняка видели один из них, эточто-то вроде S-1-5-18 или S-1-5-21-2557247 ...-... ... ... ... 1001 .

Существует полный список WellKnown SID , который также включает в себя набор SID, которые вы, вероятно, все рассматривали бы как Системный процесс -связанный.

Если я не ошибаюсь, вы хотите получить все процессы, которые работают под локальной системной учетной записью , что будет S-1-5-18 .

Хватит говорить, давайте код:

Прежде всего мы (это вы, я уже проверял это ;-)) должны импортировать GetSecurityInfo из advapi32.dll вот так:

[DllImport("advapi32.dll", SetLastError = true)]
private static extern uint GetSecurityInfo(IntPtr handle,
                                           SE_OBJECT_TYPE objectType,
                                           SECURITY_INFORMATION securityInfo,
                                           out IntPtr sidOwner,
                                           out IntPtr sidGroup,
                                           out IntPtr dacl,
                                           out IntPtr sacl,
                                           out IntPtr securityDescriptor);

... который требует двух перечислений для SE_OBJECT_TYPE и SECURITY_INFORMATION , которые должны быть определены следующим образом:

private enum SE_OBJECT_TYPE
{
    SE_UNKNOWN_OBJECT_TYPE,
    SE_FILE_OBJECT,
    SE_SERVICE,
    SE_PRINTER,
    SE_REGISTRY_KEY,
    SE_LMSHARE,
    SE_KERNEL_OBJECT,
    SE_WINDOW_OBJECT,
    SE_DS_OBJECT,
    SE_DS_OBJECT_ALL,
    SE_PROVIDER_DEFINED_OBJECT,
    SE_WMIGUID_OBJECT,
    SE_REGISTRY_WOW64_32KEY
}

private enum SECURITY_INFORMATION
{
    OWNER_SECURITY_INFORMATION = 1,
    GROUP_SECURITY_INFORMATION = 2,
    DACL_SECURITY_INFORMATION = 4,
    SACL_SECURITY_INFORMATION = 8,
}

Теперь мы почти у цели.Если вы вызываете GetSecurityInfo следующим образом ...

uint returnValue = GetSecurityInfo(process.Handle,
                                   SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
                                   SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION,
                                   out IntPtr ownerSid,
                                   out IntPtr groupSid,
                                   out IntPtr dacl,
                                   out IntPtr sacl,
                                   out IntPtr securityDescriptor);

... и в результате получаете ERROR_SUCESS (то есть 0), вы можете использовать экземпляркласса SecurityIdentifier , чтобы проверить, является ли полученный SID локальной системной учетной записью или нет, например:

SecurityIdentifier securityIdentifier = new SecurityIdentifier(ownerSid);

if (securityIdentifier.IsWellKnown(WellKnownSidType.LocalSystemSid))
{
    // The process is running unter the local system account.
}

Вот и все.Для достижения окончательного результата вам необходимо проверить наличие нескольких идентификаторов безопасности, таких как Система , Локальная служба , Сетевая служба и т. Д. *

Вот небольшой пример, который делает это для всех процессов на локальной машине.Конечно, вам нужно будет запустить его с правами доступа, в противном случае вы получите ошибки об отказе в доступе.

private static void Main(string[] args)
{
    const uint ERROR_SUCCESS = 0;
    Process[] processes = Process.GetProcesses();

    foreach (Process process in processes)
    {
        try
        {
            uint returnValue = GetSecurityInfo(process.Handle,
                                               SE_OBJECT_TYPE.SE_KERNEL_OBJECT,
                                               SECURITY_INFORMATION.OWNER_SECURITY_INFORMATION,
                                               out IntPtr ownerSid,
                                               out IntPtr groupSid,
                                               out IntPtr dacl,
                                               out IntPtr sacl,
                                               out IntPtr securityDescriptor);

            if (returnValue != ERROR_SUCCESS)
            {
                // If the function succeeds, the return value is ERROR_SUCCESS.
                // If the function fails, the return value is a nonzero error code defined in WinError.h.
                continue;
            }

            SecurityIdentifier securityIdentifier = new SecurityIdentifier(ownerSid);
            Console.WriteLine("Owner of process {0} is {1}", process.ProcessName, securityIdentifier);

            if (securityIdentifier.IsWellKnown(WellKnownSidType.LocalSystemSid))
            {
                Console.WriteLine("Running under System Account");
            }
        }
        catch (Exception e)
        {
            Console.WriteLine("Unable to retrieve owner for process {0}: {1}", process.ProcessName, e.Message);
        }
    }





Обновление:

Если вы сравните результат (с исходным ответом) со списком процессов в диспетчере задач, все равно будет расхождение.В ходе дальнейшего изучения этой проблемы я натолкнулся на статью , в которой говорится, что процессы, помеченные как критические , будут отображаться в процессах Windows . * 1107.*

Если у процесса есть видимое окно, диспетчер задач называет его «приложением».

Если процесс помечен как критический, диспетчер задач называет его «Windows».Процесс ".

В противном случае диспетчер задач называет его" фоновым процессом ".

Это можно оценить, просто вызвав IsProcessCritical .Следовательно, DllImport необходим ...

[DllImport("kernel32.dll", SetLastError = true)]
private static extern bool IsProcessCritical(IntPtr hProcess, ref bool Critical);

... впоследствии его можно назвать так:

bool criticalProcess = false;

if (!IsProcessCritical(process.Handle, ref criticalProcess))
{
    // Could not retrieve process information
}

if (criticalProcess)
{
    // This is a critical process, it should be listed
    // in the "Windows processes" section.
}

Хотя это звучит многообещающе, это не так- это все еще приводит к неправильным результатам.


Итак, после установки API Monitor (кстати, невероятного программного обеспечения), фильтрации и поиска по более чем 5 миллионам (уже предварительно отфильтрованных) вызовов API, я заметил, что Taskmgr.exe вызывает ExpandEnvironmentString несколько раз с аргументами, которые, по-видимому, не извлекаются до вызова.


После дальнейшего исследования (и логического вывода) я заметил, что в Taskmgr.exe есть жестко закодированный список. Его можно просто найти с помощью Process Explorer :

  1. Запуск обозревателя процессов
  2. Щелкните правой кнопкой мыши Taskmgr.exe
  3. Переход к строкам вкладка
  4. Прокрутка вниз
  5. Быть разочарованным

Есть следующие записи:

%windir%\explorer.exe
%windir%\system32\ntoskrnl.exe
%windir%\system32\WerFault.exe
%windir%\system32\backgroundTaskHost.exe
%windir%\system32\backgroundTransferHost.exe
%windir%\system32\winlogon.exe
%windir%\system32\wininit.exe
%windir%\system32\csrss.exe
%windir%\system32\lsass.exe
%windir%\system32\smss.exe
%windir%\system32\services.exe
%windir%\system32\taskeng.exe
%windir%\system32\taskhost.exe
%windir%\system32\dwm.exe
%windir%\system32\conhost.exe
%windir%\system32\svchost.exe
%windir%\system32\sihost.exe


Итак, мой вывод:
Решение в диспетчере задач жестко запрограммировано на основе приведенного выше списка (взято из версии для Windows 10).

0 голосов
/ 17 ноября 2018

Один из способов сделать это - отфильтровать все процессы, путь которых начинается с пути каталога Windows.

Вы можете получить путь к каталогу Windows, вызвав Environment.GetFolderPath с Environment.SpecialFolder.Windows вот так:

var windowsPath = Environment.GetFolderPath(Environment.SpecialFolder.Windows);

И затем вы можете отфильтровать все процессы, изображение которых находится где-то в этой папке:

var processes = Process.GetProcesses();
foreach (var process in processes) {
  if (!process.MainModule.FileName.StartsWith(windowsPath)) {
    // Do something with process
  }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...