Завершение процесса из командной строки Windows
Описание работы команды TaskKill, которая позволяет завершать процессы Windows из командной строки. Переменные и операторы.

Windows
Вы наверняка знакомы с традиционным способом завершить процесс в Windows с помощью диспетчера задач. Этот способ эффективен, но использование командной строки даёт больше контроля и возможность завершить несколько процессов за раз.
Возможность завершить процесс из командной строки даёт нам команда TaskKill. Вы можете убить процесс из командной строки по его идентификатору (PID) или по имени образа (имени exe файла).
Запустите консоль от имени администратора и введите команду tasklist, чтобы просмотреть все запущенные процессы.
C:\tasklist Имя образа PID Имя сессии № сеанса Память ========================= ======== ================ =========== ============ System Idle Process 0 Services 0 24 КБ System 4 Services 0 1 256 КБ conhost.exe 5944 Console 2 2 888 КБ notepad.exe 3100 Console 2 7 400 КБ tasklist.exe 8892 Console 2 6 100 КБ WmiPrvSE.exe 7340 Services 0 6 864 КБ smss.exe 372 Services 0 544 КБ csrss.exe 536 Services 0 3 336 КБ wininit.exe 812 Services 0 436 КБ
В приведённом выше примере можно увидеть имя образа и PID для каждого процесса. Если вы хотите убить процесс Notepad, нужно ввести:
Флаг /F — нужен для принудительного завершения процесса. Если его не использовать, то в некоторых случаях ничего не произойдёт, и приложение продолжит свою работу. Как пример, попытка завершения процесса explorer.exe без этого флага ни к чему не приведёт.
Если у вас есть несколько экземпляров приложений, как например chrome, то выполнение команды taskkill /IM. chrome.exe завершит их все. При указании PID можно завершить только конкретные процессы Chrome.
В taskkill есть варианты фильтрации, которые позволяют использовать переменные и операторы.
- STATUS (статус)
- IMAGENAME (имя образа)
- PID (значение)
- SESSION (номер сессии)
- CPUTIME (время CPU)
- MEMUSAGE (использование памяти в кб)
- USERNAME (имя пользователя)
- MODULES (имя DLL)
- SERVICES (имя службы)
- WINDOWTITLE (заголовок окна)
- eq (равно)
- ne (не равно)
- gt (больше чем)
- lt (меньше чем)
- ge (больше или равно)
- le (меньше или равно)
- * (любые символы)
Вы можете использовать переменные и операторы с флагом /FI. Например, вы хотите завершить все процессы, у которых заголовок окна начинается со слова Internet, то команда будет следующей:
taskkill /FI «WINDOWTITLE eq Internet*» /F
Чтобы завершить все процессы, запущенные от имени Alex:
Таким же образом можно завершить процесс, запущенный на другом компьютере из командной строки. Например, имя компьютера OperatorPC, необходимо ввести:
taskkill /S OperatorPC /U Имя_пользователя_на_удаленной_машине /P Пароль_от_удаленной_машины /IM notepad.exe /F
Подробную информацию вы всегда можете получить, запустив taskkill с ключом /? :
Вопросы традиционно приветствуются в комментариях.
- Поверка целостности системных файлов Windows с помощью sfc.exe
- Как вызвать BSOD вручную
- Неопознанная ошибка 0x80240017
- Ошибка при запуске приложения 0xc0000142
- Отсутствует msvcp120.dll
- Расшифровка кодов ошибок MySQL
- Почему обновление KB5008212 не устанавливается на Windows 10, где его скачать
- Как исправить ошибку с кодом 0x80004005 в Windows
- Исправление ошибок из-за отсутствия библиотек DirectX
- Расшифровка кодов ошибок PostgreSQL
Принудительное завершение дочернего процесса из родителя в fork() в си
Возможно ли завершить дочерний процесс не дожидаясь его окончания с помощью функции wait() ? Например, как завершить вот такой дочерний процесс:
pid_t pid; switch(pid=fork()) < case 0: for(;;)<>default: //здесь код, который завершает дочерний процесс return 0;
P.S. Если вы знаете какой-то адекватный, не сильно мудреный материал по fork() , где можно почерпнуть теоретические знания, то направьте меня, пжл.
Отслеживать
user194374
задан 3 дек 2016 в 10:43
407 4 4 серебряных знака 17 17 бронзовых знаков
1 ответ 1
Сортировка: Сброс на вариант по умолчанию
kill(pid, SIGKILL);
Или более мягко:
kill(pid, SIGTERM);
В первом случае дочерний процесс будет просто убит, во втором получит сигнал, который может обработать. Но SIGKILL убъёт процесс гарантированно, а в случае SIGTERM процесс может отказаться заканчивать работу.
В приведённом коде, поскольку процесс, похоже, не содержит обработчиков сигналов, можно использовать любой метод, поскольку, как верно указал на мою ошибку @avp, SIGTERM при отсутствии обработчика также убьёт процесс.
Как принудительно завершить процесс?
Иногда в программистcкой практике встает задача принудительно завершить посторонний процесс. Например, ваша программа может запускать внешние программы для обработки некоторых форматов файлов. Если внешняя программа не завершается в разумный промежуток времени, ее придется завершить принудительно и сообщить пользователю об ошибке. Прочитав эту статью, вы сможете убивать чужие процессы направо и налево, по одиночке и скопом. Мы будем считать, что нам известен идентификатор процесса, который мы хотим завершить.
Функция TerminateProcess
Для принудительного и безоговорочного завершения процессов в Win32 служит функция TerminateProcess :
BOOL TerminateProcess( IN HANDLE hProcess, // описатель процесса IN DWORD dwExitCode // код завершения процесса );
Сейчас я обязан сделать
| Функцию TerminateProcess следует использовать только в исключительных случаях, когда исчерпаны все другие способы воздействия на процесс, поскольку она не позволяет потокам процесса выполнить очистку или сохранить данные, а также не оповещает загруженные DLL о завершении процесса. |
Я уверен, что это предупреждение вас не остановит. Для того, чтобы воспользоваться функцией TerminateProcess , необходимо получить описатель (handle) процесса. Зная идентификатор процесса, это несложно сделать c помощью функции OpenProcess , в итоге функция принудительного завершения процесса может выглядеть, например, так:
BOOL KillProcess( IN DWORD dwProcessId ) < // получаем описатель процесса HANDLE hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId); if (hProcess == NULL) return FALSE; DWORD dwError = ERROR_SUCCESS; // пытаемся завершить процесс if (!TerminateProcess(hProcess, (DWORD)-1)) dwError = GetLastError(); // закрываем описатель процесса CloseHandle(hProcess); SetLastError(dwError); return dwError == ERROR_SUCCESS; >
Завершение процессов и система безопасности Windows NT
Если вы воспользуетесь функцией KillProcess , то обнаружите, что хотя она замечательно работает в Windows 95/98, в Windows NT она не может завершить некоторые процессы, потому что OpenProcess возвращает ошибку ERROR_ACCESS_DENIED. В частности, это происходит при попытке остановить процессы системных служб и некоторых DCOM-серверов. Как вы наверное уже догадываетесь, все дело в правах доступа.
Как и любой объект ядра, объект процесса защищен дескриптором безопасности, который проверяется всякий раз, когда открывается описатель процесса. Для разных видов процессов дескриптор безопасности инициализируется по-разному. Вы можете воспользоваться тестовой программой Process Viewer для изучения дескрипторов безопасности процессов. Так, вы можете обнаружить, что дескриптор безопасности для интерактивных процессов выглядит так:
| Интерактивный пользователь | Полный доступ |
| СИСТЕМА | Полный доступ |
в то время как для системных служб, работающих в контексте системной логон-сессии, дескриптор безопасности выглядит иначе:
| Администраторы | Чтение |
| СИСТЕМА | Полный доступ |
Теперь ясно, почему OpenProcess не позволяет открыть описатель процесса системной службы с правами PROCESS_TERMINATE, даже если вызывающий пользователь является администратором компьютера. Это может показаться странным, почему администратор компьютера не может остановить любой процесс в системе. На самом деле, такая возможность у него есть, и заключается она в наличии привилегии SE_DEBUG_NAME.
Все привилегии, которые имеет пользователь, могут находиться в двух состояниях: выключенном, неактивном, и включенном, активном состоянии. Администраторы компьютера имеют привилегию SE_DEBUG_NAME, но по умолчанию она находится в выключенном состоянии и не оказывает влияния на работу OpenProcess . Когда эта привилегия включена, вызывающий поток может открывать описатели процессов с любыми правами доступа, вне зависимости от того, какой дескриптор безопасности назначен объекту процесса. Это как раз то, что нам нужно.
Ниже приведен модифицированный код функции KillProcess , которая при необходимости включает привилегию SE_DEBUG_NAME, чтобы получить описатель процесса.
BOOL KillProcess( IN DWORD dwProcessId ) < HANDLE hProcess; DWORD dwError; // сначала попробуем получить описатель процесса без // использования дополнительных привилегий hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId); if (hProcess == NULL) < if (GetLastError() != ERROR_ACCESS_DENIED) return FALSE; OSVERSIONINFO osvi; // определяем версию операционной системы osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx(&osvi); // мы больше ничего не можем сделать, если это не Windows NT if (osvi.dwPlatformId != VER_PLATFORM_WIN32_NT) return SetLastError(ERROR_ACCESS_DENIED), FALSE; // включим привилегию SE_DEBUG_NAME и попробуем еще раз TOKEN_PRIVILEGES Priv, PrivOld; DWORD cbPriv = sizeof(PrivOld); HANDLE hToken; // получаем токен текущего потока if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, FALSE, &hToken)) < if (GetLastError() != ERROR_NO_TOKEN) return FALSE; // используем токен процесса, если потоку не назначено // никакого токена if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_ADJUST_PRIVILEGES, &hToken)) return FALSE; > _ASSERTE(ANYSIZE_ARRAY > 0); Priv.PrivilegeCount = 1; Priv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &Priv.Privileges[0].Luid); // попробуем включить привилегию if (!AdjustTokenPrivileges(hToken, FALSE, &Priv, sizeof(Priv), &PrivOld, &cbPriv)) < dwError = GetLastError(); CloseHandle(hToken); return SetLastError(dwError), FALSE; > if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) < // привилегия SE_DEBUG_NAME отсутствует в токене // вызывающего CloseHandle(hToken); return SetLastError(ERROR_ACCESS_DENIED), FALSE; > // попробуем открыть описатель процесса еще раз hProcess = OpenProcess(PROCESS_TERMINATE, FALSE, dwProcessId); dwError = GetLastError(); // восстанавливаем исходное состояние привилегии AdjustTokenPrivileges(hToken, FALSE, &PrivOld, sizeof(PrivOld), NULL, NULL); CloseHandle(hToken); if (hProcess == NULL) return SetLastError(FALSE), NULL; > // пытаемся завершить процесс if (!TerminateProcess(hProcess, (UINT)-1)) < dwError = GetLastError(); CloseHandle(hProcess); return SetLastError(dwError), FALSE; > CloseHandle(hProcess); // успешное завершение return TRUE; >
Модифицированный вариант функции KillProcess сначала пытается открыть описатель процесса без использования привилегии SE_DEBUG_NAME. Если это у него не получается, он включает привилегию, получает описатель процесса и затем восстанавливает привилегию в исходное состояние.
Теперь с помощью функции KillProcess можно убить практически любой процесс в системе, если, конечно, вы являетесь администратором компьютера. Чтобы проверить новый вариант функции в деле, вы можете воспользоваться тестовым приложением Process Viewer, которое теперь умеет завершать процессы. Например, можно остановить процесс Winlogon и через несколько секунд увидеть синий экран с надписью STOP 0xC000021A (не забудьте сохранить все открытые документы, прежде чем это сделать).
Завершение дерева процессов
Некоторое время назад мой коллега по работе попросил меня написать утилиту, аналогичную утилите kill в Unix. Он занимался переносом каких-то скриптов из Unix на Windows NT и ему нужна была такая утилита. Использовать утилиту, поставляемую в составе Windows NT Resource Kit, он не мог по лицензионным (а может, и религиозным) соображениям.
Я быстро оформил функцию KillProcess в виде небольшого консольного приложения и отправил ему. Коллега был приятно удивлен скорости, с которой я выполнил его просьбу, однако он отметил, что моя версия kill работает не так, как аналог из Unix. В Unix, kill завершает не только сам процесс, но и все дочерние процессы, которые были запущены из него прямо или косвенно (так называемое дерево процессов ). Моя же версия работала как kill -9 , когда завершается только указанный процесс. Таким образом, встала задача повторить поведение Unix kill на Windows NT.
Чтобы завершить все процессы в дереве, необходимо каким-либо образом отследить отношения родитель — потомок между процессами. В Windows 9x/Me и Windows 2000/XP это позволяют сделать функции перечисления процессов из ToolHelp32 API, в частности поле th32ParentProcessID структуры PROCESSENTRY32 содержит идентификатор родительского процесса. В Windows NT 4.0 эту информацию можно получить с помощью официально недокументированной функции ZwQuerySystemInformation . (Подробнее о функциях перечисления процессов рассказано в статье Как получить список запущенных процессов?)
Ниже приведен код функции KillProcessEx , которая позволяет завершать как отдельный процесс, так и целое дерево процессов. Если вы читали статью про перечисление процессов, то найдете много знакомых кусков кода в этой функции.
// вспомогательная функция, которая рекурсивно обходит дерево процессов // в Windows NT и завершает все процессы в дереве static BOOL KillProcessTreeNtHelper( IN PSYSTEM_PROCESSES pInfo, IN DWORD dwProcessId ) < _ASSERTE(pInfo != NULL); PSYSTEM_PROCESSES p = pInfo; // сначала завершаем все дочерние процессы for (;;) < if (p->InheritedFromProcessId == dwProcessId) KillProcessTreeNtHelper(pInfo, p->ProcessId); if (p->NextEntryDelta == 0) break; // находим адрес следующей структуры p = (PSYSTEM_PROCESSES)(((LPBYTE)p) + p->NextEntryDelta); > // завершаем исходный процесс if (!KillProcess(dwProcessId)) return GetLastError(); return ERROR_SUCCESS; > // вспомогательная функция, которая рекурсивно обходит дерево процессов // в Windows 9x и завершает все процессы в дереве static BOOL KillProcessTreeWinHelper( IN DWORD dwProcessId ) < HINSTANCE hKernel; HANDLE (WINAPI * _CreateToolhelp32Snapshot)(DWORD, DWORD); BOOL (WINAPI * _Process32First)(HANDLE, PROCESSENTRY32 *); BOOL (WINAPI * _Process32Next)(HANDLE, PROCESSENTRY32 *); // получаем описатель KERNEL32.DLL hKernel = GetModuleHandle(_T("kernel32.dll")); _ASSERTE(hKernel != NULL); // находим необходимые функции KERNEL32.DLL *(FARPROC *)&_CreateToolhelp32Snapshot = GetProcAddress(hKernel, "CreateToolhelp32Snapshot"); *(FARPROC *)&_Process32First = GetProcAddress(hKernel, "Process32First"); *(FARPROC *)&_Process32Next = GetProcAddress(hKernel, "Process32Next"); if (_CreateToolhelp32Snapshot == NULL || _Process32First == NULL || _Process32Next == NULL) return ERROR_PROC_NOT_FOUND; HANDLE hSnapshot; PROCESSENTRY32 Entry; // создаем моментальный снимок процессов hSnapshot = _CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hSnapshot == INVALID_HANDLE_VALUE) return GetLastError(); Entry.dwSize = sizeof(Entry); if (!_Process32First(hSnapshot, &Entry)) < DWORD dwError = GetLastError(); CloseHandle(hSnapshot); return dwError; > // завершаем сначала дочерние процессы do < if (Entry.th32ParentProcessID == dwProcessId) KillProcessTreeWinHelper(Entry.th32ProcessID); Entry.dwSize = sizeof(Entry); > while (_Process32Next(hSnapshot, &Entry)); CloseHandle(hSnapshot); // завершаем исходный процесс if (!KillProcess(dwProcessId)) return GetLastError(); return ERROR_SUCCESS; > BOOL KillProcessEx( IN DWORD dwProcessId, // идентификатор процесса IN BOOL bTree // признак завершения всего дерева ) < if (!bTree) return KillProcess(dwProcessId); OSVERSIONINFO osvi; DWORD dwError; // определяем версию операционной системы osvi.dwOSVersionInfoSize = sizeof(osvi); GetVersionEx(&osvi); if (osvi.dwPlatformId == VER_PLATFORM_WIN32_NT) < HINSTANCE hNtDll; NTSTATUS (WINAPI * _ZwQuerySystemInformation)(UINT, PVOID, ULONG, PULONG); // получаем описатель NTDLL.DLL hNtDll = GetModuleHandle(_T("ntdll.dll")); _ASSERTE(hNtDll != NULL); // находим адрес ZwQuerySystemInformation *(FARPROC *)&_ZwQuerySystemInformation = GetProcAddress(hNtDll, "ZwQuerySystemInformation"); if (_ZwQuerySystemInformation == NULL) return SetLastError(ERROR_PROC_NOT_FOUND), NULL; // получаем описатель кучи процесса по умолчанию HANDLE hHeap = GetProcessHeap(); NTSTATUS Status; ULONG cbBuffer = 0x8000; PVOID pBuffer = NULL; // трудно заранее определить, какой размер выходного // буфера будет достаточным, поэтому мы начинам с буфера // размером 32K и увеличиваем его по необходимости do < pBuffer = HeapAlloc(hHeap, 0, cbBuffer); if (pBuffer == NULL) return SetLastError(ERROR_NOT_ENOUGH_MEMORY), FALSE; Status = _ZwQuerySystemInformation( SystemProcessesAndThreadsInformation, pBuffer, cbBuffer, NULL); if (Status == STATUS_INFO_LENGTH_MISMATCH) < HeapFree(hHeap, 0, pBuffer); cbBuffer *= 2; > else if (!NT_SUCCESS(Status)) < HeapFree(hHeap, 0, pBuffer); return SetLastError(Status), NULL; > > while (Status == STATUS_INFO_LENGTH_MISMATCH); // вызываем вспомогательную функцию dwError = KillProcessTreeNtHelper((PSYSTEM_PROCESSES)pBuffer, dwProcessId); HeapFree(hHeap, 0, pBuffer); > else < // вызываем вспомогательную функцию dwError = KillProcessTreeWinHelper(dwProcessId); > SetLastError(dwError); return dwError == ERROR_SUCCESS; >
Используя функцию KillProcessEx , я смог написать утилиту PKILL, которая более точно соответствует своему Unix-аналогу. Эта утилита прилагается в качестве тестового приложения к данной статье.
Завершение 16-битных задач в Windows NT
Рассмотрение вопроса о завершении процессов не будет полным, если мы не затронем тему 16-битных задач на Windows NT. Для завершения 16-битных задач VDMDBG.DLL предоставляет функцию VDMTerminateTaskWOW :
BOOL VDMTerminateTaskWOW( IN DWORD dwProcessId, // идентификатор виртуальной DOS-машины IN WORD hTask16 // идентификатор 16-битной задачи );
Параметры этой функции говорят сами за себя. Тестовое приложение Process Viewer использует ее для завершения 16-битных задач на Windows NT.
Заключение
Таким образом, теперь вы во всеоружии готовы завершить любой процесс. Но, как и всякое оружие, используйте возможность принудительного завершения процессов с осторожностью.
Cсылки
- Q131065 HOWTO: How to Obtain a Handle to Any Process with SeDebugPrivilege , Microsoft Knowledge Base.
- Q182559 HOWTO: Use VDMDBG Functions on Windows NT , Microsoft Knowledge Base.
Любой из материалов, опубликованных на этом сервере, не может быть воспроизведен в какой бы то ни было форме и какими бы то ни было средствами без письменного разрешения владельцев авторских прав.
Команда TASKKILL — завершить процесс.
Команда TASKKILL используется для завершения процессов по идентификаторам или именам исполняемых файлов на локальной или удаленной системе. Используется в операционных системах Windows XP и старше.
Формат командной строки:
Описание параметров командной строки :
/S система — Имя или IP-адрес удаленного компьютера.
/U [домен\]пользователь — Пользовательский контекст, в котором должна выполняться эта команда.
/P пароль — Пароль для этого пользовательского контекста. Запрашивается, если он не задан.
/FI фильтр — Применение фильтра для выбора набора задач. Разрешение использовать «*». Пример, imagename eq acme*
/PID процесс — Идентификатор процесса, который требуется завершить. Используйте TaskList, чтобы получить PID.
/IM образ — Имя образа процесса, который требуется завершить. Знак подстановки «*» может быть использован для указания всех заданий или имен образов.
/T — Завершение указанного процесса и всех его дочерних процессов.
/F — Принудительное завершение процесса.
/? — Вывод справки по использованию.
IMAGENAME
PID
SESSION
CPUTIME
eq, ne
eq, ne, gt, lt, ge, le
eq, ne, gt, lt, ge, le
eq, ne, gt, lt, ge, le
eq, ne, gt, lt, ge, le
eq, ne
1) Символ ‘*’ для параметра /IM применим только совместно с фильтрами.
2) Завершение удаленных процессов всегда будет принудительным (/F).
3) Фильтры «WINDOWTITLE» и «STATUS» не принимаются во внимание, когда компьютер является удаленным.
Примеры использования TASKKILL.
taskkill /? > taskkill.txt — выдать справку по использованию команды в текстовый файл taskill.txt
TASKKILL /IM notepad.exe — завершить процесс, исполняемым образом которого является notepad.exe . Если таких процессов более одного — то будут завершены все.
taskkill /PID 1234 /T — завершить процесс с идентификатором 1234 и все его дочерние процессы ( /T ) . Одной командой можно завершить несколько процессов, задавая их PID — taskkill /PID 1234 /PID 2345 /PID 800 . Для определения идентификатора процессов используется команда tasklist :
tasklist | find /I «notepad» — отобразить информацию для процессов с именем, содержащим строку notepad . В ответ будет выдано сообщение, например:
notepad.exe        824 Console       1       3 916 КБ
notepad.exe      3004 Console       1      18 812 КБ
Где 824 и 3004 — это идентификаторы процессов PID
TASKKILL /F /FI «PID ge 2000» /FI «WINDOWTITLE eq Arc*» — принудительно (/F) завершить процесс, идентификатор которого больше или равен 2000 и заголовок окна которого , начинается с текста Arc
TASKKILL /F /FI «USERNAME eq NT AUTHORITY\SYSTEM» /IM notepad.exe — принудительно завершить процесс, выполняющийся в контексте учетной записи NT AUTHORITY\SYSTEM и исполняемый файл которого имеет имя notepad.exe
TASKKILL /S 192.168.0.243 /U MyDomain\user /FI «USERNAME ne NT*» /IM * — завершить все процессы, выполняющиеся в контекстах учетных записей, не начинающихся со строки NT на компьютере с IP-адресом 192.168.0.243. При подключении к удаленной системе используется имя пользователя user в домене Mydomain . Пароль не задан и будет запрошен при выполнении команды.
TASKKILL /S SERVER /U Mydomain\User /P UserPass /FI «IMAGENAME eq note*» — завершить все процессы, имя исполняемого файла которых начинается со строки note на удаленном компьютере с именем SERVER .
При завершении процессов как локально, так и удаленно, результат выполнения команды TASKKILL зависит от прав пользователя, в контексте учетной записи которого выполняется команда.
Для использования в многопользовательской конфигурации системы, например на сервере терминалов, вместо команды TASKKILL, удобнее и безопаснее использовать команду TSKILL, адаптированную для завершения процессов в среде конкретных пользователей удаленного рабочего стола (RDP).