Функция 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 Rights for Access-Token Objects. Пользователь, представленный маркером, должен иметь доступ на чтение и выполнение приложения, указанного
Чтобы получить первичный маркер, представляющий указанного пользователя, вызовите функцию LogonUser. Кроме того, можно вызвать функцию DuplicateTokenEx для преобразования маркера олицетворения в первичный маркер. Это позволяет серверу приложению, олицетворяющее клиента, создать процесс, имеющий контекст безопасности клиента.
Если hToken является ограниченной версией основного маркера вызывающего объекта, SE_ASSIGNPRIMARYTOKEN_NAME привилегии не требуются. Если необходимые привилегии еще не включены, CreateProcessAsUser включает их в течение длительности вызова. Дополнительные сведения см. в разделе Выполнение с специальными привилегиями.
службы терминалов: процесс выполняется в сеансе, указанном в маркере. По умолчанию это тот же сеанс, который называется LogonUser. Чтобы изменить сеанс, используйте функцию SetTokenInformation.
[in, optional] lpApplicationName
Имя выполняемого модуля. Этот модуль может быть приложением на основе Windows. Он может быть другим типом модуля (например, MS-DOS или ОС/2), если соответствующая подсистема доступна на локальном компьютере.
Строка может указать полный путь и имя файла модуля для выполнения или указать частичное имя. В случае частичного имени функция использует текущий диск и текущий каталог для выполнения спецификации. Функция не будет использовать путь поиска. Этот параметр должен включать расширение имени файла; расширение по умолчанию не предполагается.
Параметр
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 КБ символов. Если lpApplicationNameNULL, часть имени модуля lpCommandLine ограничена MAX_PATH символами.
Версия этой функции Юникода CreateProcessAsUserWможет изменить содержимое этой строки. Таким образом, этот параметр не может быть указателем на память только для чтения (например, const переменную или литеральную строку). Если этот параметр является постоянной строкой, функция может вызвать нарушение доступа.
Параметр lpCommandLine можно NULL. В этом случае функция использует строку, указанную lpApplicationName в качестве командной строки.
Если оба lpApplicationName и lpCommandLine не являютсяNULL, *lpApplicationName указывает модуль для выполнения, а *lpCommandLine указывает командную строку. Новый процесс может использовать GetCommandLine для получения всей командной строки. Процессы консоли, написанные в C, могут использовать argc и аргументы argv для анализа командной строки. Так как argv[0] — это имя модуля, программисты C обычно повторяют имя модуля в качестве первого маркера в командной строке.
Если lpApplicationNameNULL, первый маркер с разделителями пробелов в командной строке указывает имя модуля. Если вы используете длинное имя файла, содержащее пробел, используйте строки с кавычками, чтобы указать, где заканчивается имя файла, и аргументы начинаются (см. описание параметра lpApplicationName). Если имя файла не содержит расширения, .exe добавляется. Таким образом, если расширение имени файла .com, этот параметр должен включать расширение .com. Если имя файла заканчивается точкой (.) без расширения или если имя файла содержит путь, .exe не добавляется. Если имя файла не содержит путь к каталогу, система ищет исполняемый файл в следующей последовательности:
- Каталог, из которого загружено приложение.
- Текущий каталог родительского процесса.
- 32-разрядный системный каталог Windows. Используйте функцию GetSystemDirectory
, чтобы получить путь к этому каталогу. - 16-разрядный системный каталог Windows. Нет функции, которая получает путь к этому каталогу, но выполняется поиск.
- Каталог Windows. Используйте функцию getWindowsDirectory
GetWindowsDirectory, чтобы получить путь к этому каталогу. - Каталоги, перечисленные в переменной среды PATH. Обратите внимание, что эта функция не выполняет поиск пути для каждого приложения, указанного разделом реестра пути приложений. Чтобы включить этот путь для каждого приложения в последовательность поиска, используйте функцию
ShellExecute.
[in, optional] lpProcessAttributes
Указатель на структуру SECURITY_ATTRIBUTES, которая задает дескриптор безопасности для нового объекта процесса и определяет, могут ли дочерние процессы наследовать возвращенный дескриптор процессу. Если
[in, optional] lpThreadAttributes
Указатель на структуру SECURITY_ATTRIBUTES, которая указывает дескриптор безопасности для нового объекта потока и определяет, могут ли дочерние процессы наследовать возвращенный дескриптор потоку. Если lpThreadAttributesNULL или lpSecurityDescriptorNULL, поток получает дескриптор безопасности по умолчанию и дескриптор не может наследоваться. Дескриптор безопасности по умолчанию — это пользователь, на который ссылается параметр 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, для строк, завершаемых значением NULL. Каждая строка находится в следующей форме:
имя=значение\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
Обработка в STARTUPINFO или STARTUPINFOEX должна быть закрыта с CloseHandle, если они больше не нужны.
[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 после завершения нового процесса.
Если параметр
Функции createProcessWithLogonW и
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 createProcessAsUs er используется для реализации командлета в PowerShell версии 2.0, командлет работает правильно для удаленных сеансов вентилятора и развертывания. Однако из-за определенных сценариев безопасности командлет, реализованный с помощью CreateProcessAsUser работает только в PowerShell версии 3.0 для удаленных сеансов вентилятора; Удаленные сеансы отключаются из-за нехватки привилегий безопасности клиента. Чтобы реализовать командлет, который работает для удаленных сеансов вентилятора и вентилятора в PowerShell версии 3.0, используйте функцию CreateProcess.
Примеры
Пример см. в статье Запуск интерактивного клиентского процесса.
Заметка
Заголовок processthreadsapi.h определяет CreateProcessAsUser в качестве псевдонима, который автоматически выбирает версию ANSI или Юникод этой функции на основе определения константы препроцессора ЮНИКОДа. Сочетание использования псевдонима, нейтрального для кодирования, с кодом, не зависящим от кодирования, может привести к несоответствиям, которые приводят к ошибкам компиляции или среды выполнения. Дополнительные сведения см. в соглашениях о прототипах функций.
Требования
Требование | Ценность |
---|---|
минимальные поддерживаемые клиентские | Windows XP [только классические приложения] |
минимальный поддерживаемый сервер | Windows Server 2003 [только классические приложения] |
целевая платформа | Виндоус |
заголовка | processthreadsapi.h (include Windows.h) |
библиотеки |
Advapi32.lib |
DLL | Advapi32.dll |