ChatGPT 저도 질문을 해봤어요

예전에 재미로 몇 번 써보고 개발 관련 질문은 처음인데 이거 검색으로 찾는 데 시간이 꽤나 걸렸던 문제인데 테스트 해보지 않았지만 대단하긴 합니다.

Q) windows service 애플리케이션에서 createprocessasuser로 사용자 계정 관리자 권한으로 실행하는 코드를 c++로 작성해줘

아래는 C++로 작성된 코드로, Windows 서비스 애플리케이션에서 CreateProcessAsUser() 함수를 사용하여 사용자 계정 관리자 권한으로 프로그램을 실행하는 예제입니다. 이 예제는 Windows API 함수를 사용하므로, <Windows.h> 헤더 파일이 포함되어 있어야 합니다.

#include <Windows.h>

// 사용자 계정 관리자 권한으로 프로그램 실행하는 함수
BOOL RunProcessAsUser(HANDLE hToken, LPCWSTR lpCommandLine)
{
    STARTUPINFO si = {};
    si.cb = sizeof(STARTUPINFO);
    si.lpDesktop = L"winsta0\\default";  // 실행할 프로그램의 데스크톱 이름
    PROCESS_INFORMATION pi = {};

    // 프로세스를 실행할 사용자 계정 정보
    TOKEN_LINKED_TOKEN linkedToken = {};
    TOKEN_PRIVILEGES tokenPrivileges = {};
    linkedToken.LinkedToken = hToken;

    if (!GetTokenInformation(hToken, TokenLinkedToken, &linkedToken, sizeof(linkedToken), NULL))
    {
        return FALSE;
    }

    if (!DuplicateTokenEx(linkedToken.LinkedToken, TOKEN_ALL_ACCESS, NULL, SecurityIdentification, TokenPrimary, &hToken))
    {
        return FALSE;
    }

    tokenPrivileges.PrivilegeCount = 1;
    tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &tokenPrivileges.Privileges[0].Luid))
    {
        return FALSE;
    }

    if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
    {
        return FALSE;
    }

    if (!CreateProcessAsUser(hToken, NULL, (LPWSTR)lpCommandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi))
    {
        return FALSE;
    }

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

    return TRUE;
}

위의 함수를 호출하기 전에, 먼저 사용자 계정에 대한 토큰 핸들을 얻어야 합니다. 이 작업을 수행하는 코드는 다음과 같습니다.

BOOL GetTokenHandleForUser(LPCWSTR lpUserName, PHANDLE phToken)
{
    DWORD dwSessionId = WTSGetActiveConsoleSessionId();

    if (!WTSQueryUserToken(dwSessionId, phToken))
    {
        return FALSE;
    }

    return TRUE;
}

위 함수에서는 WTSGetActiveConsoleSessionId() 함수를 사용하여 현재 활성화된 콘솔 세션 ID를 가져온 다음, WTSQueryUserToken() 함수를 사용하여 해당 세션의 사용자 토큰 핸들을 얻습니다.

이제 RunProcessAsUser() 함수를 호출하여 사용자 계정 관리자 권한으로 프로그램을 실행할 수 있습니다. 호출 코드는 다음과 같습니다.

HANDLE hToken;

if (GetTokenHandleForUser(L"사용자이름", &hToken))
{
    RunProcessAsUser(hToken, L"실행할프로그램.exe");

Q) 여기서 현재 로그인된 사용자 계정 이름을 알 수 있을까?

네, 현재 로그인된 사용자 계정 이름을 얻는 방법이 있습니다. 아래는 C++로 작성된 코드로, GetUserName() 함수를 사용하여 현재 로그인된 사용자 계정 이름을 가져오는 예제입니다.

#include <Windows.h>
#include <Lmcons.h>

// 현재 로그인된 사용자 계정 이름을 가져오는 함수
BOOL GetLoggedInUserName(LPWSTR lpUserName, LPDWORD lpnSize)
{
    return GetUserName(lpUserName, lpnSize);
}

위의 함수를 호출하면, lpUserName 버퍼에 현재 로그인된 사용자 계정 이름이 저장됩니다. 호출 코드는 다음과 같습니다.

WCHAR szUserName[UNLEN + 1];
DWORD dwSize = UNLEN + 1;

if (GetLoggedInUserName(szUserName, &dwSize))
{
    wprintf(L"현재 로그인된 사용자 계정 이름: %s\n", szUserName);
}

위의 코드에서 UNLEN<Lmcons.h> 헤더 파일에서 정의된 상수로, 사용자 이름 버퍼의 최대 크기를 나타냅니다. 사용자 이름이 이 크기를 초과할 경우 함수가 실패합니다. GetUserName() 함수는 성공하면 TRUE를 반환하고, 실패하면 FALSE를 반환합니다. 함수가 성공하면 lpnSize 매개변수에는 사용자 이름의 길이가 저장됩니다.

Q) 위의 소스를 하나의 함수로 만들어줘

아래는 GetLoggedInUserName() 함수와 RunProcessAsUser() 함수를 합쳐서 하나의 함수로 만든 예제입니다. 이 함수는 현재 로그인된 사용자 계정 이름을 가져온 다음, 해당 계정으로 프로그램을 실행합니다.

#include <Windows.h>
#include <Lmcons.h>

// 사용자 계정 관리자 권한으로 프로그램 실행하는 함수
BOOL RunProcessAsUser(LPCWSTR lpUserName, LPCWSTR lpCommandLine)
{
    HANDLE hToken;

    // 사용자 계정 토큰 핸들 가져오기
    if (!WTSQueryUserToken(WTSGetActiveConsoleSessionId(), &hToken))
    {
        return FALSE;
    }

    // 프로그램 실행하기
    STARTUPINFO si = {};
    si.cb = sizeof(STARTUPINFO);
    si.lpDesktop = L"winsta0\\default";  // 실행할 프로그램의 데스크톱 이름
    PROCESS_INFORMATION pi = {};

    TOKEN_LINKED_TOKEN linkedToken = {};
    TOKEN_PRIVILEGES tokenPrivileges = {};
    linkedToken.LinkedToken = hToken;

    if (!GetTokenInformation(hToken, TokenLinkedToken, &linkedToken, sizeof(linkedToken), NULL))
    {
        CloseHandle(hToken);
        return FALSE;
    }

    if (!DuplicateTokenEx(linkedToken.LinkedToken, TOKEN_ALL_ACCESS, NULL, SecurityIdentification, TokenPrimary, &hToken))
    {
        CloseHandle(hToken);
        return FALSE;
    }

    tokenPrivileges.PrivilegeCount = 1;
    tokenPrivileges.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if (!LookupPrivilegeValue(NULL, SE_ASSIGNPRIMARYTOKEN_NAME, &tokenPrivileges.Privileges[0].Luid))
    {
        CloseHandle(hToken);
        return FALSE;
    }

    if (!AdjustTokenPrivileges(hToken, FALSE, &tokenPrivileges, sizeof(TOKEN_PRIVILEGES), NULL, NULL))
    {
        CloseHandle(hToken);
        return FALSE;
    }

    if (!CreateProcessAsUser(hToken, NULL, (LPWSTR)lpCommandLine, NULL, NULL, FALSE, CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_CONSOLE | CREATE_NEW_PROCESS_GROUP, NULL, NULL, &si, &pi))
    {
        CloseHandle(hToken);
        return FALSE;
    }

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

    return TRUE;
}

// 현재 로그인된 사용자 계정 이름을 가져오는 함수와 프로그램 실행 함수를 합쳐준 함수
BOOL RunProgramAsLoggedInUser(LPCWSTR lpCommandLine)
{
    WCHAR szUserName[UNLEN + 1];
    DWORD dwSize = UNLEN + 1;

    if (!GetUserName(szUserName, &dwSize))
    {
        return FALSE;
    }

    return RunProcessAsUser(szUserName, lpCommandLine);
}

이제 RunProgramAsLoggedInUser() 함수를 호출하여 현재 로그인된 사용자 계정 이름으로 프로그램을 실행할 수 있습니다. 호출 코드는 다음과 같습니다.

if (RunProgramAsLoggedInUser(L"실행할프로그램.exe"))
{
    wprintf(L"프로그램을 성공적으로 실행했습니다.\n");
}
else
{
    wprintf(L"프로그램 실행에 실패했습니다.\n");
}
``
4개의 좋아요