Как создать процесс из приложения, использующего Native API
При разработке приложений Native API может возникнуть необходимость запустить процесс. В native режиме невозможен запуск Win32-приложений, так как процессы подсистемы Win32 при создании требуют уведомления CSRSS о новом процессе (а он ещё неактивен). Зато в native режиме возможен запуск других native приложений с помощью функции RtlCreateUserProcess.
В параметрах функции нужно в соответствующих структурах передать
полный путь к исполняемому файлу, причём в NT-формате (то есть с префиксом \??\),
имя файла процесса для отображения в списке процессов и командную строку с параметрами (это строка,
которой был запущен процесс, содержащая его ключи запуска).
Например, запускаем процесс autochk.exe с параметрами, находясь в каталоге C:\windows\system32. Тогда в RtlCreateUserProcess нужно будет передать следующие строки:
- Имя файла для отображения в списке процессов: autochk.exe
- Командная строка: autochk.exe /p \??\C:
- Полный путь: \??\C:\windows\system32\autochk.exe
На снимке экрана вы видите программу проверки диска autochk.exe, запущенную из Native shell. При попытке запустить не native, а Win32 приложение из Native shell произойдёт ошибка и вы увидите синий экран смерти с текстом STOP c0000145. Это происходит потому, что функция CreateNativeProcess в Native shell не проверяет подсистему запускаемого исполняемого файла. Запускать следует либо собственные native приложения, либо native приложения, идущие в комплекте Windows, такие как autocheck.exe, autoconv.exe, autofmt.exe, autolfn.exe. В Native режиме уже запущен smss.exe, можно попытаться запустить его вторую копию, но результат подобного действия непредсказуем!
Существует и более сложный в реализации способ запуска процессов с использованием Native API, описанный на сайте http://ntprog.by.ru/_process.htm. Там есть описания проверки подсистемы и нотификации CSRSS для запуска приложений Win32. Это может пригодиться в случае запуска процесса не в Native режиме, а в обычном режиме работы Windows. Консольная программа nrun.exe от Andrey Shedel реализует запуск native приложений из командной строки обычного режима Windows.
Следующий кусок кода реализует запуск процесса в моей программе Native shell версии 0.10. Для приведения пути в NT-формат используется функция RtlDosPathNameToNtPathName_U. Инициализация параметров процесса происходит с помощью функции RtlCreateProcessParameters.
Текст функции
NTSTATUS
CreateNativeProcess(IN PCWSTR file_name, IN PCWSTR cmd_line)
{
PCWSTR file_part;
UNICODE_STRING fname, nt_file, EnvString,
NullString, UnicodeSystemDriveString;
NTSTATUS status;
// Имя исполняемого файла
UNICODE_STRING imgname;
// Путь к исполняемому файлу в NT-формате
UNICODE_STRING imgpath;
// Путь, где располагаются библиотеки в формате DOS
UNICODE_STRING dllpath;
// Командная строка
UNICODE_STRING cmdline;
// Параметры процесса
PRTL_USER_PROCESS_PARAMETERS processparameters;
// Информация о процессе
RTL_USER_PROCESS_INFORMATION
processinformation = {0};
WCHAR Env[2] = {0, 0}; // Окружение процесса
PKUSER_SHARED_DATA SharedData
= (PKUSER_SHARED_DATA)USER_SHARED_DATA; // Данные ядра
// Преобразование пути в NT-формат (прибавление префикса \??\)
RtlDosPathNameToNtPathName_U(
file_name, &nt_file, &file_part, NULL);
RtlInitUnicodeString(&imgpath, nt_file.Buffer);
RtlInitUnicodeString(&imgname, file_part);
// %SystemRoot%
RtlInitUnicodeString(&dllpath, SharedData->NtSystemRoot);
// Параметры командной строки
RtlInitUnicodeString(&cmdline, cmd_line);
// Инициализация параметров процесса
status = RtlCreateProcessParameters(
&processparameters, &imgname,
&dllpath, &dllpath, &cmdline, Env, 0, 0, 0, 0);
if (!NT_SUCCESS(status))
{
RtlCliDisplayString("RtlCreateProcessParameters failed\n");
return FALSE;
}
DbgPrint("Launching Process: %s, DllPath=%s, CmdLine=%s",
&imgname, &dllpath, &cmdline);
// Здесь происходит непосредственно запуск процесса
status = RtlCreateUserProcess(&imgpath, OBJ_CASE_INSENSITIVE,
processparameters, NULL, NULL, NULL, FALSE,
NULL, NULL, &processinformation );
if (!NT_SUCCESS(status))
{
RtlCliDisplayString("RtlCreateUserProcess failed\n");
return FALSE;
}
status = NtResumeThread(processinformation.ThreadHandle, NULL);
if (!NT_SUCCESS(status))
{
RtlCliDisplayString("NtResumeThread failed\n");
return FALSE;
}
return STATUS_SUCCESS;
}
Автор: амдф
Дата: 25 января 2011
Избранное
Остальное
По вопросам сотрудничества и другим вопросам по работе сайта пишите на cleogroup[собака]yandex.ru