C/C++: Пишем процесс-менеджер

Николай "G" Андреев

Xakep, номер #056, стр. 056-076-2


Структура PROCESSENTRY32

typedef struct tagPROCESSENTRY32 {

DWORD dwSize;

DWORD cntUsage;

DWORD th32ProcessID;

ULONG_PTR th32DefaultHeapID;

DWORD th32ModuleID;

DWORD cntThreads;

DWORD th32ParentProcessID;

LONG pcPriClassBase;

DWORD dwFlags;

TCHAR szExeFile[MAX_PATH];

} PROCESSENTRY32;

typedef PROCESSENTRY32 *PPROCESSENTRY32;

Создадим снимок процесса и начнем его исследовать. Воспользуемся для этого функцией CreateToolhelp32Snapshot, о которой я уже говорил раньше. В первом параметре мы передадим ей константу TH32CS_SNAPPROCESS, говорящую о нашем желании получить снимок именно процессов, а не модулей, нитей или чего-нибудь другого в этом роде. Второй параметр нас совершенно не интересует, поэтому передаем NULL. Функция вернет значение типа HANDLE, которое мы сохраним в какую-нибудь переменную и будем впоследствии его использовать.

Получив снимок, можно начать перечислять процессы при помощи функции Process32First, в первом параметре которой мы передадим полученный HANDLE снимка, а во втором ссылку на переменную типа PROCESSENTRY32. Далее создадим цикл do - while, его условием является равенство нулю функции Process32Next. Там же в цикле будем заносить в массив DWORD значение члена th32ProcessID нашей структуры, увеличивать счетчик на 1 и ставить имя процесса в листбокс. В коде это выглядит так:

// process - наша структура

idarray[i++] = process.th32ProcessID;

SendDlgItemMessage(hwnd, IDC_LISTBOX1, LB_ADDSTRING,

0, (LPARAM)process.szExeFile);

SendDlgItemMessage(hwnd, IDC_LISTBOX1, LB_SETCURSEL,

(WPARAM)SendDlgItemMessage(hw, IDC_LISTBOX1, LB_GETCOUNT, 0, 0)-1, 0

где hwnd - описание нашего окна (формы), а IDC_LISTBOX1 - идентификатор листбокса. В итоге, для того, чтобы перечислить процессы и сообщить о них нашему таскменеджеру, необходимо всего лишь выполнить этот цикл. Но системные процессы не дадут доступа к своим свойствам, и мы не сможем ни закрыть их, ни даже посмотреть их имена. Как это исправить? Надо повысить привилегии процесса-менеджера до уровня отладчика. Звучит сложно, но на самом деле - раз плюнуть. Я написал небольшую функцию для изменения собственных привилегий. Запусти ее с параметром true, и получишь уровень отладчика, с false - ты его, соответственно, лишишься.

Листинг функции, дающей привилегии отладчика нашей программе

void EnableDebugPrivilege(bool fEnable){

HANDLE hToken;

if (OpenProcessToken(GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &hToken)){

TOKEN_PRIVILEGES tp;

tp.PrivilegeCount = 1;

LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &tp.Privileges[0].Luid);

tp.Privileges[0].Attributes = fEnable ? SE_PRIVILEGE_ENABLED : 0;

AdjustTokenPrivileges(hToken, false, &tp, sizeof(tp), NULL, NULL);

CloseHandle(hToken);

}

}

Убиваем процессы

Хорошо, какие процессы есть в системе - мы знаем, но как ими манипулировать? Для этого нам нужно получить хэндл процесса. Только получив его, можно с ним что-нибудь сотворить. Делается это с помощью функции OpenProcess, передав которой параметры PROCESS_ALL_ACCESS, false и идентификатор процесса (из массива), получим дескриптор. Поскольку мы пишем менеджер процессов, то первое, что он должен уметь - эти процессы убивать (завершать). Завершить их совсем не сложно. Достаточно запустить функцию TerminateProcess с параметрами: хэндл процесса и код завершения (я пишу 0). Функция завершит процесс, а так как привилегии у нас высокие, то убиваемый процесс умрет без лишних слов.

Назад на стр. 056-076-1  Содержание  Вперед на стр. 056-076-3