// 创建交互式服务安装完成以后,启动UI的程序
BOOL LaunchApplication(LPCTSTR lpszExecute, LPCTSTR lpszCmdLine)
{
BOOL bRet = FALSE;
HANDLE hUserTokenDup = NULL;
LPVOID pEnv = NULL;
do
{
DWORD dwSessionId = 0;
if (0xFFFFFFFF == (dwSessionId = WTSGetActiveConsoleSessionId())) { PRINT(ERR, GetLastError(), TEXT("WTSGetActiveConsoleSessionId")); break; }
#define DEFAULT_WINLOGON_APPLICATION (TEXT("winlogon.exe"))
#define DEFAULT_DEFAULT_APPLICATION (TEXT("explorer.exe")) // 需要以explorer.exe进程的Token来创建Env环境块,否则以服务启动的App在打开文件路径的方面可能会遇到一些问题,比如最常见的是会访问C:\Windows\System32\config\systemprofile导致访问了错误的位置。
DWORD dwWinlogonPid = 0;
if (0xFFFFFFFF == (dwWinlogonPid = GetProcessID(DEFAULT_WINLOGON_APPLICATION, dwSessionId))) { PRINT(ERR, TEXT("Get Process ID Failed!")); break; }
if (NULL == (hUserTokenDup = GetProcessTokenDup(dwWinlogonPid))) { PRINT(ERR, TEXT("Get Process Duplicate Token Failed!")); break; }
if (!AdjustProcessTokenDup(hUserTokenDup, dwSessionId)) { PRINT(ERR, TEXT("Adjust Process Token Failed!")); break; }
HANDLE hDefaultTokenDup2 = NULL;
DWORD dwDefaultPid = 0;
if (0xFFFFFFFF == (dwDefaultPid = GetProcessID(DEFAULT_DEFAULT_APPLICATION, dwSessionId))) { PRINT(ERR, TEXT("Get Process ID Failed!")); break; }
if (NULL == (hDefaultTokenDup2 = GetProcessTokenDup(dwDefaultPid))) { PRINT(ERR, TEXT("Get Process Duplicate Token Failed!")); break; }
// Create Environment Block
DWORD dwCreateFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
if (CreateEnvironmentBlock(&pEnv, hDefaultTokenDup2, TRUE)) { dwCreateFlags |= CREATE_UNICODE_ENVIRONMENT; }
// Launch Process In The Client's Logon Session
TCHAR szExecute[MAX_PATH] = { 0 };
GetModuleFileName(NULL, szExecute, _countof(szExecute));
_tcsrchr(szExecute, TEXT('\\'))[1] = TEXT('\0');
StringCbCat(szExecute, _countof(szExecute) - _tcslen(szExecute), lpszExecute);
TCHAR szCmdLine[MAX_PATH] = { 0 };
if (NULL != lpszCmdLine) { StringCchPrintf(szCmdLine, _countof(szCmdLine), TEXT("%s"), lpszCmdLine); }
#define DEFAULT_DESKTOP_WINSTA0 (TEXT("winsta0\\default"))
PROCESS_INFORMATION pi = { 0 };
STARTUPINFO si = { sizeof(STARTUPINFO) };
si.lpDesktop = DEFAULT_DESKTOP_WINSTA0;
if (!CreateProcessAsUser(hUserTokenDup,
szExecute,
szCmdLine,
NULL,
NULL,
FALSE,
dwCreateFlags,
pEnv,
NULL,
&si,
&pi))
{
PRINT(ERR, GetLastError(), TEXT("CreateProcessAsUser"));
break;
}
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
// Completed
bRet = TRUE;
} while (FALSE);
if (NULL != pEnv) { DestroyEnvironmentBlock(pEnv); pEnv = NULL; }
if (NULL != hUserTokenDup) { CloseHandle(hUserTokenDup); hUserTokenDup = NULL; }
return bRet;
}
DWORD GetProcessID(LPCTSTR lpszProcessName, DWORD dwSessionId)
{
DWORD dwProcessId = 0xFFFFFFFF;
HANDLE hSnapshot = INVALID_HANDLE_VALUE;
do
{
_ASSERT(NULL != lpszProcessName);
if (NULL == lpszProcessName) { break; }
hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (INVALID_HANDLE_VALUE == hSnapshot) { PRINT(ERR, GetLastError(), TEXT("CreateToolhelp32Snapshot")); break; }
PROCESSENTRY32 pe32 = { sizeof(PROCESSENTRY32) };
if (!Process32First(hSnapshot, &pe32)) { PRINT(ERR, GetLastError(), TEXT("Process32First")); break; }
do
{
if (0 == _tcsicmp(pe32.szExeFile, lpszProcessName))
{
DWORD dwProcessSessionId = 0;
if (ProcessIdToSessionId(pe32.th32ProcessID, &dwProcessSessionId)
&& (dwSessionId == dwProcessSessionId))
{
dwProcessId = pe32.th32ProcessID;
break;
}
}
} while (Process32Next(hSnapshot, &pe32));
// Completed
} while (FALSE);
if (INVALID_HANDLE_VALUE != hSnapshot) { CloseHandle(hSnapshot); hSnapshot = INVALID_HANDLE_VALUE; }
return dwProcessId;
}
HANDLE GetProcessTokenDup(DWORD dwProcessId)
{
HANDLE hProcess = NULL;
HANDLE hToken = NULL;
HANDLE hTokenDup = NULL;
do
{
if (NULL == (hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, dwProcessId))) { PRINT(ERR, GetLastError(), TEXT("OpenProcess")); break; }
if (!OpenProcessToken(hProcess,
TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE,
&hToken))
{
PRINT(ERR, GetLastError(), TEXT("OpenProcessToken"));
break;
}
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hTokenDup)) { PRINT(ERR, GetLastError(), TEXT("DuplicateTokenEx")); break; }
// Completed
} while (FALSE);
if (NULL != hToken) { CloseHandle(hToken); hToken = NULL; }
if (NULL != hProcess) { CloseHandle(hProcess); hProcess = NULL; }
return hTokenDup;
}
BOOL AdjustProcessTokenDup(HANDLE hTokenDup, DWORD dwSessionId)
{
BOOL bRet = FALSE;
do
{
if (NULL == hTokenDup) { break; }
// Adjust Token Privileges
if(!SetTokenInformation(hTokenDup, TokenSessionId, (LPVOID)&dwSessionId, sizeof(dwSessionId))) { PRINT(ERR, GetLastError(), TEXT("SetTokenInformation")); break; }
if (!AdjustTokenDupPrivileges(hTokenDup, SE_DEBUG_NAME)) { PRINT(ERR, TEXT("Enable SE_DEBUG_NAME Privilege Failed!")); }
if (!AdjustTokenDupPrivileges(hTokenDup, SE_TCB_NAME)) { PRINT(ERR, TEXT("Enable SE_TCB_NAME Privilege Failed!")); }
if (!AdjustTokenDupPrivileges(hTokenDup, SE_CHANGE_NOTIFY_NAME)) { PRINT(ERR, TEXT("Enable SE_CHANGE_NOTIFY_NAME Privilege Failed!")); }
if (!AdjustTokenDupPrivileges(hTokenDup, SE_INCREASE_QUOTA_NAME)) { PRINT(ERR, TEXT("Enable SE_INCREASE_QUOTA_NAME Privilege Failed!")); }
if (!AdjustTokenDupPrivileges(hTokenDup, SE_ASSIGNPRIMARYTOKEN_NAME)) { PRINT(ERR, TEXT("Enable SE_ASSIGNPRIMARYTOKEN_NAME Privilege Failed!")); }
// Completed
bRet = TRUE;
} while (FALSE);
return bRet;
}
BOOL AdjustTokenDupPrivileges(HANDLE hTokenDup, LPCTSTR lpszPrivileges)
{
BOOL bRet = FALSE;
do
{
LUID luid = { 0 };
if (!LookupPrivilegeValue(NULL, lpszPrivileges, &luid))
{
PRINT(ERR, GetLastError(), TEXT("LookupPrivilegeValue"));
break;
}
TOKEN_PRIVILEGES tp = { 0 };
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
// Adjust token privileges
if (!AdjustTokenPrivileges(hTokenDup, FALSE, &tp, sizeof(tp), NULL, NULL))
{
PRINT(ERR, GetLastError(), TEXT("AdjustTokenPrivileges"));
break;
}
// Completed
bRet = TRUE;
} while (FALSE);
return bRet;
}
void PRINT(DWORD dwLevel, LPCTSTR lpszFormat, ...)
{
do
{
if (!m_bDbgValid) { break; }
TCHAR szText[DEFAULT_PRINTF_BUFFER_LENGTH] = { 0 };
TCHAR szBuffer[DEFAULT_PRINTF_BUFFER_LENGTH] = { 0 };
// Parse Parameter
va_list args;
va_start(args, lpszFormat);
StringCchVPrintf(szBuffer, _countof(szBuffer), lpszFormat, args);
va_end(args);
// Format
FORMAT(szText, _countof(szText), szBuffer);
// Dump
DUMP(dwLevel, szText);
} while (FALSE);
}
void PRINT(DWORD dwLevel, DWORD dwErrorId, LPCTSTR lpszDescription)
{
do
{
if (!m_bDbgValid) { break; }
TCHAR szText[DEFAULT_PRINTF_BUFFER_LENGTH] = { 0 };
// Format
FORMAT(szText, _countof(szText), dwErrorId, lpszDescription);
// Dump
DUMP(dwLevel, szText);
} while (FALSE);
}
void CCommon::FORMAT(LPTSTR lpszText, size_t nLength, LPCTSTR lpszInfo)
{
_ASSERT(NULL != lpszText);
_ASSERT(nLength > 0);
_ASSERT(NULL != lpszInfo);
SYSTEMTIME st = { 0 };
GetLocalTime(&st);
StringCchPrintf(lpszText,
nLength,
TEXT("[%04d-%02d-%02d %02d:%02d:%02d.%03d] - %s\r\n"),
st.wYear,
st.wMonth,
st.wDay,
st.wHour,
st.wMinute,
st.wSecond,
st.wMilliseconds,
lpszInfo);
}
void FORMAT(LPTSTR lpszText, size_t nLength, DWORD dwErrorId, LPCTSTR lpszDescription)
{
_ASSERT(NULL != lpszText);
_ASSERT(nLength > 0);
_ASSERT(NULL != lpszDescription);
SYSTEMTIME st = { 0 };
GetLocalTime(&st);
TCHAR szBuffer[DEFAULT_PRINTF_BUFFER_LENGTH] = { 0 };
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, dwErrorId, LANG_NEUTRAL, (LPTSTR)szBuffer, _countof(szBuffer), NULL);
StringCchPrintf(lpszText,
nLength,
TEXT("[%04d-%02d-%02d %02d:%02d:%02d.%03d] - Call %s() Failed with Error: %d - %s\r\n"),
st.wYear,
st.wMonth,
st.wDay,
st.wHour,
st.wMinute,
st.wSecond,
st.wMilliseconds,
lpszDescription,
dwErrorId,
szBuffer);
}