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
로그온 옵션입니다. 이 매개 변수는 0이거나 다음 값 중 하나일 수 있습니다.
[in, optional] lpApplicationName
실행할 모듈의 이름입니다. 이 모듈은 Windows 기반 애플리케이션일 수 있습니다. 로컬 컴퓨터에서 적절한 하위 시스템을 사용할 수 있는 경우 다른 유형의 모듈(예: MS-DOS 또는 OS/2)일 수 있습니다.
문자열은 실행할 모듈의 전체 경로 및 파일 이름을 지정하거나 부분 이름을 지정할 수 있습니다. 부분 이름의 경우 함수는 현재 드라이브 및 현재 디렉터리를 사용하여 사양을 완료합니다. 함수는 검색 경로를 사용하지 않습니다. 이 매개 변수에는 파일 이름 확장명을 포함해야 합니다. 기본 확장은 가정되지 않습니다.
lpApplicationName 매개 변수는 NULL일 수 있습니다. 이 경우 모듈 이름은 lpCommandLine 문자열의 첫 번째 공백으로 구분된 토큰이어야 합니다. 공백이 포함된 긴 파일 이름을 사용하는 경우 따옴표 붙은 문자열을 사용하여 파일 이름이 끝나고 인수가 시작되는 위치를 나타냅니다. 그렇지 않으면 파일 이름이 모호합니다. 예를 들어 문자열 "c:\program files\sub dir\program name"을 고려합니다. 이 문자열은 여러 가지 방법으로 해석할 수 있습니다. 시스템은 다음 순서로 가능성을 해석하려고 시도합니다.
c :\program files\sub.exec:\program files\sub dir\program.exec:\program files\sub dir\program name.exec:\program.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바이트 4바이트로 종료됩니다. 마지막 문자열에는 2개, 블록을 종료하려면 2바이트가 더 종료됩니다.
특정 사용자에 대한 환경 블록의 복사본을 검색하려면 CreateEnvironmentBlock 함수를 사용합니다.
[in, optional] lpCurrentDirectory
프로세스의 현재 디렉터리에 대한 전체 경로입니다. 문자열은 UNC 경로를 지정할 수도 있습니다.
이 매개 변수가 NULL인 경우 새 프로세스는 호출 프로세스와 동일한 현재 드라이브 및 디렉터리를 가집니다. (이 기능은 주로 애플리케이션을 시작하고 초기 드라이브 및 작업 디렉터리를 지정해야 하는 셸용으로 제공됩니다.)
[in] lpStartupInfo
STARTUPINFO 또는 STARTUPINFOEX 구조체에 대한 포인터입니다.
lpDesktop 멤버가 NULL이거나 빈 문자열인 경우 새 프로세스는 부모 프로세스의 바탕 화면 및 창 스테이션을 상속합니다. 함수는 상속된 창 스테이션 및 데스크톱에 지정된 사용자 계정에 대한 권한을 추가합니다. 그렇지 않으면 이 멤버가 데스크톱을 지정하는 경우 지정된 사용자 계정에 대한 권한을 WinSta0\Default의 경우에도 지정된 창 스테이션 및 데스크톱에 추가하는 것은 애플리케이션의 책임입니다.
STARTUPINFO 또는 STARTUPINFOEX의 핸들은 더 이상 필요하지 않은 경우 CloseHandle을 사용하여 닫아야 합니다.
[out] lpProcessInformation
프로세스에 대한 핸들을 포함하여 새 프로세스에 대한 식별 정보를 수신하는 PROCESS_INFORMATION 구조체에 대한 포인터입니다.
PROCESS_INFORMATION 핸들은 더 이상 필요하지 않은 경우 CloseHandle 함수를 사용하여 닫아야 합니다.
반환 값
함수가 성공하면 반환 값이 0이 아닙니다.
함수가 실패하면 반환 값은 0입니다. 확장 오류 정보를 가져오려면 GetLastError를 호출합니다.
프로세스 초기화가 완료되기 전에 함수가 반환됩니다. 필요한 DLL을 배치할 수 없거나 초기화에 실패하면 프로세스가 종료됩니다. 프로세스의 종료 상태 얻으려면 GetExitCodeProcess를 호출합니다.
설명
기본적으로 CreateProcessWithTokenW 는 지정된 사용자의 프로필을 HKEY_USERS 레지스트리 키에 로드하지 않습니다. 즉 , HKEY_CURRENT_USER 레지스트리 키의 정보에 액세스하면 일반적인 대화형 로그온과 일치하는 결과가 생성되지 않을 수 있습니다. LOGON_WITH_PROFILE 사용하거나 이 함수를 호출하기 전에 LoadUserProfile 함수를 호출하여 사용자의 레지스트리 하이브를 HKEY_USERS 로드해야 합니다.
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에서 첫 번째 공백으로 구분된 문자열이어야 합니다. 실행 파일 또는 경로 이름에 공백이 있는 경우 함수가 공백을 구문 분석하는 방식으로 인해 다른 실행 파일이 실행될 위험이 있습니다. 다음 예제는 함수가 "MyApp.exe" 대신 "Program.exe"(있는 경우)을 실행하려고 하기 때문에 위험합니다. LPTSTR szCmdline = L"C:\\Program Files\\MyApp";
CreateProcessWithTokenW(/*...*/, szCmdline, /*...*/);
악의적인 사용자가 시스템에서 "Program.exe"이라는 애플리케이션을 만드는 경우 Program Files 디렉터리를 사용하여 CreateProcessWithTokenW 를 잘못 호출하는 모든 프로그램은 의도한 애플리케이션 대신 이 애플리케이션을 실행합니다.
이 문제를 방지하려면 lpApplicationName에 대해 NULL을 전달하지 마세요. lpApplicationName에 대해 NULL을 전달하는 경우 아래 예제와 같이 lpCommandLine의 실행 경로 주위에 따옴표를 사용합니다.
LPTSTR szCmdline = L"\"C:\\Program Files\\MyApp\"";
CreateProcessWithTokenW(/*...*/, szCmdline, /*...*/);
요구 사항
요구 사항 | 값 |
---|---|
지원되는 최소 클라이언트 | Windows Vista [데스크톱 앱만 해당] |
지원되는 최소 서버 | Windows Server 2003 [데스크톱 앱만 해당] |
대상 플랫폼 | Windows |
헤더 | winbase.h(Windows.h 포함) |
라이브러리 | Advapi32.lib |
DLL | Advapi32.dll |