страничка tripsin'а


Главная | Статьи | Заметки | Файлы| Ссылки | я
 

Дальше

Получение списка процессов. 0 часть. Подготовка.

Скачай демонстрационный проект (26,1 кб)

Здесь мы рассмотрим 6 способов получения списка процессов в User Mode. Хотя способов гораздо больше, здесь будут рассмотрены только законные (рекомендованные)  способы. Вот они: с помощью библиотек – Tool Help, Process Satus Helper,  Performance Data Helper, из реестра, с помощью Native API, через сервер терминалов. Остальные можно отнести ко всяким хитростям и хакам, и в простой прикладной программе они вряд ли пригодятся. Если все-таки они тебе нужны, то читай статью MsRem’а «Обнаружение скрытых процессов».

Список процессов хранится в ядре системы в виде кольцевого двусвязного списка структур EPROCESS. Эти структуры разные в разных версиях Windows. И просто так ты этот список получить не сможешь. Для этого нужно опускаться в ring0 (например, писать драйвер). Из user-mode (ring3) информацию о процессах можно получить с помощью функции NtQuerySystemInformation (из ntdll.dll). Все остальные библиотеки, используемые для работы с процессами, потоками, модулями и т.п., так или иначе используют именно эту функцию.

Мы напишем функцию FillProcessesList, которая будет получать объект-список TStringList и заполнять его списком имен запущенных процессов и другой информацией. В случае удачного завершения функция будет возвращать True , при ошибке – False. Эту функцию мы напишем для каждого способа, а использовать ее будем  в простом тестовом проекте. Работать будем в Delphi. Для начала создадим болванку проекта. Кинем на пустую форму Memo и 1 кнопку. Все имена компонентов оставим по умолчанию. В разделе uses  добавим модуль Sample1, в котором и напишем функцию  FillProcessesList. Работать наша прога будет до неприличия просто: при нажатии на кнопку в Memo будет выводиться список процессов. Код должен выглядеть примерно так:

 

unit Unit1;

 

interface

 

uses

  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,

  Dialogs, StdCtrls, ExtCtrls, Sample1;

 

type

  TForm1 = class(TForm)

    Button1: TButton;

    Memo1: TMemo;

    procedure Button1Click(Sender: TObject);

  end;

 

var

  Form1: TForm1;

 

implementation

 

{$R *.dfm}

 

procedure TForm1.Button1Click(Sender: TObject);

var

  slProcessesList: TStringList; // Сюда будем пихать список процессов

begin

  slProcessesList := TStringList.Create; // Создаем объект

  if FillProcessesList(slProcessesList) then // Заполняем список процессов

    Memo1.Lines.Assign(slProcessesList)      // и передаем его в TMemo

  else                                       // или выводим ошибку.

    ShowMessage('Ошибка. Не могу получить список процессов.');

  slProcessesList.Free; // Уничтожаем объект.

end;

 

end.

 

Чтобы исследовать каждый новый метод получения списка процессов, надо в разделе uses менять модуль Sample1 на Sample2, ...3 и т.д.

Кроме того, нам понадобится несколько вспомогательных функций. Дело в том, что некоторый гордые системные процессы не хотят открываться простой юзерской проге, мол мало прав. Поэтому наша прога будет нагло присваивать себе привилегии отладчика, функцией EnableDebugPrivileges и сдавать их функцией DisableDebugPrivileges.

Подробно код их разбирать не будем, т.к. это уже другая тема.

 

procedure EnableDebugPrivileges; // Получить привилегии отладчика

var

  hToken: THandle;

  tp: TTokenPrivileges;

  DebugNameValue: Int64;

  ret: Cardinal;

begin

  OpenProcessToken(GetCurrentProcess,TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,hToken); // Получаем маркер доступа текущего процесса

  // Получаем значение отладочных привилегий

  LookupPrivilegeValue(nil,'SeDebugPrivilege',DebugNameValue);

  tp.PrivilegeCount := 1; // Включаем отладочные привилегии

  tp.Privileges[0].Luid := DebugNameValue;

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

  // Применяем обновленные привилегии

  AdjustTokenPrivileges(hToken,False,tp,sizeof(tp),nil,ret);

end;

 

procedure DisableDebugPrivileges; // Отключить привилегии отладчика

var

  hToken: THandle;

  tp: TTokenPrivileges;

  DebugNameValue: Int64;

  ret: Cardinal;

begin

  OpenProcessToken(GetCurrentProcess,TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY,hToken);

  LookupPrivilegeValue(nil,'SeDebugPrivilege',DebugNameValue);

  tp.PrivilegeCount := 1;

  tp.Privileges[0].Luid := DebugNameValue;

  tp.Privileges[0].Attributes := 0; // Отключаем отладочные привилегии

  AdjustTokenPrivileges(hToken,False,tp,sizeof(tp),nil,ret);

end;

 

Часто, когда API-функции исполняются неудачно, исключений не возникает. Чтобы все-таки определить причину неудачи надо вызывать GetLastError. Она возвращает код ошибки. А функция PrintError выводит более-менее вразумительное описание этой ошибки и избавит тебя от лазаний по справочникам.

 

procedure PrintError;

var

  msgbuf: array [0..4095] of Char;

  errcode: Cardinal;

begin

  errcode := GetLastError; // Получаем код последней ошибки

  // Форматируем его и выводим на экран в мессаджбоксе

  FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, nil,errcode,

                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),

                msgbuf, sizeof(msgbuf), nil );

  MessageBox(0,PChar('Код:' + IntToStr(errcode) + ' - ' + msgbuf),

             'Ошибка!',MB_ICONERROR + MB_SETFOREGROUND);

end;

 

Эти функции объединены в модуль Addition.pas. Подключай его к проекту по мере надобности.

Ну вроде все. Остается только добавить, что все примеры я компилил в Delphi 7 и тестировал в Windows XP.

 

 

Дальше


(с) tripsin aka Орехов Роман, 2006 г.

Hosted by uCoz