주로 서비스에서 UI 있는 프로그램을 서비스 세션이 아닌 대화형 데스크탑이 있는 세션에서 실행시킴으로써 정상적으로 작동시키기 위한 것.
부가적으로 이 함수로 실행시키면 비스타의 UAC 를 띄우지 않고 관리자 권한으로 실행시킬 수 있다.
서비스가 SYSTEM 계정으로 실행중이라면 실행시킨 프로그램도 SYSTEM 계정을 받아서 실행됨.
코드 프로젝트의 기사의 소스코드를 기반으로 2000 ~ Vista 에서 작동하도록 수정함.
http://www.codeproject.com/KB/vista-security/VistaSessions.aspx
- #ifdef _UNICODE
#define tstring wstring
#else
#define tstring string
#endif
- // Winlogon.exe 실행파일의 세션을 검색하여 같은 세션에서 실행시킴, 2000 ~ Vista
BOOL LaunchAppIntoDifferentSessionAll(tstring strPath)
{
if( strPath.empty() )
return FALSE;
tstring strSearch;
OSVERSIONINFO osi;
ZeroMemory(&osi,sizeof(OSVERSIONINFO));
osi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
GetVersionEx(&osi);
- // 변수 선언
BOOL bResult = FALSE;
DWORD dwSessionId = 0; // 세션 ID
DWORD dwWinlogonPID = 0; // Winlogon PID
- typedef DWORD (*pfnWTSGetActiveConsoleSessionId)(void);
HMODULE hModule = NULL;
pfnWTSGetActiveConsoleSessionId fnWTSGetActiveConsoleSessionId = NULL;
- if( osi.dwMajorVersion == 6 )
{
OutputDebugString(_T("Vista, 라이브러리 로딩 시도"));
hModule = ::LoadLibrary(_T("Kernel32.dll"));
if( hModule != NULL )
{
OutputDebugString(_T("Vista, 함수 로딩 시도"));
fnWTSGetActiveConsoleSessionId = (pfnWTSGetActiveConsoleSessionId) GetProcAddress(hModule, "WTSGetActiveConsoleSessionId");
if( fnWTSGetActiveConsoleSessionId == NULL )
OutputDebugString(_T("WTSGetActiveConsoleSessionId 함수 로딩 실패"));
- dwSessionId = fnWTSGetActiveConsoleSessionId();
}
}
// 같은 세션으로 실행할 프로세스 찾기(Winlogon.exe)
BOOL IsExistsWinlogon = FALSE;
PROCESSENTRY32 pe32;
pe32.dwSize = sizeof(PROCESSENTRY32);
HANDLE hSnap = ::CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if( hSnap == INVALID_HANDLE_VALUE )
{
bResult = FALSE;
goto CleanUP;
}
- if( !Process32First(hSnap, &pe32) )
{
bResult = FALSE;
goto CleanUP;
}
- if( osi.dwMajorVersion == 6 )
strSearch = _T("winlogon.exe");
else if( osi.dwMajorVersion == 5 )
strSearch = _T("explorer.exe");
- do
{
if( lstrcmpi(pe32.szExeFile, strSearch.c_str()) == 0 )
{
OutputDebugString(_T("WinLogon 프로세스 검색"));
DWORD dwWLSessionID = 0;
BOOL bRet = ProcessIdToSessionId(pe32.th32ProcessID, &dwWLSessionID);
- if( bRet && (osi.dwMajorVersion == 6) && (dwSessionId == dwWLSessionID) )
{
// 비스타
OutputDebugString(_T("Vista"));
dwWinlogonPID = pe32.th32ProcessID;
IsExistsWinlogon = TRUE;
break;
}
else if( bRet && (osi.dwMajorVersion == 5) )
{
// 2000 ~ XP
OutputDebugString(_T("2000/XP"));
dwSessionId = dwWLSessionID;
dwWinlogonPID = pe32.th32ProcessID;
IsExistsWinlogon = TRUE;
break;
}
}
} while ( Process32Next(hSnap, &pe32) );
- if( IsExistsWinlogon == FALSE )
{
OutputDebugString(_T("Winlogon.exe 검색 실패"));
bResult = FALSE;
goto CleanUP;
}
- // WINLOGON 프로세스 열고 토큰 복사하여 특정 세션 지정
HANDLE hProcess = ::OpenProcess(MAXIMUM_ALLOWED, FALSE, dwWinlogonPID);
HANDLE hToken = NULL;
HANDLE hTokenDup = NULL;
if( hProcess == NULL )
goto CleanUP;
if( !::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID|TOKEN_READ|TOKEN_WRITE, &hToken))
{
OutputDebugString(_T("OpenProcessToken Failed"));
bResult = FALSE;
goto CleanUP;
}
LUID luid;
if( !LookupPrivilegeValue(NULL,SE_DEBUG_NAME, &luid) )
{
OutputDebugString(_T("LookupPrivilegeValue Failed"));
bResult = FALSE;
goto CleanUP;
}
TOKEN_PRIVILEGES tp;
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
if( !DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hTokenDup) )
{
OutputDebugString(_T("DuplicateTokenEx Failed"));
bResult = FALSE;
goto CleanUP;
}
SetTokenInformation(hTokenDup, TokenSessionId, (LPVOID)&dwSessionId, sizeof(DWORD));
if( !AdjustTokenPrivileges(hTokenDup, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL,NULL) )
{
OutputDebugString(_T("AdjustTokenPrivileges Failed"));
bResult = FALSE;
goto CleanUP;
}
if( GetLastError() == ERROR_NOT_ALL_ASSIGNED )
{
OutputDebugString(_T("AdjustTokenPrivileges Assign Failed"));
bResult = FALSE;
goto CleanUP;
}
- // CreateProcessAsUser 준비
STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = _T("winsta0\\default");
PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
LPVOID pEnv = NULL;
if( CreateEnvironmentBlock(&pEnv, hTokenDup, TRUE) )
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
else
pEnv = NULL;
- LPTSTR lpszPath = _tcsdup(strPath.c_str());
if( lpszPath == NULL )
{
OutputDebugString(_T("Path String Assign Failed"));
bResult = FALSE;
goto CleanUP;
}
- OutputDebugString(lpszPath);
- bResult = ::CreateProcessAsUser(
hTokenDup,
NULL,
lpszPath,
NULL,
NULL,
FALSE,
dwCreationFlags,
pEnv,
NULL,
&si,
&pi);
- free(lpszPath);
- if( !bResult )
OutputDebugString(_T("CreateProcessAsUser Failed"));
if( (bResult) && (pi.hProcess != INVALID_HANDLE_VALUE) )
CloseHandle(pi.hProcess);
if( (bResult) && (pi.hThread != INVALID_HANDLE_VALUE) )
CloseHandle(pi.hThread);
- CleanUP:
if( hModule )
FreeLibrary(hModule);
if( hSnap != INVALID_HANDLE_VALUE )
CloseHandle(hSnap);
if( hProcess != NULL )
CloseHandle(hProcess);
if( hToken )
CloseHandle(hToken);
if( hTokenDup )
CloseHandle(hTokenDup);
- return bResult;
}
- BOOL EnablePrivilege(LPCTSTR szPrivilege)
{
BOOL bResult = FALSE;
HANDLE hToken = NULL;
TOKEN_PRIVILEGES tpOld, tpCurrent;
- if( !OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken) )
return bResult;
- tpCurrent.PrivilegeCount = 1;
tpCurrent.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
- if( ::LookupPrivilegeValue(NULL, szPrivilege, &tpCurrent.Privileges[0].Luid) )
{
DWORD dwOld = sizeof(TOKEN_PRIVILEGES);
if( ::AdjustTokenPrivileges(hToken, FALSE, &tpCurrent, dwOld, &tpOld, &dwOld) )
bResult = TRUE;
else
bResult = FALSE;
}
else
bResult = FALSE;
- CloseHandle(hToken);
return bResult;
}