Поделиться через


Функция CreateProcessAsUserA (processthreadsapi.h)

Создает новый процесс и его основной поток. Новый процесс выполняется в контексте безопасности пользователя, представленного указанным маркером.

Как правило, процесс, вызывающий функцию CreateProcessAsUser , должен иметь привилегию SE_INCREASE_QUOTA_NAME и может требовать права SE_ASSIGNPRIMARYTOKEN_NAME , если маркер не может быть назначен. Если эта функция завершается сбоем с ERROR_PRIVILEGE_NOT_HELD (1314), используйте вместо нее функцию CreateProcessWithLogonW . Для CreateProcessWithLogonW не требуются специальные привилегии, но указанная учетная запись пользователя должна иметь возможность интерактивного входа. Как правило, для создания процесса с альтернативными учетными данными лучше всего использовать CreateProcessWithLogonW .

Синтаксис

BOOL CreateProcessAsUserA(
  [in, optional]      HANDLE                hToken,
  [in, optional]      LPCSTR                lpApplicationName,
  [in, out, optional] LPSTR                 lpCommandLine,
  [in, optional]      LPSECURITY_ATTRIBUTES lpProcessAttributes,
  [in, optional]      LPSECURITY_ATTRIBUTES lpThreadAttributes,
  [in]                BOOL                  bInheritHandles,
  [in]                DWORD                 dwCreationFlags,
  [in, optional]      LPVOID                lpEnvironment,
  [in, optional]      LPCSTR                lpCurrentDirectory,
  [in]                LPSTARTUPINFOA        lpStartupInfo,
  [out]               LPPROCESS_INFORMATION lpProcessInformation
);

Параметры

[in, optional] hToken

Дескриптор основного маркера, представляющего пользователя. Дескриптор должен иметь права доступа TOKEN_QUERY, TOKEN_DUPLICATE и TOKEN_ASSIGN_PRIMARY . Дополнительные сведения см. в разделе Права доступа к объектам Access-Token. Пользователь, представленный маркером, должен иметь доступ на чтение и выполнение приложения, указанного в параметре lpApplicationName или lpCommandLine .

Чтобы получить основной маркер, представляющий указанного пользователя, вызовите функцию LogonUser . Кроме того, можно вызвать функцию DuplicateTokenEx для преобразования токена олицетворения в первичный. Это позволяет серверным приложениям, олицетворяющим клиента, создать процесс, имеющий контекст безопасности клиента.

Если hToken является ограниченной версией основного маркера вызывающего объекта, привилегия SE_ASSIGNPRIMARYTOKEN_NAME не требуется. Если необходимые привилегии еще не включены, CreateProcessAsUser включает их на время вызова. Дополнительные сведения см. в разделе Выполнение с особыми привилегиями.

Службы терминалов: Процесс выполняется в сеансе, указанном в маркере. По умолчанию это тот же сеанс, который называется LogonUser. Чтобы изменить сеанс, используйте функцию SetTokenInformation .

[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 , должна указывать исполняемый модуль, а также его аргументы. По умолчанию все 16-разрядные приложения на базе Windows, созданные командой CreateProcessAsUser , выполняются в отдельном VDM ( эквивалентном CREATE_SEPARATE_WOW_VDM в CreateProcess).

[in, out, optional] lpCommandLine

Командная строка для выполнения. Максимальная длина этой строки составляет 32 КБ символов. Если lpApplicationName имеет значение NULL, часть имени модуля в lpCommandLine ограничена MAX_PATH символами.

Версия Этой функции в Юникоде , CreateProcessAsUserW, может изменять содержимое этой строки. Таким образом, этот параметр не может быть указателем на память только для чтения (например , переменную const или литеральную строку). Если этот параметр является константной строкой, функция может привести к нарушению доступа.

Параметр lpCommandLine может иметь значение NULL. В этом случае функция использует строку, на которую указывает lpApplicationName , в качестве командной строки.

Если значения lpApplicationName и lpCommandLine не имеют значения NULL, *lpApplicationName указывает модуль для выполнения, а *lpCommandLine — командную строку. Новый процесс может использовать GetCommandLine для получения всей командной строки. Консольные процессы, написанные на языке C, могут использовать аргументы argc и argv для анализа командной строки. Так как argv[0] — это имя модуля, программисты C обычно повторяют имя модуля в качестве первого маркера в командной строке.

Если lpApplicationName имеет значение NULL, первый маркер командной строки с разделителями пробелами указывает имя модуля. Если вы используете длинное имя файла, содержащее пробел, используйте строки в кавычках, чтобы указать, где заканчивается имя файла и начинаются аргументы (см. описание параметра lpApplicationName ). Если имя файла не содержит расширения, добавляется .exe. Поэтому, если расширение имени файла является .com, этот параметр должен включать расширение .com. Если имя файла заканчивается точкой (.) без расширения или если имя файла содержит путь, .exe не добавляется. Если имя файла не содержит путь к каталогу, система ищет исполняемый файл в следующей последовательности:

  1. Каталог, из которого загружено приложение.
  2. Текущий каталог для родительского процесса.
  3. 32-разрядный системный каталог Windows. Используйте функцию GetSystemDirectory , чтобы получить путь к этому каталогу.
  4. 16-разрядный системный каталог Windows. Нет функции, которая получает путь к этому каталогу, но выполняется поиск.
  5. Каталог Windows. Используйте функцию GetWindowsDirectory , чтобы получить путь к этому каталогу.
  6. Каталоги, перечисленные в переменной среды PATH. Обратите внимание, что эта функция не выполняет поиск по пути для каждого приложения, указанному в разделе реестра Пути приложений . Чтобы включить этот путь для каждого приложения в последовательность поиска, используйте функцию ShellExecute .
Система добавляет в строку командной строки пустой символ, чтобы отделить имя файла от аргументов. При этом исходная строка делится на две строки для внутренней обработки.

[in, optional] lpProcessAttributes

Указатель на структуру SECURITY_ATTRIBUTES , которая задает дескриптор безопасности для нового объекта процесса и определяет, могут ли дочерние процессы наследовать возвращенный дескриптор процессу. Если lpProcessAttributes имеет значение NULL или lpSecurityDescriptor имеет значение NULL, процесс получает дескриптор безопасности по умолчанию и дескриптор не может быть унаследован. Дескриптор безопасности по умолчанию — это дескриптор пользователя, на который ссылается параметр hToken . Этот дескриптор безопасности может не разрешать доступ вызывающему объекту. В этом случае процесс может быть не открыт снова после его запуска. Дескриптор процесса действителен и будет по-прежнему иметь полные права доступа.

[in, optional] lpThreadAttributes

Указатель на структуру SECURITY_ATTRIBUTES , которая задает дескриптор безопасности для нового объекта потока и определяет, могут ли дочерние процессы наследовать возвращенный дескриптор в поток. Если lpThreadAttributes имеет значение NULL или lpSecurityDescriptor имеет значение NULL, поток получает дескриптор безопасности по умолчанию и дескриптор не может быть унаследован. Дескриптор безопасности по умолчанию — это дескриптор пользователя, на который ссылается параметр hToken . Этот дескриптор безопасности может не разрешать доступ для вызывающего объекта.

[in] bInheritHandles

Если этот параметр имеет значение TRUE, каждый наследуемый дескриптор в вызывающем процессе наследуется новым процессом. Если параметр имеет значение FALSE, дескрипторы не наследуются. Обратите внимание, что унаследованные дескрипторы имеют те же значения и права доступа, что и исходные дескрипторы. Дополнительные сведения о наследуемых дескрипторов см. в разделе Примечания.

Службы терминалов: Нельзя наследовать дескрипторы между сеансами. Кроме того, если этот параметр имеет значение TRUE, необходимо создать процесс в том же сеансе, что и вызывающий объект.

Процессы защищенного освещения процессов (PPL): Наследование универсального дескриптора блокируется, когда процесс PPL создает процесс, отличный от PPL, так как PROCESS_DUP_HANDLE не допускается из процесса, отличного от PPL, в процесс PPL. См . раздел Управление безопасностью и правами доступа.

[in] dwCreationFlags

Флаги, управляющие классом приоритета и созданием процесса. Список значений см. в разделе Флаги создания процесса.

Этот параметр также управляет классом приоритета нового процесса, который используется для определения приоритетов планирования потоков процесса. Список значений см. в разделе GetPriorityClass. Если ни один из флагов класса приоритета не указан, класс приоритета по умолчанию NORMAL_PRIORITY_CLASS , если класс приоритета процесса создания не является IDLE_PRIORITY_CLASS или BELOW_NORMAL_PRIORITY_CLASS. В этом случае дочерний процесс получает класс приоритета по умолчанию для вызывающего процесса.

Если параметр dwCreationFlags имеет значение 0:

  • Процесс наследует режим ошибки вызывающего объекта и родительской консоли.
  • Предполагается, что блок среды для нового процесса содержит символы ANSI (дополнительные сведения см. в разделе параметр lpEnvironment ).
  • 16-разрядное приложение на основе Windows выполняется на общей виртуальной машине DOS (VDM).

[in, optional] lpEnvironment

Указатель на блок среды для нового процесса. Если этот параметр имеет значение NULL, новый процесс использует среду вызывающего процесса.

Блок среды состоит из блока строк, завершаемых значением NULL. Каждая строка имеет следующий вид:

Имя=value\0

Так как знак равенства используется в качестве разделителя, его нельзя использовать в имени переменной среды.

Блок среды может содержать символы Юникода или ANSI. Если блок среды, на который указывает lpEnvironment , содержит символы Юникода, убедитесь, что dwCreationFlags содержит CREATE_UNICODE_ENVIRONMENT.

Версия ANSI этой функции CreateProcessAsUserA завершается ошибкой , если общий размер блока среды для процесса превышает 32 767 символов.

Обратите внимание, что блок среды ANSI завершается двумя нулевыми байтами: один для последней строки, еще один для завершения блока. Блок среды Юникода завершается четырьмя нулевыми байтами: два для последней строки, еще два для завершения блока.

Windows Server 2003 и Windows XP: Если размер объединенной пользовательской и системной переменной среды превышает 8192 байта, процесс, созданный CreateProcessAsUser , больше не выполняется с блоком среды, переданным в функцию родительским процессом. Вместо этого дочерний процесс выполняется с блоком среды, возвращенным функцией CreateEnvironmentBlock .

Чтобы получить копию блока среды для данного пользователя, используйте функцию CreateEnvironmentBlock .

[in, optional] lpCurrentDirectory

Полный путь к текущему каталогу для процесса. В строке также можно указать UNC-путь.

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

[in] lpStartupInfo

Указатель на структуру STARTUPINFO или STARTUPINFOEX .

Пользователь должен иметь полный доступ как к указанной оконной станции, так и к рабочему столу. Если вы хотите, чтобы процесс был интерактивным, укажите winsta0\default. Если член lpDesktop имеет значение NULL, новый процесс наследует станцию рабочего стола и окна родительского процесса. Если этот элемент является пустой строкой "", новый процесс подключается к оконной станции с помощью правил, описанных в разделе Подключение процесса к оконной станции.

Чтобы задать расширенные атрибуты, используйте структуру STARTUPINFOEX и укажите EXTENDED_STARTUPINFO_PRESENT в параметре dwCreationFlags .

Дескрипторы в STARTUPINFO или STARTUPINFOEX должны быть закрыты с помощью CloseHandle , если они больше не нужны.

Важно Вызывающий объект отвечает за то, чтобы стандартные поля дескрипторов в STARTUPINFO содержали допустимые значения дескрипторов. Эти поля копируются без изменений в дочерний процесс без проверки, даже если член dwFlags указывает STARTF_USESTDHANDLES. Неправильные значения могут привести к неправильному поведению дочернего процесса или аварийному завершению. Используйте средство проверки среды выполнения Проверки приложений для обнаружения недопустимых дескрипторов.
 

[out] lpProcessInformation

Указатель на структуру PROCESS_INFORMATION , получающую идентификационные сведения о новом процессе.

Маркеры в PROCESS_INFORMATION должны быть закрыты с помощью CloseHandle , если они больше не нужны.

Возвращаемое значение

Если функция выполняется успешно, возвращается ненулевое значение.

Если функция выполняется неудачно, возвращается нулевое значение. Дополнительные сведения об ошибке можно получить, вызвав GetLastError.

Обратите внимание, что функция возвращается до завершения инициализации процесса. Если не удается найти необходимую библиотеку DLL или не удается инициализировать, процесс завершается. Чтобы получить состояние завершения процесса, вызовите Метод GetExitCodeProcess.

Комментарии

CreateProcessAsUser должен иметь возможность открыть основной маркер вызывающего процесса с TOKEN_DUPLICATE и TOKEN_IMPERSONATE права доступа.

По умолчанию CreateProcessAsUser создает новый процесс на неинтерактивной оконной станции с рабочим столом, который не отображается и не может принимать входные данные пользователем. Чтобы включить взаимодействие пользователя с новым процессом, необходимо указать имя станции интерактивного окна и рабочего стола по умолчанию winsta0\default в элементе lpDesktop структуры STARTUPINFO . Кроме того, перед вызовом CreateProcessAsUser необходимо изменить список управления доступом (DACL) как станции интерактивного окна по умолчанию, так и рабочего стола по умолчанию. Списки DACLs для оконной станции и рабочего стола должны предоставлять доступ пользователю или сеансу входа в систему, представленным параметром hToken .

CreateProcessAsUser не загружает профиль указанного пользователя в раздел реестра HKEY_USERS . Поэтому для доступа к сведениям в разделе реестра HKEY_CURRENT_USER необходимо загрузить данные профиля пользователя в HKEY_USERS с помощью функции LoadUserProfile перед вызовом CreateProcessAsUser. Не забудьте вызвать UnloadUserProfile после завершения нового процесса.

Если параметр lpEnvironment имеет значение NULL, новый процесс наследует среду вызывающего процесса. CreateProcessAsUser не изменяет блок среды автоматически, чтобы включить переменные среды, относящиеся к пользователю, представленному hToken. Например, переменные USERNAME и USERDOMAIN наследуются от процесса вызова, если lpEnvironment имеет значение NULL. Вы несете ответственность за подготовку блока среды для нового процесса и его указание в lpEnvironment.

Функции CreateProcessWithLogonW и CreateProcessWithTokenW похожи на CreateProcessAsUser, за исключением того, что вызывающей функции не требуется вызывать функцию LogonUser для проверки подлинности пользователя и получения маркера.

CreateProcessAsUser позволяет получить доступ к указанному каталогу и исполняемому образу в контексте безопасности вызывающего объекта или целевого пользователя. По умолчанию CreateProcessAsUser обращается к каталогу и исполняемому образу в контексте безопасности вызывающего объекта. В этом случае, если вызывающий объект не имеет доступа к каталогу и исполняемому образу, функция завершается ошибкой. Чтобы получить доступ к каталогу и исполняемому образу с помощью контекста безопасности целевого пользователя, укажите hToken в вызове функции ImpersonateLoggedOnUser перед вызовом CreateProcessAsUser.

Процессу назначается идентификатор процесса. Идентификатор действителен до завершения процесса. Его можно использовать для идентификации процесса или указать в функции OpenProcess , чтобы открыть дескриптор процесса. Начальному потоку в процессе также назначается идентификатор потока. Его можно указать в функции OpenThread , чтобы открыть дескриптор потока. Идентификатор действителен до завершения потока и может использоваться для уникальной идентификации потока в системе. Эти идентификаторы возвращаются в структуре PROCESS_INFORMATION .

Вызывающий поток может использовать функцию WaitForInputIdle , чтобы дождаться завершения инициализации нового процесса и ожидать ввода данных пользователем без ожидания ввода. Это может быть полезно для синхронизации между родительским и дочерним процессами, так как Функция CreateProcessAsUser возвращается без ожидания завершения инициализации нового процесса. Например, процесс создания будет использовать WaitForInputIdle перед попыткой найти окно, связанное с новым процессом.

Предпочтительным способом завершения процесса является использование функции ExitProcess , так как эта функция отправляет уведомление о приближении завершения во все библиотеки DLL, присоединенные к процессу. Другие средства завершения процесса не уведомляют подключенные библиотеки DLL. Обратите внимание, что, когда поток вызывает ExitProcess, другие потоки процесса завершаются без возможности выполнить какой-либо дополнительный код (включая код завершения потока присоединенных библиотек DLL). Дополнительные сведения см. в разделе Завершение процесса.

По умолчанию передача TRUE в качестве значения параметра bInheritHandles приводит к тому, что новый процесс наследует все наследуемые дескрипторы. Это может быть проблемой для приложений, которые создают процессы из нескольких потоков одновременно, но хотят, чтобы каждый процесс наследовал разные дескрипторы. Приложения могут использовать функцию UpdateProcThreadAttributeList с параметром PROC_THREAD_ATTRIBUTE_HANDLE_LIST для предоставления списка дескрипторов, наследуемых определенным процессом.

Замечания по безопасности

Параметр lpApplicationName может иметь значение NULL. В этом случае исполняемое имя должно быть первой строкой с разделителями пробелами в lpCommandLine. Если в имени исполняемого файла или пути есть пробел, существует риск запуска другого исполняемого файла из-за того, как функция анализирует пробелы. Следующий пример опасен тем, что функция попытается выполнить "Program.exe", если она существует, а не "MyApp.exe".
	LPTSTR szCmdline[] = _tcsdup(TEXT("C:\\Program Files\\MyApp"));
	CreateProcessAsUser(hToken, NULL, szCmdline, /*...*/ );

Если злоумышленник создает в системе приложение с именем "Program.exe", любая программа, которая неправильно вызывает CreateProcessAsUser с помощью каталога Program Files, будет запускать это приложение вместо предполагаемого приложения.

Чтобы избежать этой проблемы, не передайте значение NULL для lpApplicationName. Если вы передаете значение NULL для lpApplicationName, используйте кавычки вокруг пути к исполняемому файлу в lpCommandLine, как показано в примере ниже.

	LPTSTR szCmdline[] = _tcsdup(TEXT("\"C:\\Program Files\\MyApp\""));
	CreateProcessAsUser(hToken, NULL, szCmdline, /*...*/);

Powershell: Если функция CreateProcessAsUser используется для реализации командлета в PowerShell версии 2.0, командлет правильно работает как для удаленных сеансов развертывания, так и для удаленных сеансов развертывания. Однако из-за определенных сценариев безопасности командлет, реализованный с помощью CreateProcessAsUser , правильно работает только в PowerShell версии 3.0 для удаленных сеансов с вентилятором. Развертывание удаленных сеансов завершится сбоем из-за недостаточных привилегий безопасности клиента. Чтобы реализовать командлет, который работает как для удаленных сеансов в размноженных, так и для удаленных сеансов в PowerShell версии 3.0, используйте функцию CreateProcess .

Примеры

Пример см. в разделе Запуск интерактивного клиентского процесса.

Примечание

Заголовок processthreadsapi.h определяет CreateProcessAsUser в качестве псевдонима, который автоматически выбирает версию ANSI или Юникод этой функции на основе определения константы препроцессора ЮНИКОД. Сочетание использования псевдонима, не зависящий от кодировки, с кодом, не зависящим от кодировки, может привести к несоответствиям, которые приводят к ошибкам компиляции или среды выполнения. Дополнительные сведения см. в разделе Соглашения для прототипов функций.

Требования

Требование Значение
Минимальная версия клиента Windows XP [только классические приложения]
Минимальная версия сервера Windows Server 2003 [только классические приложения]
Целевая платформа Windows
Header processthreadsapi.h (включая Windows.h)
Библиотека Advapi32.lib
DLL Advapi32.dll

См. также раздел

CloseHandle

CreateEnvironmentBlock

CreateProcess

CreateProcessWithLogonW

ExitProcess

GetEnvironmentStrings

GetExitCodeProcess

GetStartupInfo

ImpersonateLoggedOnUser

LoadUserProfile

PROCESS_INFORMATION

Функции процессов и потоков

Процессы

SECURITY_ATTRIBUTES

SHCreateProcessAsUserW

STARTUPINFO

STARTUPINFOEX

SetErrorMode

WaitForInputIdle