切换菜单
搜索
个人笔记云
首页
java
spring
springmvc
python
使用教程
笔记管理
搜索
登录/注册
好物分享
退出
搜索
windows服务启动一个当前用户的进程windows Service启动带有管理员权限的GUI进程
2022-08-18
469
[原文](https://m.yht7.com/news/87159) # windows服务启动一个当前用户的进程windows Service启动带有管理员权限的GUI进程 ``` bool createProcessWithAdmin(const std::string & process_name, LPPROCESS_INFORMATION process) { HANDLE hToken = NULL; HANDLE hTokenDup = NULL; if (process_name.empty()) { return false; } if (!OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken)) { return false; } if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityAnonymous, TokenPrimary, &hTokenDup)) { CloseHandle(hToken); return false; } STARTUPINFO si; LPVOID pEnv = NULL; DWORD dwSessionId = WTSGetActiveConsoleSessionId(); ZeroMemory(&si, sizeof(STARTUPINFO)); if (!SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD))) { CloseHandle(hToken); CloseHandle(hTokenDup); return false; } si.cb = sizeof(STARTUPINFO); si.lpDesktop = "WinSta0\Default"; si.wShowWindow = SW_SHOW; si.dwFlags = STARTF_USESHOWWINDOW; if (!CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE)) { CloseHandle(hToken); CloseHandle(hTokenDup); return false; } if (!CreateProcessAsUser(hTokenDup, process_name.c_str(), NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, pEnv, NULL, &si, process)) { CloseHandle(hToken); CloseHandle(hTokenDup); return false; } if (pEnv) { DestroyEnvironmentBlock(pEnv); } CloseHandle(hToken); CloseHandle(hTokenDup); return true; } ``` windows服务启动一个当前用户的进程windows Service启动带有管理员权限的GUI进程 用法: 1 PROCESS_INFORMATION pi; 2 createProcessWithAdmin("D:/absolute-path-exe", &pi); 用以上的代码就能用windows服务进程创建带有管理员权限的主GUI程序了。 另外windows service推荐用Qt的解决方案,编写windows service更简单了: https://github.com/qtproject/qt-solutions references: http://stackoverflow.com/questions/6418791/requesting-administrator-privileges-at-run-time http://blog.csdn.net/woshinia/article/details/7850295 http://stackoverflow.com/questions/6261427/how-to-run-a-process-as-an-administrator-from-win32-c http://blog.csdn.net/breeze_vickie/article/details/4334257 https://stackoverflow.com/questions/267838/how-can-a-windows-service-execute-a-gui-application ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 一个比较简单的方法: 1.WTSGetActiveConsoleSessionId 2.WTSQueryUserToken 3.CreateProcessAsUser 三步就能实现目标 但是如果第三步使用CreateProcessWithToken创建进程只能改变用户名不能改变session id ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ 首先,为什么会使用windows服务? 大多数Windows服务是以SYSTEM用户启动的。SYSTEM用户是系统中权限最高的用户,可以操作注册表中Local Machine、系统目录,不需要UAC就能以管理员权限启动一个进程等等。 在windows中,每一个用户会有一个Session ,Session 0专用于服务和其他不与用户交互的应用程序。 第一个登录进来,可以进行交互式操作的用户被连到Session 1上。第二个登录进行的用户被分配给Session 2,以此类推。 因为Service在Session 0中,而我们登陆系统以后看到的桌面属于另一个Session,如果采取在服务进程中启动子进程来显示对话框,子对话框将无法在我们这个session中显示。 PS: 如果Service 中想显示MessageBox,需要使用API :WTSSendMessage 言归正传,那么如何在Service为当前用户登陆的session启动一个进程呢? 我们可以使用API:CreateProcessAsUser 但是使用这个API需要一系列的准备 比如复制当前激活session 用户的Token,创建环境变量等等。 BOOL MyCreateProcessAsUser(const HANDLE& hCurrentToken,LPCTSTR strPath,LPTSTR lpCmdLine) { HANDLE hTokenDup = NULL; if (!DuplicateTokenEx(hCurrentToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hTokenDup)) { #ifdef _DEBUG int iError = GetLastError(); CString strLog; strLog.Format(_T("DuplicateTokenEx fail,Error code:%d"), iError); OutputDebugString(strLog); #endif return FALSE; } DWORD dwSessionID = WTSGetActiveConsoleSessionId(); if (!SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionID, sizeof(DWORD))) { SafeCloseHandle(hTokenDup); return FALSE; } STARTUPINFO si; PROCESS_INFORMATION pi; ZeroMemory(&si, sizeof(STARTUPINFO)); ZeroMemory(&pi, sizeof(PROCESS_INFORMATION)); si.cb = sizeof(STARTUPINFO); si.lpDesktop = L"WinSta0\Default"; si.dwFlags = STARTF_USESHOWWINDOW; si.wShowWindow = HIDE_WINDOW; LPVOID pEnv = NULL; DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT; if (!CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE)) { SafeCloseHandle(hTokenDup); return FALSE; } if (!CreateProcessAsUser(hTokenDup, strPath, lpCmdLine, NULL, NULL, FALSE, dwCreationFlags, pEnv, NULL, &si, &pi)) { SafeCloseHandle(hTokenDup); if (pEnv != NULL) DestroyEnvironmentBlock(pEnv); return FALSE; } CloseHandle(pi.hProcess); CloseHandle(pi.hThread); CloseHandle(hTokenDup); if (pEnv != NULL) DestroyEnvironmentBlock(pEnv); return TRUE; } 这样就可以在service中启动一个当前用户 权限的进程了。 另一个问题来了,如何获取当前激活session 用户的Token? WTSGetActiveConsoleSessionId();在这种情况下通常是失败的。 一种常见的方法就是 打开explorer.exe进程,取它的Token ...没办法,谁让我service权限高呢,咩哈哈哈 BOOL GetCurrentLogonUserToken(HANDLE& hToken) { DWORD dwCurSessionId = WTSGetActiveConsoleSessionId(); if (TRUE == WTSQueryUserToken(dwCurSessionId, &hToken)) return TRUE; DWORD err = GetLastError(); BOOL bRet = FALSE; HANDLE hProcessSnap = NULL; PROCESSENTRY32 pe32; DWORD dwSessionId = -1; hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) { return FALSE; } pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hProcessSnap, &pe32)) { do { if (!_tcsicmp(pe32.szExeFile, _T("explorer.exe"))) { ::ProcessIdToSessionId(pe32.th32ProcessID, &dwSessionId); if (dwSessionId != dwCurSessionId) continue; //{ HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID); DWORD err = GetLastError(); bRet = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken); if (bRet == 0) { } CloseHandle(hProcessSnap); return TRUE; //} } } while (Process32Next(hProcessSnap, &pe32)); bRet = TRUE; } else { bRet = FALSE; } CloseHandle(hProcessSnap); return bRet; } 以上就是全文了~
教程分类
热门视频教程
热门文章
热门书籍推荐