Модераторы: feodorv, GremlinProg, xvr, Fixin
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Процессы и их перечисление, просмотрите статью плз. ниче не забыл? 
:(
    Опции темы
Kergan
Дата 20.12.2005, 16:02 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бывалый
*


Профиль
Группа: Участник
Сообщений: 159
Регистрация: 20.8.2005

Репутация: 2
Всего: 5



Тут много тем было по этому поводу. Вот,решил нембольшой мануал написать... Как тулхелпом процессы, кучи, модули и потоки перечислить. все-таки работа с процессами не ограничивается их перечислением)))
Работа с процессами. Основные приемы.
Раюота с процессами – основа, без которой заниматься системным программированием так же бессмысленно, как без знания структуры PE-файлов или организации памяти. Поэтому я поднимаю эту тему вновь и расскажу о работе с процессами посредством функций TOOLHELP.

Язык программирования: я выбрал C (без плюсиков, т.к. работы с классами в этой статье не будет – после прочтения вы сможете их без труда составить сами) по многим причинам и в первую очередь из-за его низкоуровнего взаимодействия с памятью…записал-считал, все просто и понятно.

Перечислить запущенные в системе процессы можно по-разному, я привык пользоваться функциями TOOLHELP. Общая последовательность действий при работе с этой библиотекой: делаем «снимок» (Snapshot) системной информации, которая нам необходима, потом бегаем по процессам (а также модулям и кучам). Поэтому начнем с простого – перечислим все процессы.
Код

    //Перечисление процессов
    int EnumerateProcs(void)
{
    //создаем "снимок" информации о процессах
    //первый параметр функции - константа, определяющая,
    //какую информацию нам нужно "снять", а второй - 
    //идентификатор процесса, к которому относится эта
    //информация. В данном случае это 0 т.к. мы делаем
    //снимок всех процессов
    HANDLE pSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    bool bIsok = false;
    //Структура, в которую будут записаны данные процесса
    PROCESSENTRY32 ProcEntry;
    //установим ее размер, это необходимое действие
    ProcEntry.dwSize = sizeof(ProcEntry);
    //теперь определим первый процесс
    //первый параметр функции - хэндл "снимка" информации
    //второй - адрес структуры PROCESSENTRY32
    //true - в случае удачи, false - в случае неудачи
    bIsok = Process32First(pSnap, &ProcEntry);    
    //здесь можно было вставить роскошный цикл for(….) но это
    //не совсем удобочитаемо
    //так что цикл while
    while(bIsok)
    {
        //печатаем имя процесса, его идентификатор
        //теперь, когда у нас есть структура ProcEntry
        //То, какую информацию вы из нее возьмете, зависит
        //только от задачи ))
        printf("%s  %u\n", ProcEntry.szExeFile, ProcEntry.th32ProcessID);
        bIsok = Process32Next(pSnap, &ProcEntry);
    }
    //чистим память!
    CloseHandle(pSnap);
    return 1;
}

Вуаля, список всех процессов, аки в диспетчере задач. Теперь мы сделаем кое-что, чего в диспетчере нет! В адресном пространстве каждого процесса (в области памяти, выделенной ему системой) находятся различные библиотеки, которые, собственно, состовляют ПРИЛОЖЕНИЕ. Это и Kernel32 и GDI и еще множество различных. Наша задача – их все пересчитать и переписать! Для этого действа напишем небольшую функцию.
Код

//Перечисление модулей процесса
int EnumerateModules(DWORD PID)
{
    //Входной параметр - идентификатор процесса, чьи модули мы собираемся
    //перечислять. Во первых создадим snapshot информации о модулях
    //теперь нам нужна информация о конкретном процессе - процессе
    //с идентификатором PID
    HANDLE pMdlSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, PID);

    bool bIsok = false;

    //структура с информацией о модуле
    MODULEENTRY32 MdlEntry;
    //зададим размер
    MdlEntry.dwSize = sizeof(MODULEENTRY32);
    //и найдем первый модуль
    bIsok = Module32First(pMdlSnap, &MdlEntry);
    //и далее, как и с процессами
    while(bIsok)
    {    
        //печатаем имя модуля
        printf("    %s \n", MdlEntry.szModule);
        //и переходим к следующему
        bIsok = Module32Next(pMdlSnap, &MdlEntry);    
    }
    //чистим память!
    CloseHandle(pMdlSnap);
    return 1;
}

А теперь немного притормозим и посмотрим, какую еще информацию о процессах и модулях мы получаем:
Код

struct tagPROCESSENTRY32 {
    DWORD dwSize;        //Рамер структуры
DWORD cntUsage;    //Число ссылк на процесс. Процесс уничтожается, //когда число ссылок становится 0
    DWORD th32ProcessID;    //Идентификатор процесса – необходим
                        //во многих функциях
    DWORD th32DefaultHeapID;    //Идентификатор основной кучи – имеет
                        //смысл только в функциях toolhelp
    DWORD th32ModuleID;    //идентификатор модуля - имеет
                        //смысл только в функциях toolhelp
    DWORD cntThreads;        //Число потоков
    DWORD th32ParentProcessID;    //Идентификатор родителя – возвращается
                            //Даже если родителя уже нет
LONG pcPriClassBase;    //приоритет по умолчанию всех //создаваемых процессом потоков
    DWORD dwFlags;            //Зарезервировано
    CHAR  szExeFile[MAX_PATH];    //Собственно имя процесса
} PROCESSENTRY32,*PPROCESSENTRY32,*LPPROCESSENTRY32;
typedef struct tagMODULEENTRY32 {
    DWORD dwSize;            //размер структуры
    DWORD th32ModuleID;    //идентификатор модуля
    DWORD th32ProcessID;    //идентификатор процесса, к которому относится
                        //модуль
    DWORD GlblcntUsage;        //общее число ссылок на этот модуль
    DWORD ProccntUsage;        //число ссылко в контексте процесса,
                        //по идентификатору которого был создан
                        //снэпшот. Если равен 65535 – модуль подгружен
                        //неявно
    BYTE *modBaseAddr;        //адрес модуля в контексте процесса
    DWORD modBaseSize;        //размер проекции
    HMODULE hModule;        //ссылка на модуль
    char szModule[MAX_MODULE_NAME32 + 1]; //Имя модуля
    char szExePath[MAX_PATH];        //Полный путь к модулю
} MODULEENTRY32,*PMODULEENTRY32,*LPMODULEENTRY32;

Обратите внмание: ссылка на модуль (параметр hModule) – это первый байт ДОС-заголовка! Таким образом, мы получаем возможность работать с проекцией при некотором знании структуры PE-файлов. В частности мы можем прочиатать таблицу импорта, и, как правило, – даже переписать ее (это используется при перехвате АПИ).
Параметр szExePath имеет свой «заскок» - иногда полный путь к модулю возвращается со странными вставками и, например, всесто «c:\windows\system32\advapi32.dll» я иногда получаю «c:\x86_proc_winsyspath\advapi32.dll».
Как правило для системных задач средней сложности (перехват апи, или, наоборот, перехват стелсов) всего вышеописанного хватает. Но на этом возможности toolhelp не исчерпываются и теперь мы побегаем по потокам! Работа с потоками несколько отличается от работы с модулями – даже если мы сделаем снимок, задав идентификатор какого-либо процесса, функция Thread32Next не остановится, пока не пробежится по ВСЕМ потокам в системе. Поэтому мы должны проверять, к какому процессу принадлежит поток – благо, в структуре THREADENTRY32 есть член th32OwnerProcessID – идентификатор породившего поток процесса. Таким образом:
Код

int EnumerateThreads(DWORD PID)
{
    //Начнем с создания снимка
    HANDLE pThreadSnap =  CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, PID);

    bool bIsok = false;
    //Структура, описывающая поток
    THREADENTRY32 ThrdEntry;
    //ставим размер
    ThrdEntry.dwSize = sizeof(THREADENTRY32);
    //Берем первый поток
    bIsok = Thread32First(pThreadSnap, &ThrdEntry);
    //и бегаем по всем потокам...
    while (bIsok)
    {    
        //проверяем, тому ли процессу принадлежит поток
        if (ThrdEntry.th32OwnerProcessID == PID)
        {
            //Если да, то выводим некотурую информацию...
            //Хоть она никому нафиг не нужна :о)
            printf("%u  %u\n", ThrdEntry.th32OwnerProcessID, ThrdEntry.th32ThreadID);
        }
        bIsok = Thread32Next(pThreadSnap, &ThrdEntry);
    }
    //не забываем чистить память
    CloseHandle(pThreadSnap);
    return 1;
}

Ну вот, у нас есть потоки. Что еще осталось? Правильно, остались кучи. Здесь тоже все очень просто:
Код

int EnumerateHeaps(DWORD PID)
{
    //Первый параметр - идентификатор процесса
    //а второй - основная куча
    //Теперь делаем снимок, чтоб перечислить кучки...
    HANDLE pSnapHeaps = CreateToolhelp32Snapshot(TH32CS_SNAPHEAPLIST, PID);
    bool bIsok = false;
    bool bIsokHeap = false;
    //Структура, в которую будут записываться данные списка кучи
    HEAPLIST32 HpLst;
    //Структура, в которую будут записываться данные
    //непосредствнно БЛОКОВ КУЧИ
    HEAPENTRY32 HpEntry;
    //Ставим размеры...
    HpLst.dwSize = sizeof(HEAPLIST32);
    HpEntry.dwSize = sizeof(HEAPENTRY32);
    bIsok = Heap32ListFirst(pSnapHeaps, &HpLst);
    while (bIsok)
    {
        //Теперь перечисляем блоки кучи
        //этот код я привел, чтобы стало ясно
        //как получить данные по блокам
        //но он жрет много времени
        //так что я его закомментирую - если вам интересно
        //можете погонять...
        /*bIsokHeap = Heap32First(&HpEntry, PID, HpLst.th32HeapID);
        while(bIsokHeap)
        {
            //Выводим немного информации
            printf("%u    \n", HpEntry.dwBlockSize);
            //Шагаем дальше
            bIsokHeap = Heap32Next(&HpEntry);
        }*/
        //выводим инфу о куче в общем
        printf("%u \n", HpLst.dwSize);
        //шагаем дальше
        bIsok = Heap32ListNext(pSnapHeaps, &HpLst);
    }
    CloseHandle(pSnapHeaps);
    return 1;
}

Ну вот, теперь тока осталось написать о структурах THREADENTRY32, HEAPENTRY32 и HEAPLIST32:
Код

typedef struct tagTHREADENTRY32{
 DWORD dwSize;        //размер структуры
 DWORD cntUsage;    //число ссылок
 DWORD th32ThreadID;    //идентификатор
 DWORD th32OwnerProcessID;    //родительский процесс
 LONG tpBasePri;        //основной приоритет (при инициализации)
 LONG tpDeltaPri;    //изменение приоритета
 DWORD dwFlags; //зарезервировано
 } THREADENTRY32;
typedef THREADENTRY32 * PTHREADENTRY32;
typedef THREADENTRY32 * LPTHREADENTRY32; 


typedef struct tagHEAPENTRY32
{
    DWORD  dwSize;    //размер структуры
    HANDLE hHandle;     // хэндл этого блока
    DWORD  dwAddress;   // линейный адрес начала блока
    DWORD  dwBlockSize; // размер блока в байтах
    DWORD  dwFlags;    //флаги
/*
LF32_FIXED Блок памяти имеет фиксированную позицию 
LF32_FREE  Блок памяти не используется
 LF32_MOVEABLE  Блок памяти может перемещаться
*/
    DWORD  dwLockCount; число «замков»
    DWORD  dwResvd;    // зарезервировано
    DWORD  th32ProcessID;   // родительский процесс
    DWORD  th32HeapID;      // идентификатор кучи
} HEAPENTRY32;
typedef HEAPENTRY32 *  PHEAPENTRY32;
typedef HEAPENTRY32 *  LPHEAPENTRY32; 

typedef struct tagHEAPLIST32
{
    DWORD  dwSize;    //размер структуры
    DWORD  th32ProcessID;   // родительский процесс
    DWORD  th32HeapID;      //куча в контексте процесса 
    DWORD  dwFlags;    //флаг. Значение всегда одно:
// HF32_DEFAULT – основная куча процесса
} HEAPLIST32;

В прилагаемых к статье исходниках все функции собраны вместе. Вызовы функций EnumerateHeaps, EnumerateThreads и EnumerateModules проводится из EnumerateProcs. Все скомпилино в Visual C++ 6.0. В тесте использована информация из MSDN и книги Джеффри Рихтера «Создание эффективных win32 приложений» (имхо эта книга – настольная для системного программиста).

Это сообщение отредактировал(а) Kergan - 21.12.2005, 12:21

Присоединённый файл ( Кол-во скачиваний: 140 )
Присоединённый файл  ProcArticle.rar 8,86 Kb
--------------------
Была у меня дурацкая подпись...Я ее убрал, а новую еще не придумал. :(
PM MAIL ICQ   Вверх
Fixin
Дата 20.12.2005, 23:28 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Ёжик
***


Профиль
Группа: Комодератор
Сообщений: 1357
Регистрация: 6.1.2004

Репутация: 8
Всего: 18



Первое, что заметил - заключи структуры в кодовые теги - лучше выглядеть будет.
PM MAIL ICQ   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "C/C++: Системное программирование и WinAPI"
Fixin
GremlinProg
xvr
feodorv
  • Большое количество информации и примеров с использованием функций WinAPI можно найти в MSDN
  • Описание сообщений, уведомлений и примеров с использованием компонент WinAPI (BUTTON, EDIT, STATIC, и т.п.), можно найти в MSDN Control Library
  • Непосредственно, перед созданием новой темы, проверьте заголовок и удостоверьтесь, что он отражает суть обсуждения.
  • После заполнения поля "Название темы", обратите внимание на наличие и содержание панели "А здесь смотрели?", возможно Ваш вопрос уже был решен.
  • Приводите часть кода, в которой предположительно находится проблема или ошибка.
  • Если указываете код, пользуйтесь тегами [code][/code], или их кнопочными аналогами.
  • Если вопрос решен, воспользуйтесь соответствующей ссылкой, расположенной напротив названия темы.
  • Один топик - один вопрос!
  • Перед тем как создать тему - прочтите это .

На данный раздел распространяются Правила форума и Правила раздела С++:Общие вопросы .


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Chipset, Step, Fixin, GremlinProg, xvr. feodorv.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Системное программирование и WinAPI | Следующая тема »


 




[ Время генерации скрипта: 0.0880 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.