CreateProcessWithLogonW 함수(winbase.h)
새 프로세스 및 기본 스레드를 만듭니다. 그런 다음, 새 프로세스는 지정된 자격 증명(사용자, 도메인 및 암호)의 보안 컨텍스트에서 지정된 실행 파일을 실행합니다. 필요에 따라 지정된 사용자에 대한 사용자 프로필을 로드할 수 있습니다.
이 함수는 호출자가 LogonUser 함수를 호출하여 사용자를 인증하고 토큰을 가져올 필요가 없다는 점을 제외하고 CreateProcessAsUser 및 CreateProcessWithTokenW 함수와 비슷합니다.
구문
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
사용자의 이름입니다. 로그온할 사용자 계정의 이름입니다. UPN 형식, 사용자@DNS_domain_name 사용하는 경우 lpDomain 매개 변수는 NULL이어야 합니다.
사용자 계정에는 로컬 컴퓨터에 대한 로컬 로그온 권한이 있어야 합니다. 이 권한은 워크스테이션 및 서버의 모든 사용자에게 부여되지만 도메인 컨트롤러의 관리자에게만 부여됩니다.
[in, optional] lpDomain
계정 데이터베이스에 lpUsername 계정이 포함된 도메인 또는 서버의 이름입니다. 이 매개 변수가 NULL이면 사용자 이름을 UPN 형식으로 지정해야 합니다.
[in] lpPassword
lpUsername 계정의 텍스트 지우기 암호입니다.
[in] dwLogonFlags
로그온 옵션입니다. 이 매개 변수는 0(0) 또는 다음 값 중 하나일 수 있습니다.
[in, optional] lpApplicationName
실행할 모듈의 이름입니다. 이 모듈은 Windows 기반 애플리케이션일 수 있습니다. 로컬 컴퓨터에서 적절한 하위 시스템을 사용할 수 있는 경우 다른 유형의 모듈(예: MS-DOS 또는 OS/2)일 수 있습니다.
문자열은 실행할 모듈의 전체 경로 및 파일 이름을 지정하거나 부분 이름을 지정할 수 있습니다. 부분 이름인 경우 함수는 현재 드라이브 및 현재 디렉터리를 사용하여 사양을 완료합니다. 함수는 검색 경로를 사용하지 않습니다. 이 매개 변수에는 파일 이름 확장명을 포함해야 합니다. 기본 확장은 가정되지 않습니다.
lpApplicationName 매개 변수는 NULL일 수 있으며 모듈 이름은 lpCommandLine 문자열의 첫 번째 공백으로 구분된 토큰이어야 합니다. 공백이 포함된 긴 파일 이름을 사용하는 경우 따옴표 붙은 문자열을 사용하여 파일 이름이 끝나고 인수가 시작되는 위치를 나타냅니다. 그렇지 않으면 파일 이름이 모호합니다.
예를 들어 다음 문자열은 다양한 방법으로 해석할 수 있습니다.
"c:\program files\sub dir\program name"
시스템은 다음 순서로 가능성을 해석하려고 시도합니다.
- c:\program.exe files\sub dir\program name
- c:\program files\sub.exe dir\program name
- c:\program files\sub dir\program.exe name
- 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 추가되지 않습니다. 파일 이름에 디렉터리 경로가 없는 경우 시스템은 다음 순서로 실행 파일을 검색합니다.
- 애플리케이션이 로드된 디렉터리입니다.
- 부모 프로세스의 현재 디렉터리입니다.
- 32비트 Windows 시스템 디렉터리입니다. GetSystemDirectory 함수를 사용하여 이 디렉터리의 경로를 가져옵니다.
- 16비트 Windows 시스템 디렉터리입니다. 이 디렉터리의 경로를 가져오는 함수는 없지만 검색됩니다.
- Windows 디렉터리입니다. GetWindowsDirectory 함수를 사용하여 이 디렉터리의 경로를 가져옵니다.
- PATH 환경 변수에 나열된 디렉터리입니다. 이 함수는 App Paths 레지스트리 키로 지정된 애플리케이션별 경로를 검색하지 않습니다. 이 애플리케이션별 경로를 검색 순서에 포함하려면 ShellExecute 함수를 사용합니다.
[in] dwCreationFlags
프로세스를 만드는 방법을 제어하는 플래그입니다. CREATE_DEFAULT_ERROR_MODE, CREATE_NEW_CONSOLE 및 CREATE_NEW_PROCESS_GROUP 플래그는 기본적으로 사용하도록 설정됩니다. 값 목록은 프로세스 만들기 플래그를 참조하세요.
또한 이 매개 변수는 프로세스 스레드의 일정 우선 순위를 결정하는 데 사용되는 새 프로세스의 우선 순위 클래스를 제어합니다. 값 목록은 GetPriorityClass를 참조하세요. 우선 순위 클래스 플래그를 지정하지 않으면 만들기 프로세스의 우선 순위 클래스가 IDLE_PRIORITY_CLASS 또는 BELOW_NORMAL_PRIORITY_CLASS 않는 한 우선 순위 클래스는 기본적으로 NORMAL_PRIORITY_CLASS. 이 경우 자식 프로세스는 호출 프로세스의 기본 우선 순위 클래스를 받습니다.
dwCreationFlags 매개 변수의 값이 0인 경우:
- 프로세스는 기본 오류 모드를 가져오고, 새 콘솔을 만들고, 새 프로세스 그룹을 만듭니다.
- 새 프로세스의 환경 블록은 ANSI 문자를 포함하는 것으로 간주됩니다(추가 정보는 lpEnvironment 매개 변수 참조).
- 16비트 Windows 기반 애플리케이션은 공유 VDM(Virtual DOS 컴퓨터)에서 실행됩니다.
[in, optional] lpEnvironment
새 프로세스의 환경 블록에 대한 포인터입니다. 이 매개 변수가 NULL인 경우 새 프로세스는 lpUsername에서 지정한 사용자의 프로필에서 만든 환경을 사용합니다.
환경 블록은 null로 종료된 null로 끝나는 문자열 블록으로 구성됩니다. 각 문자열은 다음과 같은 형식입니다.
이름=값
등호(=)는 구분 기호로 사용되므로 환경 변수의 이름에 사용하면 안 됩니다.
환경 블록에는 유니코드 또는 ANSI 문자가 포함될 수 있습니다. lpEnvironment에서 가리키는 환경 블록에 유니코드 문자가 포함된 경우 dwCreationFlags에 CREATE_UNICODE_ENVIRONMENT 포함되어 있는지 확인합니다.
ANSI 환경 블록은 0바이트(0)로 종료됩니다. 하나는 마지막 문자열에 대해, 다른 하나는 블록을 종료합니다. 유니코드 환경 블록은 0바이트로 종료됩니다. 마지막 문자열에는 2개, 블록을 종료하려면 2바이트가 더 있습니다.
특정 사용자에 대한 환경 블록의 복사본을 검색하려면 CreateEnvironmentBlock 함수를 사용합니다.
[in, optional] lpCurrentDirectory
프로세스의 현재 디렉터리에 대한 전체 경로입니다. 문자열은 UNC 경로를 지정할 수도 있습니다.
이 매개 변수가 NULL인 경우 새 프로세스에는 호출 프로세스와 동일한 현재 드라이브 및 디렉터리가 있습니다. 이 기능은 주로 애플리케이션을 시작하고 초기 드라이브 및 작업 디렉터리를 지정해야 하는 셸에 대해 제공됩니다.
[in] lpStartupInfo
STARTUPINFO 구조체에 대한 포인터입니다.
애플리케이션은 WinSta0\Default의 경우에도 지정된 사용자 계정에 대한 권한을 지정된 창 스테이션 및 데스크톱에 추가해야 합니다.
lpDesktop 멤버가 NULL이거나 빈 문자열인 경우 새 프로세스는 부모 프로세스의 데스크톱 및 창 스테이션을 상속합니다. 애플리케이션은 상속된 창 스테이션 및 데스크톱에 지정된 사용자 계정에 대한 권한을 추가해야 합니다.
Windows XP: CreateProcessWithLogonW 는 지정된 사용자 계정에 대한 권한을 상속된 창 스테이션 및 데스크톱에 추가합니다.
STARTUPINFO의 핸들은 더 이상 필요하지 않은 경우 CloseHandle을 사용하여 닫아야 합니다.
[out] lpProcessInformation
프로세스에 대한 핸들을 포함하여 새 프로세스에 대한 식별 정보를 수신하는 PROCESS_INFORMATION 구조체에 대한 포인터입니다.
필요하지 않은 경우 PROCESS_INFORMATION 핸들을 CloseHandle 함수로 닫아야 합니다.
반환 값
함수가 성공하면 반환 값이 0이 아닙니다.
함수가 실패하면 반환 값은 0입니다. 확장 오류 정보를 가져오려면 GetLastError를 호출합니다.
프로세스가 초기화를 완료하기 전에 함수가 반환됩니다. 필요한 DLL을 배치할 수 없거나 초기화에 실패하면 프로세스가 종료됩니다. 프로세스의 종료 상태 얻으려면 GetExitCodeProcess를 호출합니다.
설명
기본적으로 CreateProcessWithLogonW 는 지정된 사용자 프로필을 HKEY_USERS 레지스트리 키에 로드하지 않습니다. 즉 , HKEY_CURRENT_USER 레지스트리 키의 정보에 액세스해도 일반적인 대화형 로그온과 일치하는 결과가 생성되지 않을 수 있습니다. CreateProcessWithLogonW를 호출하거나, LOGON_WITH_PROFILE 사용하거나, LoadUserProfile 함수를 호출하기 전에 사용자 레지스트리 하이브를 HKEY_USERS 로드해야 합니다.
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 SP2, Windows Server 2003 이상: 함수가 호출자 토큰에서 로그온 SID를 사용하고 "LocalSystem" 계정에 대한 토큰이 이 SID를 포함하지 않으므로 "LocalSystem" 계정으로 실행되는 프로세스에서 CreateProcessWithLogonW 를 호출할 수 없습니다. 또는 CreateProcessAsUser 및 LogonUser 함수를 사용합니다.
이 함수를 사용하는 애플리케이션을 컴파일하려면 _WIN32_WINNT 0x0500 이상으로 정의합니다. 자세한 내용은 Windows 헤더 사용을 참조하세요.
보안 설명
lpApplicationName 매개 변수는 NULL일 수 있으며 실행 파일 이름은 lpCommandLine의 첫 번째 공백으로 구분된 문자열이어야 합니다. 실행 파일 또는 경로 이름에 공백이 있는 경우 함수가 공백을 구문 분석하는 방식으로 인해 다른 실행 파일을 실행할 수 있는 위험이 있습니다. 함수가 "MyApp.exe" 대신 "Program.exe"(있는 경우)을 실행하려고 하기 때문에 다음 예제를 사용하지 마십시오.LPTSTR szCmdline[]=_tcsdup(TEXT("C:\\Program Files\\MyApp"));
CreateProcessWithLogonW(..., szCmdline, ...)
악의적인 사용자가 시스템에서 "Program.exe"이라는 애플리케이션을 만드는 경우 Program Files 디렉터리를 사용하여 CreateProcessWithLogonW 를 잘못 호출하는 모든 프로그램은 의도한 애플리케이션 대신 악의적인 사용자 애플리케이션을 실행합니다.
이 문제를 방지하려면 lpApplicationName에 대해 NULL을 전달하지 마세요. lpApplicationName에 NULL을 전달하는 경우 다음 예제와 같이 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 |
헤더 | winbase.h(Windows.h 포함) |
라이브러리 | Advapi32.lib |
DLL | Advapi32.dll |