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


Функция CreateProcessWithLogonW (winbase.h)

Создает новый процесс и его основной поток. Затем новый процесс запускает указанный исполняемый файл в контексте безопасности указанных учетных данных (пользователя, домена и пароля). При необходимости можно загрузить профиль пользователя для указанного пользователя.

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

Синтаксис

BOOL CreateProcessWithLogonW(
  [in]                LPCWSTR               lpUsername,
  [in, optional]      LPCWSTR               lpDomain,
  [in]                LPCWSTR               lpPassword,
  [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] lpUsername

Имя пользователя. Это имя учетной записи пользователя для входа. Если используется формат имени участника-пользователя, пользователь@DNS_domain_name, параметр lpDomain должен иметь значение NULL.

Учетная запись пользователя должна иметь разрешение "Локальный вход" на локальном компьютере. Это разрешение предоставляется всем пользователям на рабочих станциях и серверах, но только администраторам на контроллерах домена.

[in, optional] lpDomain

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

[in] lpPassword

Пароль в виде ясного текста для учетной записи lpUsername .

[in] dwLogonFlags

Параметр входа. Этот параметр может иметь значение 0 (ноль) или одно из следующих значений.

Значение Значение
LOGON_WITH_PROFILE
0x00000001
Войдите в систему, а затем загрузите профиль пользователя в разделе реестра HKEY_USERS . Функция возвращается после загрузки профиля. Загрузка профиля может занять много времени, поэтому лучше использовать это значение только в том случае, если необходимо получить доступ к сведениям в разделе реестра HKEY_CURRENT_USER .

Windows Server 2003: Профиль выгружается после завершения нового процесса независимо от того, были ли созданы дочерние процессы.

Windows XP: Профиль выгружается после того, как новый процесс и все созданные им дочерние процессы завершаются.

LOGON_NETCREDENTIALS_ONLY
0x00000002
Войдите в систему, но используйте только указанные учетные данные в сети. Новый процесс использует тот же маркер, что и вызывающий объект, но система создает новый сеанс входа в LSA, а процесс использует указанные учетные данные в качестве учетных данных по умолчанию.

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

Система не проверяет указанные учетные данные. Таким образом, процесс может начаться, но он может не иметь доступа к сетевым ресурсам.

[in, optional] lpApplicationName

Имя выполняемого модуля. Этот модуль может быть приложением на основе Windows. Это может быть другой тип модуля (например, MS-DOS или OS/2), если соответствующая подсистема доступна на локальном компьютере.

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

Параметр lpApplicationName может иметь значение NULL, а имя модуля должно быть первым маркером с разделителями пробелами в строке lpCommandLine . Если вы используете длинное имя файла, содержащее пробел, используйте строки в кавычках, чтобы указать, где заканчивается имя файла и начинаются аргументы; В противном случае имя файла будет неоднозначным.

Например, следующую строку можно интерпретировать по-разному:

"c:\program files\sub dir\program name"

Система пытается интерпретировать возможности в следующем порядке:

  1. c:\program.exe files\sub dir\program name
  2. c:\program files\sub.exe dir\program name
  3. c:\program files\sub dir\program.exe имя
  4. c:\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 не добавляется. Если имя файла не содержит пути к каталогу, система выполняет поиск исполняемого файла в следующей последовательности:

  1. Каталог, из которого загружено приложение.
  2. Текущий каталог для родительского процесса.
  3. 32-разрядный системный каталог Windows. Используйте функцию GetSystemDirectory , чтобы получить путь к этому каталогу.
  4. 16-разрядный системный каталог Windows. Нет функции, которая получает путь к этому каталогу, но выполняется поиск.
  5. Каталог Windows. Используйте функцию GetWindowsDirectory , чтобы получить путь к этому каталогу.
  6. Каталоги, перечисленные в переменной среды 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 завершается двумя 0 (нулевыми) байтами: один для последней строки и еще один для завершения блока. Блок среды Юникода завершается четырьмя нулевыми байтами: два для последней строки и еще два для завершения блока.

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

[in, optional] lpCurrentDirectory

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

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

[in] lpStartupInfo

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

Приложение должно добавить разрешение для указанной учетной записи пользователя на указанную станцию окна и рабочий стол, даже для WinSta0\Default.

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

Windows XP: CreateProcessWithLogonW добавляет разрешение для указанной учетной записи пользователя в унаследованную станцию окон и рабочий стол.

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

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

[out] lpProcessInformation

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

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

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

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

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

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

Комментарии

По умолчанию CreateProcessWithLogonW не загружает указанный профиль пользователя в раздел реестра HKEY_USERS . Это означает, что доступ к сведениям в разделе реестра HKEY_CURRENT_USER может не привести к результатам, которые соответствуют обычному интерактивному входу в систему. Вы несете ответственность за загрузку куста реестра пользователей в HKEY_USERS перед вызовом CreateProcessWithLogonW с помощью LOGON_WITH_PROFILE или путем вызова функции LoadUserProfile .

Если параметр lpEnvironment имеет значение NULL, новый процесс использует блок среды, созданный из профиля пользователя, указанного в lpUserName. Если переменные HOMEDRIVE и HOMEPATH не заданы, CreateProcessWithLogonW изменяет блок среды, чтобы использовать диск и путь к рабочему каталогу пользователя.

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

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

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

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

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

CreateProcessWithLogonW обращается к указанному каталогу и исполняемому образу в контексте безопасности целевого пользователя. Если исполняемый образ находится в сети и в пути указана буква сетевого диска, то буква сетевого диска недоступна для целевого пользователя, так как для каждого входа в систему можно назначить буквы сетевого диска. Если указана буква сетевого диска, эта функция завершается ошибкой. Если исполняемый образ находится в сети, используйте UNC-путь.

Существует ограничение на количество дочерних процессов, которые могут быть созданы этой функцией и выполняться одновременно. Например, в Windows XP это ограничение составляет MAXIMUM_WAIT_OBJECTS*4. Однако вы не сможете создать такое количество процессов из-за ограничений квот на уровне системы.

Windows XP с пакетом обновления 2 (SP2), Windows Server 2003 или более поздней версии: Невозможно вызвать CreateProcessWithLogonW из процесса, выполняющегося под учетной записью LocalSystem, так как функция использует идентификатор безопасности входа в маркере вызывающего объекта, а маркер для учетной записи LocalSystem не содержит этого идентификатора безопасности. В качестве альтернативы используйте функции CreateProcessAsUser и LogonUser .

Чтобы скомпилировать приложение, использующее эту функцию, определите _WIN32_WINNT как 0x0500 или более поздней версии. Дополнительные сведения см. в разделе Использование заголовков Windows.

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

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

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

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

LPTSTR szCmdline[]=_tcsdup(TEXT("\"C:\\Program Files\\MyApp\""));
CreateProcessWithLogonW(..., szCmdline, ...)

Примеры

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


#include <windows.h>
#include <stdio.h>
#include <userenv.h>

void DisplayError(LPWSTR pszAPI)
{
    LPVOID lpvMessageBuffer;

    FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | 
        FORMAT_MESSAGE_FROM_SYSTEM,
        NULL, GetLastError(), 
        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), 
        (LPWSTR)&lpvMessageBuffer, 0, NULL);

    //
    //... now display this string
    //
    wprintf(L"ERROR: API        = %s.\n", pszAPI);
    wprintf(L"       error code = %d.\n", GetLastError());
    wprintf(L"       message    = %s.\n", (LPWSTR)lpvMessageBuffer);

    //
    // Free the buffer allocated by the system
    //
    LocalFree(lpvMessageBuffer);

    ExitProcess(GetLastError());
}

void wmain(int argc, WCHAR *argv[])
{
    DWORD     dwSize;
    HANDLE    hToken;
    LPVOID    lpvEnv;
    PROCESS_INFORMATION pi = {0};
    STARTUPINFO         si = {0};
    WCHAR               szUserProfile[256] = L"";

    si.cb = sizeof(STARTUPINFO);
    
    if (argc != 4)
    {
        wprintf(L"Usage: %s [user@domain] [password] [cmd]", argv[0]);
        wprintf(L"\n\n");
        return;
    }

    //
    // TO DO: change NULL to '.' to use local account database
    //
    if (!LogonUser(argv[1], NULL, argv[2], LOGON32_LOGON_INTERACTIVE, 
            LOGON32_PROVIDER_DEFAULT, &hToken))
        DisplayError(L"LogonUser");

    if (!CreateEnvironmentBlock(&lpvEnv, hToken, TRUE))
        DisplayError(L"CreateEnvironmentBlock");

    dwSize = sizeof(szUserProfile)/sizeof(WCHAR);

    if (!GetUserProfileDirectory(hToken, szUserProfile, &dwSize))
        DisplayError(L"GetUserProfileDirectory");

    //
    // TO DO: change NULL to '.' to use local account database
    //
    if (!CreateProcessWithLogonW(argv[1], NULL, argv[2], 
            LOGON_WITH_PROFILE, NULL, argv[3], 
            CREATE_UNICODE_ENVIRONMENT, lpvEnv, szUserProfile, 
            &si, &pi))
        DisplayError(L"CreateProcessWithLogonW");

    if (!DestroyEnvironmentBlock(lpvEnv))
        DisplayError(L"DestroyEnvironmentBlock");

    CloseHandle(hToken);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

Требования

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

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

CloseHandle

CreateEnvironmentBlock

CreateProcessAsUser

ExitProcess

GetEnvironmentStrings

GetExitCodeProcess

OpenProcess

PROCESS_INFORMATION

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

Процессы

STARTUPINFO

SetErrorMode

WaitForInputIdle