Функция CreateProcessWithTokenW (winbase.h)
Создает новый процесс и его основной поток. Новый процесс выполняется в контексте безопасности указанного маркера. При необходимости можно загрузить профиль пользователя для указанного пользователя.
Процесс, вызывающий CreateProcessWithTokenW , должен иметь привилегию SE_IMPERSONATE_NAME. Если эта функция завершается сбоем с ERROR_PRIVILEGE_NOT_HELD (1314), используйте вместо нее функцию CreateProcessAsUser или CreateProcessWithLogonW . Как правило, процесс, который вызывает
CreateProcessAsUser должен иметь привилегию SE_INCREASE_QUOTA_NAME и может потребовать привилегию SE_ASSIGNPRIMARYTOKEN_NAME, если маркер не назначается. CreateProcessWithLogonW не требует особых привилегий, но для указанной учетной записи пользователя необходимо разрешить интерактивный вход. Как правило, лучше всего использовать CreateProcessWithLogonW для создания процесса с альтернативными учетными данными.
Синтаксис
BOOL CreateProcessWithTokenW(
[in] HANDLE hToken,
[in] DWORD dwLogonFlags,
[in, optional] LPCWSTR lpApplicationName,
[in, out, optional] LPWSTR lpCommandLine,
[in] DWORD dwCreationFlags,
[in, optional] LPVOID lpEnvironment,
[in, optional] LPCWSTR lpCurrentDirectory,
[in] LPSTARTUPINFOW lpStartupInfo,
[out] LPPROCESS_INFORMATION lpProcessInformation
);
Параметры
[in] hToken
Дескриптор первичного маркера, представляющего пользователя. Дескриптор должен иметь права доступа TOKEN_QUERY, TOKEN_DUPLICATE и TOKEN_ASSIGN_PRIMARY. Дополнительные сведения см. в разделе Права доступа для объектов Access-Token. Пользователь, представленный маркером, должен иметь доступ на чтение и выполнение приложения, указанного в параметре lpApplicationName или lpCommandLine .
Чтобы получить основной маркер, представляющий указанного пользователя, вызовите функцию LogonUser . Кроме того, можно вызвать функцию DuplicateTokenEx , чтобы преобразовать токен олицетворения в первичный. Это позволяет серверное приложение, олицетворяющее клиента, создать процесс, имеющий контекст безопасности клиента.
Службы терминалов: Процесс вызывающего объекта всегда выполняется в сеансе вызывающего объекта, а не в сеансе, указанном в токене. Чтобы запустить процесс в сеансе, указанном в маркере, используйте функцию CreateProcessAsUser.
[in] dwLogonFlags
Параметр входа. Этот параметр может быть равен нулю или одному из следующих значений.
[in, optional] lpApplicationName
Имя выполняемого модуля. Этот модуль может быть приложением на основе Windows. Это может быть другой тип модуля (например, MS-DOS или OS/2), если соответствующая подсистема доступна на локальном компьютере.
В строке можно указать полный путь и имя файла модуля для выполнения или указать частичное имя. В случае частичного имени функция использует текущий диск и текущий каталог для завершения спецификации. Функция не будет использовать путь поиска. Этот параметр должен включать расширение имени файла; расширение по умолчанию не предполагается.
Параметр lpApplicationName может иметь значение NULL. В этом случае имя модуля должно быть первым маркером с разделителями пробелами в строке lpCommandLine . Если вы используете длинное имя файла, содержащее пробел, используйте строки в кавычках, чтобы указать, где заканчивается имя файла и начинаются аргументы; В противном случае имя файла будет неоднозначным. Например, рассмотрим строку "c:\program files\sub dir\program name". Эту строку можно интерпретировать несколькими способами. Система пытается интерпретировать возможности в следующем порядке:
c:\program.exec:\program files\sub.exec:\program files\sub dir\program.exec:\program files\sub dir\program name.exe Если исполняемый модуль является 16-разрядным приложением, lpApplicationName должно иметь значение NULL, а строка, на которую указывает lpCommandLine , должна указывать исполняемый модуль и его аргументы.
[in, out, optional] lpCommandLine
Командная строка, выполняемая.
Максимальная длина этой строки составляет 1024 символа. Если lpApplicationName имеет значение NULL, часть имени модуля lpCommandLine ограничена MAX_PATH символами.
Функция может изменять содержимое этой строки. Поэтому этот параметр не может быть указателем на память, доступную только для чтения (например , переменную const или строку литерала). Если этот параметр является строкой константы, функция может вызвать нарушение доступа.
Параметр lpCommandLine может иметь значение NULL. В этом случае функция использует строку, на которую указывает lpApplicationName , в качестве командной строки.
Если значения lpApplicationName и lpCommandLine не имеют значения NULL, *lpApplicationName указывает модуль для выполнения, а *lpCommandLine — командную строку. Новый процесс может использовать GetCommandLine для получения всей командной строки. Консольные процессы, написанные на языке C, могут использовать аргументы argc и argv для анализа командной строки. Так как argv[0] — это имя модуля, программисты C обычно повторяют имя модуля в качестве первого маркера в командной строке.
Если lpApplicationName имеет значение NULL, первый маркер командной строки с разделителями пробелами указывает имя модуля. Если вы используете длинное имя файла, содержащее пробел, используйте строки в кавычках, чтобы указать, где заканчивается имя файла и начинаются аргументы (см. описание параметра lpApplicationName ). Если имя файла не содержит расширения, добавляется .exe. Поэтому, если расширение имени файла .com, этот параметр должен включать расширение .com. Если имя файла заканчивается точкой (.) без расширения или если имя файла содержит путь, .exe не добавляется. Если имя файла не содержит пути к каталогу, система выполняет поиск исполняемого файла в следующей последовательности:
- Каталог, из которого загружено приложение.
- Текущий каталог для родительского процесса.
- 32-разрядный системный каталог Windows. Используйте функцию GetSystemDirectory , чтобы получить путь к этому каталогу.
- 16-разрядный системный каталог Windows. Нет функции, которая получает путь к этому каталогу, но выполняется поиск.
- Каталог Windows. Используйте функцию GetWindowsDirectory , чтобы получить путь к этому каталогу.
- Каталоги, перечисленные в переменной среды PATH. Обратите внимание, что эта функция не выполняет поиск по пути для каждого приложения, указанному в разделе реестра Пути приложений . Чтобы включить этот путь для каждого приложения в последовательность поиска, используйте функцию ShellExecute .
[in] dwCreationFlags
Флаги, управляющие способом создания процесса. Флаги CREATE_DEFAULT_ERROR_MODE, CREATE_NEW_CONSOLE и CREATE_NEW_PROCESS_GROUP включены по умолчанию. Список значений см. в разделе Флаги создания процесса.
Этот параметр также управляет классом приоритета нового процесса, который используется для определения приоритетов планирования потоков процесса. Список значений см. в разделе GetPriorityClass. Если ни один из флагов класса приоритета не указан, класс приоритета по умолчанию NORMAL_PRIORITY_CLASS, если класс приоритета процесса создания не IDLE_PRIORITY_CLASS или BELOW_NORMAL_PRIORITY_CLASS. В этом случае дочерний процесс получает класс приоритета по умолчанию вызывающего процесса.
Если параметр dwCreationFlags имеет значение 0:
- Процесс получает режим ошибок по умолчанию, создает новую консоль и группу процессов.
- Предполагается, что блок среды для нового процесса содержит символы ANSI (дополнительные сведения см. в разделе параметр lpEnvironment ).
- 16-разрядное приложение windows выполняется на общей виртуальной машине DOS (VDM).
[in, optional] lpEnvironment
Указатель на блок среды для нового процесса. Если этот параметр имеет значение NULL, новый процесс использует среду, созданную из профиля пользователя, указанного в параметре lpUsername.
Блок среды состоит из блока строк, завершаемых значением NULL. Каждая строка имеет следующий вид:
Имя=Значение
Поскольку знак равенства (=) используется в качестве разделителя, его не следует использовать в имени переменной среды.
Блок среды может содержать символы Юникода или ANSI. Если блок среды, на который указывает lpEnvironment , содержит символы Юникода, убедитесь, что dwCreationFlags содержит CREATE_UNICODE_ENVIRONMENT.
Блок среды ANSI завершается двумя нулевыми байтами: один для последней строки, еще один для завершения блока. Блок среды Юникод завершается четырьмя нулевыми байтами: два для последней строки и еще два для завершения блока.
Чтобы получить копию блока среды для конкретного пользователя, используйте функцию CreateEnvironmentBlock .
[in, optional] lpCurrentDirectory
Полный путь к текущему каталогу для процесса. Строка также может указывать UNC-путь.
Если этот параметр имеет значение NULL, новый процесс будет иметь тот же текущий диск и каталог, что и вызывающий процесс. (Эта функция предоставляется в основном для оболочек, которым необходимо запустить приложение и указать его начальный диск и рабочий каталог.)
[in] lpStartupInfo
Указатель на структуру STARTUPINFO или STARTUPINFOEX .
Если элемент lpDesktop имеет значение NULL или пустую строку, новый процесс наследует станцию рабочего стола и окна родительского процесса. Функция добавляет разрешение для указанной учетной записи пользователя к унаследованной оконной станции и рабочему столу. В противном случае, если этот элемент указывает рабочий стол, приложение должно добавить разрешение для указанной учетной записи пользователя на указанную оконную станцию и рабочий стол, даже для WinSta0\Default.
Дескрипторы в STARTUPINFO или STARTUPINFOEX должны закрываться с помощью CloseHandle , если они больше не нужны.
[out] lpProcessInformation
Указатель на структуру PROCESS_INFORMATION , которая получает идентификационные сведения для нового процесса, включая дескриптор процесса.
Дескрипторы в PROCESS_INFORMATION должны быть закрыты с помощью функции CloseHandle , если они больше не нужны.
Возвращаемое значение
Если функция выполняется успешно, возвращается ненулевое значение.
Если функция выполняется неудачно, возвращается нулевое значение. Дополнительные сведения об ошибке можно получить, вызвав GetLastError.
Обратите внимание, что функция возвращается до завершения инициализации процесса. Если не удается найти необходимую библиотеку DLL или не удается инициализировать, процесс завершается. Чтобы получить состояние завершения процесса, вызовите Метод GetExitCodeProcess.
Комментарии
По умолчанию CreateProcessWithTokenW не загружает профиль указанного пользователя в раздел реестра HKEY_USERS . Это означает, что доступ к сведениям в разделе реестра HKEY_CURRENT_USER может не привести к результатам, соответствующим обычному интерактивному входу в систему. Вы несете ответственность за загрузку куста реестра пользователя в HKEY_USERS с помощью LOGON_WITH_PROFILE или вызова функции LoadUserProfile перед вызовом этой функции.
Если параметр lpEnvironment имеет значение NULL, новый процесс использует блок среды, созданный из профиля пользователя, указанного в lpUserName. Если переменные HOMEDRIVE и HOMEPATH не заданы, CreateProcessWithTokenW изменяет блок среды, используя диск и путь к рабочему каталогу пользователя.
При создании новые дескрипторы процессов и потоков получают права полного доступа (PROCESS_ALL_ACCESS и THREAD_ALL_ACCESS). Если дескриптор безопасности не указан, дескриптор может использоваться в любой функции, требующей дескриптора объекта этого типа. При указании дескриптора безопасности перед предоставлением доступа выполняется проверка доступа ко всем последующим использованию дескриптора. Если доступ запрещен, запрашивающий процесс не может использовать дескриптор для получения доступа к процессу или потоку.
Чтобы получить маркер безопасности, передайте дескриптор процесса в структуре PROCESS_INFORMATION в функцию OpenProcessToken .
Процессу назначается идентификатор процесса. Идентификатор действителен до завершения процесса. Его можно использовать для идентификации процесса или указать в функции OpenProcess , чтобы открыть дескриптор процесса. Начальному потоку в процессе также назначается идентификатор потока. Его можно указать в функции OpenThread , чтобы открыть дескриптор потока. Идентификатор действителен до завершения потока и может использоваться для уникальной идентификации потока в системе. Эти идентификаторы возвращаются в PROCESS_INFORMATION.
Вызывающий поток может использовать функцию WaitForInputIdle , чтобы дождаться завершения инициализации нового процесса и ожидать ввода данных пользователем без ожидания ввода. Это может быть полезно для синхронизации между родительским и дочерним процессами, так как createProcessWithTokenW возвращает значение , не дожидаясь завершения инициализации нового процесса. Например, процесс создания будет использовать WaitForInputIdle перед попыткой найти окно, связанное с новым процессом.
Предпочтительным способом завершения процесса является использование функции ExitProcess , так как эта функция отправляет уведомление о приближении завершения во все библиотеки DLL, присоединенные к процессу. Другие средства завершения процесса не уведомляют подключенные библиотеки DLL. Обратите внимание, что когда поток вызывает ExitProcess, другие потоки процесса завершаются без возможности выполнения дополнительного кода (включая код завершения потока присоединенных библиотек DLL). Дополнительные сведения см. в разделе Прекращение процесса.
Чтобы скомпилировать приложение, использующее эту функцию, определите _WIN32_WINNT как 0x0500 или более поздней версии. Дополнительные сведения см. в разделе Использование заголовков Windows.
Примечания по безопасности
Параметр lpApplicationName может иметь значение NULL. В этом случае имя исполняемого файла должно быть первой строкой с разделителями пробелами в lpCommandLine. Если в имени исполняемого файла или пути есть пробел, существует риск запуска другого исполняемого файла из-за того, как функция анализирует пробелы. Следующий пример опасен тем, что функция попытается запустить "Program.exe", если она существует, а не "MyApp.exe". LPTSTR szCmdline = L"C:\\Program Files\\MyApp";
CreateProcessWithTokenW(/*...*/, szCmdline, /*...*/);
Если злоумышленник создает в системе приложение с именем "Program.exe", любая программа, которая неправильно вызывает CreateProcessWithTokenW с помощью каталога Program Files, запустит это приложение вместо предполагаемого приложения.
Чтобы избежать этой проблемы, не передайте значение NULL для lpApplicationName. Если для lpApplicationName задано значение NULL, используйте в lpCommandLine путь к исполняемому файлу в кавычках, как показано в примере ниже.
LPTSTR szCmdline = L"\"C:\\Program Files\\MyApp\"";
CreateProcessWithTokenW(/*...*/, szCmdline, /*...*/);
Требования
Требование | Значение |
---|---|
Минимальная версия клиента | Windows Vista [только классические приложения] |
Минимальная версия сервера | Windows Server 2003 [только классические приложения] |
Целевая платформа | Windows |
Header | winbase.h (включая Windows.h) |
Библиотека | Advapi32.lib |
DLL | Advapi32.dll |