Вопрос Как получить адрес DLL при CreateProcess


yum

Пользователь
Форумчанин
Регистрация
30.11.2023
Сообщения
47
Репутация
5
Я создаю процесс через CreateProcessA в CREATE_SUSPENDED. Как я могу получить все DLL импортируемые в этот процесс.
 

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 085
Репутация
8 208
Я создаю процесс через CreateProcessA в CREATE_SUSPENDED. Как я могу получить все DLL импортируемые в этот процесс.
Вот что ответил ChatGPT.

Алгоритм такой:

Для получения списка всех DLL, импортированных в процесс, созданный с помощью CreateProcessA в режиме CREATE_SUSPENDED, вы можете выполнить следующие шаги. Этот процесс включает в себя анализ структур данных, используемых операционной системой Windows для управления загрузкой модулей.

  1. Получение контекста процесса: Сначала получите контекст созданного процесса, используя GetThreadContext. Это позволит вам определить, где в памяти расположен PEB (Process Environment Block), который содержит информацию о загруженных модулях.
  2. Чтение PEB: Используйте ReadProcessMemory для чтения PEB из адресного пространства целевого процесса. В PEB есть поле Ldr (PPEB_LDR_DATA), которое указывает на структуру, содержащую списки загруженных модулей.
  3. Перебор списка модулей: Структура PPEB_LDR_DATA содержит три двусвязных списка (InLoadOrderModuleList, InMemoryOrderModuleList и InInitializationOrderModuleList), каждый из которых содержит элементы типа LDR_DATA_TABLE_ENTRY. Эти элементы содержат информацию о каждом модуле, включая базовый адрес, размер и полный путь к DLL.
  4. Чтение и анализ списка импорта для каждого модуля: Для каждой DLL, указанной в LDR_DATA_TABLE_ENTRY, вы можете проанализировать PE-заголовок, чтобы получить доступ к разделу импорта. Это позволит вам узнать, какие внешние функции и DLL использует каждый модуль.
Основная сложность здесь заключается в чтении и анализе данных из памяти другого процесса, что требует глубокого понимания формата PE (Portable Executable) и структур данных Windows. Вам потребуется использовать ReadProcessMemory для чтения различных частей памяти процесса и корректно интерпретировать полученные данные.

Попросил написать пример.

Вначале долго упирался, сказал что сложно, но удалось что-то выудить, пример не проверял на запуск.)

Задача:
Напиши программу, которая просто выведет список LDR_DATA_TABLE_ENTRY, имена DLL и их адреса.
Программа должна работать как в x32, так и x64.

C:
#include <windows.h>
#include <stdio.h>
#include <winternl.h>

// Определение типа функции NtQueryInformationProcess для динамического вызова
typedef NTSTATUS (NTAPI *pNtQueryInformationProcess)(
    HANDLE ProcessHandle,
    PROCESSINFOCLASS ProcessInformationClass,
    PVOID ProcessInformation,
    ULONG ProcessInformationLength,
    PULONG ReturnLength);

// Структура PROCESS_BASIC_INFORMATION для использования с NtQueryInformationProcess
typedef struct _PROCESS_BASIC_INFORMATION {
    PVOID Reserved1;
    PEB* PebBaseAddress;
    PVOID Reserved2[2];
    ULONG_PTR UniqueProcessId;
    PVOID Reserved3;
} PROCESS_BASIC_INFORMATION;

int main() {
    STARTUPINFOA si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(si));
    si.cb = sizeof(si);
    ZeroMemory(&pi, sizeof(pi));

    // Создание процесса в состоянии CREATE_SUSPENDED
    if (!CreateProcessA(NULL, "C:\\Windows\\System32\\notepad.exe", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &si, &pi)) {
        printf("CreateProcess failed (%d).\n", GetLastError());
        return 0;
    }

    // Получаем функцию NtQueryInformationProcess из ntdll.dll
    HMODULE hNtdll = GetModuleHandleA("ntdll.dll");
    pNtQueryInformationProcess NtQueryInformationProcess = (pNtQueryInformationProcess)GetProcAddress(hNtdll, "NtQueryInformationProcess");

    PROCESS_BASIC_INFORMATION pbi;
    ZeroMemory(&pbi, sizeof(PROCESS_BASIC_INFORMATION));

    // Получаем базовый адрес PEB
    NTSTATUS status = NtQueryInformationProcess(pi.hProcess, ProcessBasicInformation, &pbi, sizeof(PROCESS_BASIC_INFORMATION), NULL);
    if (status != 0) {
        printf("NtQueryInformationProcess failed (%d).\n", status);
        return 0;
    }

    // Чтение PEB
    PEB peb;
    ReadProcessMemory(pi.hProcess, pbi.PebBaseAddress, &peb, sizeof(PEB), NULL);

    // Чтение PEB_LDR_DATA
    PEB_LDR_DATA ldr;
    ReadProcessMemory(pi.hProcess, peb.Ldr, &ldr, sizeof(PEB_LDR_DATA), NULL);

    // Чтение InLoadOrderModuleList
    LIST_ENTRY* startListEntry = ldr.InLoadOrderModuleList.Flink;
    LIST_ENTRY* listEntry = startListEntry;

    do {
        LDR_DATA_TABLE_ENTRY moduleEntry;
        ReadProcessMemory(pi.hProcess, CONTAINING_RECORD(listEntry, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks), &moduleEntry, sizeof(LDR_DATA_TABLE_ENTRY), NULL);

        WCHAR moduleName[MAX_PATH];
        ReadProcessMemory(pi.hProcess, moduleEntry.BaseDllName.Buffer, moduleName, moduleEntry.BaseDllName.MaximumLength, NULL);

        printf("Module Name: %ws, Base Address: %p\n", moduleName, moduleEntry.DllBase);

        listEntry = moduleEntry.InLoadOrderLinks.Flink;
    } while (listEntry != startListEntry);

    // Закрываем дескрипторы
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);

    return 0;
}

Обратите внимание, что этот код работает только в контексте текущей архитектуры процесса.
 

yum

Пользователь
Форумчанин
Регистрация
30.11.2023
Сообщения
47
Репутация
5
А если просто запускать процесс без CREATE_SUSPEND?
 

X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 085
Репутация
8 208
А если просто запускать процесс без CREATE_SUSPEND?
Тогда такой алгоритм:

  1. Отслеживание события загрузки DLL: Используйте функции отладки, такие как DebugActiveProcess для присоединения к процессу как отладчик. Затем вы можете отслеживать события отладки, в частности, событие LOAD_DLL_DEBUG_EVENT, которое указывает на загрузку DLL.
  2. Использование ToolHelp32 для перечисления модулей: С помощью функции CreateToolhelp32Snapshot можно создать снимок текущего состояния процессов, потоков, модулей и других частей системы. Используя Module32First и Module32Next, вы можете перечислить все модули (DLL), загруженные в процесс.
Ниже приведен пример кода на C++, который использует CreateToolhelp32Snapshot для перечисления всех DLL, загруженных в указанный процесс:

C:
#include <windows.h>
#include <tlhelp32.h>
#include <iostream>

void ListProcessModules(DWORD dwPID) {
    HANDLE hModuleSnap = INVALID_HANDLE_VALUE;
    MODULEENTRY32 me32;

    // Создаем снимок всех модулей в процессе.
    hModuleSnap = CreateToolhelp32Snapshot(TH32CS_SNAPMODULE, dwPID);
    if (hModuleSnap == INVALID_HANDLE_VALUE) {
        std::cerr << "CreateToolhelp32Snapshot failed." << std::endl;
        return;
    }

    // Настройка размера структуры перед использованием.
    me32.dwSize = sizeof(MODULEENTRY32);

    // Получаем информацию о первом модуле в снимке.
    if (!Module32First(hModuleSnap, &me32)) {
        std::cerr << "Module32First failed." << std::endl;  // Показываем сообщение об ошибке, если не удалось.
        CloseHandle(hModuleSnap);  // Освобождаем ресурс снимка.
        return;
    }

    // Теперь перебираем все модули.
    do {
        std::wcout << L"MODULE NAME: " << me32.szModule << L"\n";
        std::wcout << L"Executable  = " << me32.szExePath << L"\n";
        std::wcout << std::endl;
    } while (Module32Next(hModuleSnap, &me32));

    CloseHandle(hModuleSnap);  // Очищаем снимок после использования.
}

int main() {
    DWORD processID = 1234; // Укажите ID процесса, для которого необходимо получить список DLL.
    ListProcessModules(processID);
    return 0;
}
 
Верх Низ