• XSS.stack #1 – первый литературный журнал от юзеров форума

Статья Рождение процесса. Часть 1

MonsterV2

Премиум
Premium
Регистрация
09.03.2025
Сообщения
59
Реакции
71
Гарант сделки
1
Депозит
13.2864 Ł
Автор: Achilles
Переведено и дополнено: MonsterV2

Данная статья представляет собой обзор механизмов создания процессов в Windows.

Windows API предоставляет различные способы создания процесса. Перед погружением в недры ядра, мы рассмотрим ключевые функции и структуры Win32 API:
  1. CreateProcessA/W — создаёт процесс от имени текущего пользователя
C++:
BOOL WINAPI CreateProcessA(
  LPCSTR                lpApplicationName,
  LPSTR                 lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL                  bInheritHandles,
  DWORD                 dwCreationFlags,
  LPVOID                lpEnvironment,
  LPCSTR                lpCurrentDirectory,
  LPSTARTUPINFOA        lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);
  1. CreateProcessAsUserA/W — создаёт процесс от имени заданного токена пользователя. Вызывающий CreateProcessAsUserA/W процесс должен иметь привилегию SE_INCREASE_QUOTA_NAME и привилегию SE_ASSIGNPRIMARYTOKEN_NAME, если токен не может быть присвоен.
C++:
BOOL WINAPI CreateProcessAsUserA(
  HANDLE                hToken,
  LPCSTR                lpApplicationName,
  LPSTR                 lpCommandLine,
  LPSECURITY_ATTRIBUTES lpProcessAttributes,
  LPSECURITY_ATTRIBUTES lpThreadAttributes,
  BOOL                  bInheritHandles,
  DWORD                 dwCreationFlags,
  LPVOID                lpEnvironment,
  LPCSTR                lpCurrentDirectory,
  LPSTARTUPINFOA        lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);
  1. CreateProcessWithTokenW — создаёт процесс в контексте безопасности указанного токена. Процесс, вызывающий CreateProcessWithTokenW, должен иметь привилегию SE_IMPERSONATE_NAME
C++:
BOOL WINAPI CreateProcessWithTokenW(
  HANDLE hToken,
  DWORD dwLogonFlags,
  LPCWSTR lpApplicationName,
  LPWSTR lpCommandLine,
  DWORD dwCreationFlags,
  LPVOID lpEnvironment,
  LPCWSTR lpCurrentDirectory,
  LPSTARTUPINFOW lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);
  1. CreateProcessWithLogonW — создаёт процесс и запускает исполняемый файл/пакетный файл/16-битное COM-приложение в контексте безопасности указанных учётных данных — пользователя, домена и пароля.
C++:
BOOL WINAPI CreateProcessWithLogonW(
  LPCWSTR               lpUsername,
  LPCWSTR               lpDomain,
  LPCWSTR               lpPassword,
  DWORD                 dwLogonFlags,
  LPCWSTR               lpApplicationName,
  LPWSTR                lpCommandLine,
  DWORD                 dwCreationFlags,
  LPVOID                lpEnvironment,
  LPCWSTR               lpCurrentDirectory,
  LPSTARTUPINFOW        lpStartupInfo,
  LPPROCESS_INFORMATION lpProcessInformation
);

Функции CreateProcessWithTokenW и CreateProcessWithLogonW находятся в Advapi32.dll и обе выполняют RPC запрос к службе Secondary Logon (seclogon.dll, хостящийся в svchost.exe) — эта служба позволяет запускать процессы с разными учётными данными пользователя. Далее SecLogon вызывает SlrCreateProcessWithLogon функцию, которая в конечном итоге вызывает CreateProcessAsUserW (см. картинку ниже).

123.png


  1. ShellExecuteA/W / ShellExecuteExA/W — запускают процесс на основе расширения файла, обращаясь к реестру. Функции принимают любой файл и пытаются найти исполняемый файл для запуска, просматривая соответствующее расширение файла в HKEY_CLASS_ROOT\* реестре.
C++:
HINSTANCE STDAPICALLTYPE ShellExecuteA(
  HWND   hwnd,
  LPCSTR lpOperation,
  LPCSTR lpFile,
  LPCSTR lpParameters,
  LPCSTR lpDirectory,
    INT    nShowCmd
);

ntdll.NtCreateUserProcess
kernelbase.CreateProcessInternalW
kernelbase.CreateProcessW
kernel32.CreateProcessWStub
windows.storage.private: long __cdecl CInvokeCreateProcessVerb::CallCreateProcess(void)
windows.storage.private: long __cdecl CInvokeCreateProcessVerb::_PrepareAndCallCreateProcess(void)
windows.storage.private: enum TRYRESULT __cdecl CInvokeCreateProcessVerb::_TryCreateProcess(void)
windows.storage.CInvokeCreateProcessVerb::Launch
windows.storage.public: virtual long __cdecl CInvokeCreateProcessVerb::Execute(void)
windows.storage.private: long __cdecl CBindAndInvokeStaticVerb::InitAndCallExecute(struct IExecuteCommand *, struct IShellItemArray *, bool)
windows.storage.CBindAndInvokeStaticVerb::tryCreateProcessDdeHandler
windows.storage.CBindAndInvokeStaticVerb::Execute
shell32.private: long __cdecl CShellExecute::_ExecuteAssoc(struct IAssociationArray *)
shell32.CShellExecute::_DoExecute
shell32.CShellExecute::ExecuteNormal
shell32.ShellExecuteNormal
shell32.ShellExecuteExW
shell32.ShellExecuteW

Все эти пути выполнения ведут к незадокументированной функции CreateProcessInternalW из Kernel32, которая выполняет начальную настройку для создания процесса Windows пользовательского режима и в конечном итоге вызывает функцию NtCreateUserProcess Ntdll.dll, которая через системный вызов совершит переход в режим ядра, где инициализация процесса продолжится внутри NtCreateUserProcess из NtOsKrnl.exe

C++:
// Не уверен, что это правильная сигнатура
// У меня в дизасме KernelBase.dll отсутствует последний аргумент `hRestrictedUserToken`
// Похоже, его убрали в новых версиях Windows...
BOOL WINAPI CreateProcessInternalW(
    HANDLE hUserToken,
    LPCWSTR lpApplicationName,
    LPWSTR lpCommandLine,
    LPSECURITY_ATTRIBUTES lpProcessAttributes,
    LPSECURITY_ATTRIBUTES lpThreadAttributes,
    BOOL bInheritHandles,
    DWORD dwCreationFlags,
    LPVOID lpEnvironment,
    LPCWSTR lpCurrentDirectory,
    LPSTARTUPINFOW lpStartupInfo,
    LPPROCESS_INFORMATION lpProcessInformation,
    PHANDLE hRestrictedUserToken
);

Аргументы CreateProcess*


Аргументы функций CreateProcess* могут включать дескриптор токена, учётные данные пользователя, путь к исполняемому файлу, аргументы командной строки, наследование дескриптора, флаги создания процесса, блок переменных среды, рабочая директория, указатели на структуры STARTUPINFO(EX)A/W и PROCESS_INFORMATION.

Флаги, затрагивающие создание процесса:​

  1. CREATE_SUSPENDED — создаёт главный поток нового процесса в приостановленном состоянии, поэтому нужно будет вызвать NtResumeThread для начала выполнения;
  2. DEBUG_PROCESS — вызывающий процесс объявляет себя отладчиком (да, детка!) и создаёт новый процесс под своим контролем;
  3. EXTENDED_STARTUPINFO_PRESENT — запуск с расширенной STARTUPINFOEX структурой вместо STARTUPINFO.

STARTUPINFO — предоставляет конфигурацию для создания процесса. EX-Версия содержит пары ключ/значение для атрибутов процесса и потока, заполненных через UpdateProcThreadAttributes;

PROCESS_INFORMATION — содержит новый уникальный PID, новый уникальный TID и дескрипторы нового процесса и главного потока.

Создание современных процессов Windows (UWP)


Создание современных процессов требует использования атрибута PROC_THREAD_ATTRIBUTE_PACKAGE_FULL_NAME. Также возможен запуск через COM-интерфейс IApplicationActivationManager, который реализуется классом COM с CLSID, названным CLSID_ApplicationAcitvationManger, с использованием ActivateApplication метода в этом интерфейсе

C++:
HRESULT STDMETHODCALLTYPE ActivateApplication(
  LPCWSTR         appUserModelId,
  LPCWSTR         arguments,
  ACTIVATEOPTIONS options,
  DWORD           *processId
);

Как насчёт Нативных, Минимальных и Pico процессов?


Нативные процессы нельзя создать через WinAPI — CreateProcessInternalW блокирует PE изображения с IMAGE_SUBSYSTEM_NATIVE значением в поле Subsystem внутри IMAGE_OPTIONAL_HEADER. Однако, можно воспользоваться RtlCreateUserProcess из ntdll.dll, которая являётся обёрткой над всё тем же сисколом NtCreateUserProcess.

C++:
/**
 * Creates a new process and its primary thread. The new process runs in the security context of the calling process.
 *
 * @param NtImagePathName The path of the image to be executed.
 * @param ExtendedParameters Reserved
 * @param ProcessParameters The process parameter information.
 * @param ProcessSecurityDescriptor The security descriptor for the new process. If NULL, the process gets a default security descriptor.
 * @param ThreadSecurityDescriptor The security descriptor for the initial thread. If NULL, the thread gets a default security descriptor.
 * @param ParentProcess The handle of a process to use (instead of the calling process) as the parent for the process being created.
 * @param InheritHandles If this parameter is TRUE, each inheritable handle in the calling process is inherited by the new process.
 * @param DebugPort The handle of an ALPC port for debug messages. If NULL, the process gets a default port. (WindowsErrorReportingServicePort)
 * @param TokenHandle The handle of a Token to use as the security context.
 * @param ProcessInformation The user process information.
 * @return NTSTATUS Successful or errant status.
 * @sa https://learn.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessw
 */
NTSYSAPI
NTSTATUS
NTAPI
RtlCreateUserProcess(
    _In_ PCUNICODE_STRING NtImagePathName,
    _In_ ULONG ExtendedParameters, // HIWORD(NumaNodeNumber), LOWORD(Reserved)
    _In_ PRTL_USER_PROCESS_PARAMETERS ProcessParameters,
    _In_opt_ PSECURITY_DESCRIPTOR ProcessSecurityDescriptor,
    _In_opt_ PSECURITY_DESCRIPTOR ThreadSecurityDescriptor,
    _In_opt_ HANDLE ParentProcess,
    _In_ BOOLEAN InheritHandles,
    _In_opt_ HANDLE DebugPort,
    _In_opt_ HANDLE TokenHandle, // used to be ExceptionPort
    _Out_ PRTL_USER_PROCESS_INFORMATION ProcessInformation
    );
// https://ntdoc.m417z.com/rtlcreateuserprocess

Windows также включает ряд процессов режима ядра, таких как процесс System, процесс Memory Compression, процесс Registry и Pico процессы для WSL (Спасибо! Microsoft :)). Создание таких процессов обеспечивается системным вызовом NtCreateProcessEx с определёнными возможностями для вызывающих из режима ядра.

PspCreatePicoProcess заботится как о создании минимального процесса, так и об инициализации контекста его поставщика Pico. Эта функция доступна лишь Pico провайдерам через специальный интерфейс

Внутренее устройство процессов


Каждый процесс Windows представлен структурой EPROCESS (e — executive). Потоки для этого процесса представлены структурой ETHREAD.

EPROCESS и большинство связанных с ним структур существуют в системном адресном пространстве, за исключением Process Environment Block (PEB), который существует в адресном пространстве процесса (пользователя). (*пытается найти базу kernel32, спасибо PEB) Для каждого процесса процесс подсистемы Windows (CSRSS) создает параллельную структуру, называемую CSR_PROCESS. Аналогично, часть режима ядра графической подсистемы Windows (Win32k.sys) поддерживает структуру данных для каждого процесса, W32PROCESS, которая создаётся в первый раз при обращении потока к графической подсистеме ядра через User32.dll или Gdi32.dll. Для каждого не простаивающего процесса каждая структура EPROCESS инкапсулируется как объект процесса диспетчером объектов.

Если вы хотите создать свои собственные структуры данных для отслеживания информации на основе каждого процесса. Это ваш выбор. PsSetCreateProcessNotifyRoutine(Ex, Ex2) даёт такую возможность, что хорошо документировано в WDK и часто применяется в различных антивирусных решениях.

Используйте команду dt nt!_EPROCESS для просмотра всех полей EPROCESS с помощью WinDbg.

3.png


Структура EPROCESS (Windows 10.17763.1098)
Process Control Block (первый член) — это структура типа KPROCESS для процесса ядра. Многие процедуры, хотя и являются частью структуры EPROCESS, но используют KPROCESS.

Используйте команду dt nt!_KPROCESS для просмотра всех полей KPROCESS с помощью WinDbg.

5.png


Структура KPROCESS (Windows 10.17763.1098)
PEB это структура, которая хранит часть данных из EPROCESS в пространство пользователя, а также содержит информацию, необходимую PE загрузчику, менеджеру кучи и другим компонентам Windows, и предоставляет к ней быстрый доступ без необходимости дёргать ядро.
34.png


Проверка PEB у explorer.exe
Структура CSR_PROCESS содержит информацию о процессах, специфичную для подсистемы Windows (CSRSS).

Структура W32PROCESS содержит всю информацию, необходимую коду графической подсистемы Windows в ядре (Win32k) для сохранения информации о состоянии GUI процессов.

Защищённые процессы


(Йоу, не трожь мою память)

Защищённые процессы могут быть созданы любым приложением только в том случае, если PE файл имеет цифровую подпись с использованием специального сертификата Windows Media.

Истоки модели защищённых процессов Windows (PP) восходят к Vista, где она была введена для защиты DRM процессов. Защищённая модель процессов была сильно ограничена, оставляя возможность загружать только те DLL, которые были установлены вместе с системой. Кроме того, для того, чтобы исполняемый файл считался пригодным для запуска защищённым, он должен быть подписан определённым сертификатом Microsoft, встроенным в двоичный файл. Одна из защит, которую обеспечивало ядро, заключается в том, что незащищённый процесс не мог открыть дескриптор защищённого процесса с достаточными правами для внедрения произвольного кода или чтения памяти.

*Нагло украдено отсюда: https://googleprojectzero.blogspot.com/2018/10/injecting-code-into-windows-protected.html

Несколько примеров защищённых процессов: Audio Device Graph (Audiodg.exe), Media Foundation Protected Pipeline (Mfpmp.exe), Windows Error Reporting Client Process (Werfaultsecure.exe).

Процесс System также защищён: несколько ключей шифрования, сгенерированных драйвером Ksecdd.sys, хранятся в его памяти пользовательского режима; также не стоит забывать, что память процесса System содержит все дескрипторы ядра в системе.

Защищённые процессы имеют специально установленный в их структуре EPROCESS бит ProtectedProcess, который изменяет поведение процедур, связанных с безопасностью, в диспетчере процессов, чтобы запретить определённые права доступа, которые обычно предоставляются администраторам. Единственные права доступа, предоставленные для защищённых процессов, это — PROCESS_QUERY/SET_LIMITED_INFORMATION, PROCESS_TERMINATE и PROCESS_SUSPEND_RESUME, что является первым шагом к изоляции защищённого процесса от доступа в пользовательском режиме.

«Облегчённые» защищённые процессы


Модель Protected Process Light (PPL) появилась в Windows 8.1 как расширение для PP: теперь у EPROCESS вместо бита ProtectedProcess целая структура весом аж в один байт — PS_PROTECTION. Разные сигнеры имеют разные уровни доверия, что, в свою очередь, приводит к тому, что некоторые PPL более или менее защищены, чем другие PPL. Обычно разрешены только маски доступа PROCESS_QUERY/SET_LIMITED_INFORMATION и PROCESS_SUSPEND_RESUME. PROCESS_TERMINATE не разрешён для определенных PPL сигнеров. WinSystem является сигнером с наивысшим приоритетом и используется для System процесса и его дочерних минимальных процессов, таких как Memory Compression и Registry. Для процессов пользовательского режима WinTCB является сигнером с наивысшим приоритетом и используется для защиты критических процессов: smss.exe, csrss.exe, wininit.exe и services.exe.

Что насчёт вредоносных процессов? Что мешает им заявлять, что они защищённый процесс, и, тем самым, защищать себя от антивирусов? Microsoft расширила свой модуль Code Integrity, чтобы распознавать два специальных продвинутых OID'а ключей, которые могут быть закодированы в цифровом сертификате подписи кода: 1.3.6.1.4.1.311.10.3.22 и 1.3.6.4.1.311.10.3.20. В случае, если один из этих EKU присутствует, жёстко закодированные строки Signer и Issuer в сертификате, объединённые с дополнительными возможными EKU, затем ассоциируются с различными значениями Protected Signer.

675.png


Сейчас PPL защищаются все работающие в пользовательском пространстве части антивирусных решений (Antimalware сигнер), а также несколько системных процессов: smss.exe, csrss.exe, wininit.exe, services.exe, ntoskrnl.exe (System) + его дочерние минимальные процессы (Memory Compression и Registry). Кстати, если установить в ключе реестра HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Lsa DWORD значение RunAsPPL в единичку, то после перезапуска процесс lsass.exe также будет запущен под PPL с уникальным сигнером Lsa.

Минимальные процессы


По сути, это закрытые контейнеры для системных приложений уровня ядра: для их создания необязателен исполняемый файл на диске, в них не мапятся KUSER_SHARED_DATA c HYPERVISOR_SHARED_DATA, у них пусто пространство пользовательского режима, ntdll.dll и kernel32.dll не загружаются по умолчанию, не создаётся PEB и связанные с ним структуры, не создаётся начальный поток, а минимальные потоки внутри таких процессов не имеют TEB по умолчанию. Эти процессы создаются через NtCreateProcessEx со специфичными флагами и управляются ядром, и ядро не предоставляет возможности создавать или управлять такими процессами из пользовательского режима, поскольку они предназначены не для пользователя, а для системы, чтоб выполнять специальные задачи. Внутри структуры EPROCESS минимального процесса выставлен флаг Minimal.

Примеры таких процессов: System, System Idle Process, Memory Compression, Registry.

C++:
// NtCreateProcessEx флаги с упоминанием минимальных процессов
#define PROCESS_CREATE_FLAGS_MINIMAL_PROCESS 0x00000800 // NtCreateProcessEx only
#define PROCESS_CREATE_FLAGS_CLONE_MINIMAL 0x00002000 // NtCreateProcessEx only
#define PROCESS_CREATE_FLAGS_CLONE_MINIMAL_REDUCED_COMMIT 0x00004000

68747470733a2f2f6d69726f2e6d656469756d2e636f6d2f76322f726573697a653a6669743a3634302f666f726d61...png


Pico процессы


Pico процессы это минимальные процессы с соответствующим Pico провайдером в виде драйвера режима ядра для управления пустым адресным пространством пользовательского режима. Pico процессы WSL поддерживаются драйверами Lxss.sys и LxCore.sys и позволяют имитировать поведение другого ядра ОС. Управление Pico процессами возможно через выделенные API, предоставляемые после регистрации провайдера.

Для поддержки существования Pico процесс должен присутствовать провайдер, который зарегистрирован через PsRegisterPicoProvider с определённым правилом: Pico провайдер должен быть загружен до загрузки любых других сторонних драйверов. Кроме того, эти основные драйверы должны быть подписаны с помощью сертификата подписчика Microsoft и Windows Component EKU.

Когда Pico провайдер вызывает API регистрации, он получает набор указателей на функций, который позволяет ему создавать и управлять процессами Pico:

• Функция для создания Pico процесса и функция для создания Pico потока.

• Одна функция для получения контекста Pico процесса, одна для его установки и ещё одна пара функций для выполнения того же самого для потоков Pico, таким образом заполняя PicoContext поле в ETHREAD или EPROCESS.

• Функция для получения структуры CPU контекста потока Pico и одна для её установки. Другая функция для изменения сегментов FS и/или GS потока Pico.

• Другие функции для завершения, приостановки, возобновления Pico процессов и их потоков.

68747470733a2f2f6d69726f2e6d656469756d2e636f6d2f76322f726573697a653a6669743a3634302f666f726d61...png


Trustlet процессы (Безопасные процессы)


Windows содержит новые функции безопасности на основе виртуализации, такие как: Device Guard и Credential Guard, работающие в новой среде изолированного режима пользователя (Isolated User Mode Environment), которая, хотя и остается непривилегированной (ring3), имеет виртуальный уровень доверия 1 (VTL 1), что обеспечивает ей защиту от обычного VTL 0, в котором работают как ядро NT (ring0), так и приложения (ring3).

Trustlet'ы это обычные PE файлы с несколькими специфичными для IUM свойствами:

• Ограничены в использовании системных вызовов и DLL.

• Импортируют специфичную для изолированного пользовательского режима системную DLL под названием Iumbase.dll, которая предоставляет API базовой системы IUM, содержащую поддержку почтовых ящиков, ящиков хранения, криптографии и т. д. Эта библиотека в конечном итоге вызывает Iumdll.dll, которая является VTL 1 версией Ntdll.dll, и содержит защищённые системные вызовы, реализованные защищённым ядром и не передающиеся в ядро Normal VTL 0.

• Содержит раздел PE с именем .tPolicy с экспортированной глобальной переменной с именем s_IumPolicyMetadata.

• Они подписаны сертификатом, содержащим EKU изолированного режима пользователя.

Вместо заключения


Это была первая часть обзора создания процессов в Windows. В следующей статье мы подробнее рассмотрим реализацию CreateProcess.

Источники:

  1. https://docs.microsoft.com/en-us/
  2. Windows Internals 7th Edition, Part 1
  3. 8.8.8.8
 


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх