Уроки Разработка малвари-18.Определение PID нужного процесса, или перечисления процессов


X-Shar

:)
Администрация
Регистрация
03.06.2012
Сообщения
6 085
Репутация
8 208
Тема перечисления процессов затрагивалась здесь:Уроки - Разработка малвари-12. Иньекция в процесс

Также в этой теме для проведения атаки Thread Hijacking в удаленный процесс необходимо получить ID целевого процесса.

Давайте попробуем это сделать, что-бы не привлекать внимание антивирусов.)

Предлагаю использовать функцию NtQuerySystemInformation.
NtQuerySystemInformation экспортируется из модуля ntdll.dll, поэтому для его использования потребуется GetModuleHandle и GetProcAddress.

Документация Microsoft по NtQuerySystemInformation показывает, что он способен возвращать много информации о системе. Основное внимание этой статьи будет уделено его использованию для перечисления процессов.

Получение адреса NtQuerySystemInformation

Как было упомянуто ранее, для получения адреса NtQuerySystemInformation из ntdll.dll необходимы GetProcAddress и GetModuleHandle.

C:
// Указатель на функцию
typedef NTSTATUS (NTAPI* fnNtQuerySystemInformation)(
    SYSTEM_INFORMATION_CLASS SystemInformationClass,
    PVOID                    SystemInformation,
    ULONG                    SystemInformationLength,
    PULONG                   ReturnLength
);

fnNtQuerySystemInformation pNtQuerySystemInformation = NULL;

// Получение адреса NtQuerySystemInformation
pNtQuerySystemInformation = (fnNtQuerySystemInformation)GetProcAddress(GetModuleHandle(L"NTDLL.DLL"), "NtQuerySystemInformation");
if (pNtQuerySystemInformation == NULL) {
    printf("[!] GetProcAddress завершилась с ошибкой: %d\n", GetLastError());
    return FALSE;
}

Параметры NtQuerySystemInformation

Параметры NtQuerySystemInformation показаны ниже.

C:
__kernel_entry NTSTATUS NtQuerySystemInformation(
  [in]            SYSTEM_INFORMATION_CLASS SystemInformationClass,
  [in, out]       PVOID                    SystemInformation,
  [in]            ULONG                    SystemInformationLength,
  [out, optional] PULONG                   ReturnLength
);

SystemInformationClass - Определяет, какой тип системной информации возвращает функция.

SystemInformation - Указатель на буфер, который получит запрошенную информацию. Возвращенная информация будет в форме структуры, тип которой указан в соответствии с параметром SystemInformationClass.

SystemInformationLength - Размер буфера, на который указывает параметр SystemInformation, в байтах.

ReturnLength - Указатель на переменную ULONG, которая получит фактический размер информации, записанной в SystemInformation.

Поскольку задача заключается в перечислении процессов, будет использован флаг SystemProcessInformation. При использовании этого флага функция вернет массив структур SYSTEM_PROCESS_INFORMATION (через параметр SystemInformation), по одной для каждого процесса, работающего в системе.

Структура SYSTEM_PROCESS_INFORMATION

Следующим шагом будет изучение документации Microsoft, чтобы понять, как выглядит структура SYSTEM_PROCESS_INFORMATION.

C:
typedef struct _SYSTEM_PROCESS_INFORMATION {
    ULONG NextEntryOffset;
    ULONG NumberOfThreads;
    BYTE Reserved1[48];
    UNICODE_STRING ImageName;
    KPRIORITY BasePriority;
    HANDLE UniqueProcessId;
    PVOID Reserved2;
    ULONG HandleCount;
    ULONG SessionId;
    PVOID Reserved3;
    SIZE_T PeakVirtualSize;
    SIZE_T VirtualSize;
    ULONG Reserved4;
    SIZE_T PeakWorkingSetSize;
    SIZE_T WorkingSetSize;
    PVOID Reserved5;
    SIZE_T QuotaPagedPoolUsage;
    PVOID Reserved6;
    SIZE_T QuotaNonPagedPoolUsage;
    SIZE_T PagefileUsage;
    SIZE_T PeakPagefileUsage;
    SIZE_T PrivatePageCount;
    LARGE_INTEGER Reserved7[6];
} SYSTEM_PROCESS_INFORMATION;

Основное внимание будет уделено полям UNICODE_STRING ImageName, которое содержит имя процесса, и UniqueProcessId, которое является идентификатором процесса.
Кроме того, поле NextEntryOffset будет использовано для перехода к следующему элементу в возвращаемом массиве.

Поскольку вызов NtQuerySystemInformation с флагом SystemProcessInformation вернет массив структур SYSTEM_PROCESS_INFORMATION неизвестного размера, NtQuerySystemInformation должен быть вызван дважды. Первый вызов получит размер массива, который будет использован для выделения буфера, а затем второй вызов использует выделенный буфер.

Ожидается, что первый вызов NtQuerySystemInformation завершится с ошибкой STATUS_INFO_LENGTH_MISMATCH (0xC0000004), так как в нем передаются недействительные параметры, просто для получения размера массива.

C:
ULONG                        uReturnLen1    = NULL,
                             uReturnLen2    = NULL;
PSYSTEM_PROCESS_INFORMATION  SystemProcInfo = NULL;
NTSTATUS                     STATUS         = NULL;

// Первый вызов NtQuerySystemInformation
// Он завершится ошибкой STATUS_INFO_LENGTH_MISMATCH
// Но он предоставит информацию о том, сколько памяти необходимо выделить (uReturnLen1)
pNtQuerySystemInformation(SystemProcessInformation, NULL, NULL, &uReturnLen1);

// Выделение достаточного буфера для возвращаемого массива структур `SYSTEM_PROCESS_INFORMATION`
SystemProcInfo = (PSYSTEM_PROCESS_INFORMATION) HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (SIZE_T)uReturnLen1);
if (SystemProcInfo == NULL) {
    printf("[!] HeapAlloc завершилась с ошибкой: %d\n", GetLastError());
    return FALSE;
}

// Второй вызов NtQuerySystemInformation
// Вызываем NtQuerySystemInformation с правильными аргументами, результат будет сохранен в 'SystemProcInfo'
STATUS = pNtQuerySystemInformation(SystemProcessInformation, SystemProcInfo, uReturnLen1, &uReturnLen2);
if (STATUS != 0x0) {
    printf("[!] NtQuerySystemInformation завершилась с ошибкой: 0x%0.8X \n", STATUS);
    return FALSE;
}

Перечисление Процессов

Теперь, когда массив успешно получен, следующим шагом будет проход по нему что-бы найти нужный ImageName.
Buffer, который содержит имя процесса. На каждой итерации будет производиться сравнение имени процесса с целевым именем процесса.

Чтобы получить доступ к каждому элементу типа SYSTEM_PROCESS_INFORMATION в массиве, необходимо использовать член NextEntryOffset. Чтобы найти адрес следующего элемента, добавьте адрес предыдущего элемента к NextEntryOffset. Это демонстрируется в приведенном ниже фрагменте кода.

C:
// 'SystemProcInfo' теперь представляет новый элемент в массиве
SystemProcInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)SystemProcInfo + SystemProcInfo->NextEntryOffset);

Освобождение выделенной памяти

Перед переходом SystemProcInfo к новому элементу в массиве необходимо сохранить начальный адрес выделенной памяти, чтобы освободить его позже. Следовательно, перед началом цикла адрес необходимо сохранить во временной переменной.
C:
// Поскольку мы будем изменять 'SystemProcInfo', мы сохраняем его начальное значение перед while-циклом, чтобы освободить его позже
pValueToFree = SystemProcInfo;

Недокументированная часть NtQuerySystemInformation

NtQuerySystemInformation остается в значительной степени недокументированным, и большая часть его до сих пор остается неизвестной. Например, обратите внимание на члены Reserved в SYSTEM_PROCESS_INFORMATION.

1695465903592.png


Полный код выполнения перечисления процессов с использованием NtQuerySystemInformation представлен ниже:

C:
BOOL GetRemoteProcessHandle(LPCWSTR szProcName, DWORD* pdwPid, HANDLE* phProcess) {

    fnNtQuerySystemInformation   pNtQuerySystemInformation = NULL;
    ULONG                        uReturnLen1               = NULL,
                                 uReturnLen2               = NULL;
    PSYSTEM_PROCESS_INFORMATION  SystemProcInfo            = NULL;
    NTSTATUS                     STATUS                    = NULL;
    PVOID                        pValueToFree              = NULL;

    pNtQuerySystemInformation = (fnNtQuerySystemInformation)GetProcAddress(GetModuleHandle(L"NTDLL.DLL"), "NtQuerySystemInformation");
    if (pNtQuerySystemInformation == NULL) {
        printf("[!] GetProcAddress завершилась с ошибкой: %d\n", GetLastError());
        return FALSE;
    }

    pNtQuerySystemInformation(SystemProcessInformation, NULL, NULL, &uReturnLen1);

    SystemProcInfo = (PSYSTEM_PROCESS_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (SIZE_T)uReturnLen1);
    if (SystemProcInfo == NULL) {
        printf("[!] HeapAlloc завершилась с ошибкой: %d\n", GetLastError());
        return FALSE;
    }

    // Так как мы будем изменять 'SystemProcInfo', мы сохраняем его начальное значение перед циклом while, чтобы освободить его позже
    pValueToFree = SystemProcInfo;

    STATUS = pNtQuerySystemInformation(SystemProcessInformation, SystemProcInfo, uReturnLen1, &uReturnLen2);
    if (STATUS != 0x0) {
        printf("[!] NtQuerySystemInformation завершилась с ошибкой: 0x%0.8X \n", STATUS);
        return FALSE;
    }

    while (TRUE) {

        // Проверяем размер имени процесса
        // Сравниваем имя перечисленного процесса с заданным целевым процессом
        if (SystemProcInfo->ImageName.Length && wcscmp(SystemProcInfo->ImageName.Buffer, szProcName) == 0) {

            // Открываем дескриптор целевого процесса, сохраняем его и завершаем выполнение
            *pdwPid        = (DWORD)SystemProcInfo->UniqueProcessId;
            *phProcess    = OpenProcess(PROCESS_ALL_ACCESS, FALSE, (DWORD)SystemProcInfo->UniqueProcessId);
            break;
        }

        // Если NextEntryOffset равен 0, мы достигли конца массива
        if (!SystemProcInfo->NextEntryOffset)
            break;

        // Переходим к следующему элементу в массиве
        SystemProcInfo = (PSYSTEM_PROCESS_INFORMATION)((ULONG_PTR)SystemProcInfo + SystemProcInfo->NextEntryOffset);
    }

    // Освобождаем память, используя начальный адрес
    HeapFree(GetProcessHeap(), 0, pValueToFree);

    // Проверяем, удалось ли нам успешно получить дескриптор целевого процесса
    if (*pdwPid == NULL || *phProcess == NULL)
        return FALSE;
    else
        return TRUE;
}

Этот код использует NtQuerySystemInformation, чтобы перечислить все процессы, работающие в системе, и затем ищет определенный процесс на основе его имени (szProcName). Если такой процесс найден, функция возвращает его идентификатор процесса (pdwPid) и дескриптор (phProcess). Если процесс не найден или произошла какая-либо другая ошибка, функция возвращает FALSE.

Демонстрация:

1695466139210.png
 
Автор темы Похожие темы Форум Ответы Дата
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 6
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 16
X-Shar Введение в разработку вредоносных программ 1
X-Shar Введение в разработку вредоносных программ 6
X-Shar Введение в разработку вредоносных программ 0
X-Shar Введение в разработку вредоносных программ 7
X-Shar Введение в разработку вредоносных программ 8
X-Shar Введение в разработку вредоносных программ 2
X-Shar Введение в разработку вредоносных программ 4
X-Shar Введение в разработку вредоносных программ 2
Похожие темы
Уроки Разработка вирусов-35.Обход EDRs.Последняя тема цикла
Уроки Разработка вирусов-34.Обход Windows defender
Уроки Разработка вирусов-33.Уменьшение вероятности детекта зверька
Уроки Разработка вирусов-32.Открываем врата ада
Уроки Разработка вирусов-31.Обход виртуальных машин
Уроки Разработка вирусов-30.Черпаем силы в антиотладке
Уроки Разработка вирусов-29. Предельная техника-2. Практика. Реализуем техники инъекции через сисколы
Уроки Разработка малвари-14. Размещаем Payload удаленно на сервере
Уроки Разработка малвари-13.Инъекция шелл-кода в процесс
Уроки Разработка малвари-12. Иньекция в процесс
Уроки Разработка малвари-11. Локальный запуск Payload
Уроки Разработка малвари-10. Обфускация Payload
Уроки Разработка малвари-9. Шифруем Payload
Уроки Разработка малвари-8. Куда класть нагрузку ?
Уроки Разработка малвари-7. Виды детектов
Уроки Разработка малвари-6. Процессы Windows
Уроки Разработка малвари - 5. Изучаем динамические библиотеки
Уроки Разработка малвари - 4. Шпаргалка по архитектуре винды
Уроки Разработка малвари - 3. Так какой-же язык выбрать !?
Уроки Разработка малвари - 2. Изучаем инструменты
Верх Низ