有点累 随便写写
在win7以后,win服务虽然是system的高权 但因为不在同一session的缘故,无法再可以控制桌面,包括显示ui,获取句柄,截图,弹窗等等。。
这样我在做进程守护的时候就遇到了些问题,守护的程序出现执行却无反馈的情况,查了很多例子,需要CreateProcessAsUser来调动程序就可以解决,需要注意这个CreateProcessAsUser需要system权限,仅admin是不行的,虽然网上有例子说可以手动提升admin权限,但我在本地安全策略里添加了相关权限依旧不行。
CreateProcessAsUser,打开程序之前需要一个令牌降权,有两种方法一个是获取用户的令牌
dwSessionID = ::WTSGetActiveConsoleSessionId();//获取用户id if (FALSE == ::WTSQueryUserToken(dwSessionID,&hToken)//hToken获取到令牌 { int i = GetLastError();//获取错误编码 }
另一种方法是通过获取其他程序的令牌,当然这种很有可能出现意外
LPWSTR lpa = ConvertCharToLPWSTR(_T("EXPLORER.EXE")) GetTokenByName(hToken,lpa) BOOL GetTokenByName(HANDLE &hToken, LPWSTR lpName) { if (!lpName) { return FALSE; } HANDLE hProcessSnap = NULL; BOOL bRet = FALSE; PROCESSENTRY32 pe32 = { 0 }; hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if (hProcessSnap == INVALID_HANDLE_VALUE) return (FALSE); pe32.dwSize = sizeof(PROCESSENTRY32); if (Process32First(hProcessSnap, &pe32)) { do { CString exefile = pe32.szExeFile; CString paraname = lpName; LPCSTR cname = wtoc(lpName).c_str; if (!exefile.CompareNoCase(cname)) { HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pe32.th32ProcessID); bRet = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken); CloseHandle(hProcessSnap); return (bRet); } } while (Process32Next(hProcessSnap, &pe32)); bRet = TRUE; } else bRet = FALSE; CloseHandle(hProcessSnap); return (bRet); }
我使用的是第一种方案,这里只写出降权call程序的代码,server的太多就不写了
#include "pch.h" #include <UserEnv.h> #include <WtsApi32.h> //#include <afx.h> #include <tchar.h> #pragma comment(lib, "UserEnv.lib") #pragma comment(lib, "WtsApi32.lib") // 突破SESSION 0隔离创建用户进程 传入程序路径 #define _AFXDLL BOOL CreateUserProcess(char *lpszFileName) { BOOL bRet = TRUE; DWORD dwSessionID = 0; HANDLE hToken = NULL; HANDLE hDuplicatedToken = NULL; LPVOID lpEnvironment = NULL; STARTUPINFO si = { 0 }; PROCESS_INFORMATION pi = { 0 }; si.cb = sizeof(si); do { // 获得当前Session ID dwSessionID = ::WTSGetActiveConsoleSessionId(); LPCWSTR err = _T("ERROR"); // 获得当前Session的用户令牌 if (FALSE == ::WTSQueryUserToken(dwSessionID, &hToken)) { int i = GetLastError(); //ShowMessage("WTSQueryUserToken", "ERROR"); MessageBox(GetForegroundWindow(), err, _T("WTSQueryUserToken"), 1); bRet = FALSE; break; } // 复制令牌 if (FALSE == ::DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDuplicatedToken)) { //ShowMessage("DuplicateTokenEx", "ERROR"); MessageBox(GetForegroundWindow(), err, _T("DuplicateTokenEx"), 1); bRet = FALSE; break; } // 创建用户Session环境 if (FALSE == ::CreateEnvironmentBlock(&lpEnvironment, hDuplicatedToken, FALSE)) { //ShowMessage("CreateEnvironmentBlock", "ERROR"); MessageBox(GetForegroundWindow(), err, _T("CreateEnvironmentBlock"), 1); bRet = FALSE; break; } // 在复制的用户Session下执行应用程序,创建进程 if (FALSE == ::CreateProcessAsUser(hDuplicatedToken, lpszFileName, NULL, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, lpEnvironment, NULL, &si, &pi)) { //ShowMessage("CreateProcessAsUser", "ERROR"); MessageBox(GetForegroundWindow(), err, _T("CreateProcessAsUser"), 1); bRet = FALSE; break; } } while (FALSE); // 关闭句柄, 释放资源 if (lpEnvironment) { ::DestroyEnvironmentBlock(lpEnvironment); } if (hDuplicatedToken) { ::CloseHandle(hDuplicatedToken); } if (hToken) { ::CloseHandle(hToken); } return bRet; } int main(int argc, char* argv[]) { char a[] = "calc.exe"; CreateUserProcess(a); return 0; }
这个可能在编码上有点问题,应该难不道诸位的,最后感谢提供例子的朋友。
累了睡了
-----------------------------
CreateUserProcess做成服务刚开机时,用户还未登陆系统,这时会索取不到令牌,会出错,原本跳过本次循环就可以了,但有MessageBox
所以使用时一定要去除所有MessageBox 不然报错会弹窗 可弹窗又不显示,整个服务就卡住了。
----------------------------------------------
1 #include <stdio.h> 2 #include <Windows.h> 3 #include <UserEnv.h> 4 #include <WtsApi32.h> 5 #pragma comment(lib, "UserEnv.lib") 6 #pragma comment(lib, "WtsApi32.lib") 7 8 #define SLEEP_TIME 5000 //间隔时间 9 10 #define FILE_PATH "C:\log.txt" //信息输出文件 11 12 bool brun = false; 13 14 SERVICE_STATUS servicestatus; 15 16 SERVICE_STATUS_HANDLE hstatus; 17 18 //int WriteToLog(const char* str); 19 20 void WINAPI ServiceMain(int argc, char** argv); 21 22 void WINAPI CtrlHandler(DWORD request); 23 24 static HANDLE hProcess = NULL; 25 26 27 28 // 突破SESSION 0隔离创建用户进程 传入程序路径 29 30 int WriteToLog(const char* str) 31 32 { 33 34 FILE* pfile; 35 36 fopen_s(&pfile, FILE_PATH, "a+"); 37 38 if (pfile == NULL) 39 40 { 41 42 return -1; 43 44 } 45 46 fprintf_s(pfile, "%s ", str); 47 48 fclose(pfile); 49 50 return 0; 51 52 } 53 54 const char* itoa1(int val) 55 { 56 static char result[sizeof(int) << 3 + 2]; 57 unsigned int tempval = val; 58 if (val < 0) tempval = -val; 59 int i = sizeof(int) << 3 + 1; 60 do { 61 result[i] = "0123456789"[tempval % 10]; 62 tempval /= 10; --i; 63 } while (tempval); 64 if (val < 0) result[i--] = '-'; 65 return &result[i + 1]; 66 } 67 68 HANDLE CreateUserProcess(char *lpszFileName) 69 { 70 BOOL bRet = TRUE; 71 DWORD dwSessionID = 0; 72 HANDLE hToken = NULL; 73 HANDLE hDuplicatedToken = NULL; 74 LPVOID lpEnvironment = NULL; 75 STARTUPINFO si = { 0 }; 76 PROCESS_INFORMATION pi = { 0 }; 77 si.cb = sizeof(si); 78 79 do 80 { 81 // 获得当前Session ID 82 dwSessionID = ::WTSGetActiveConsoleSessionId(); 83 //LPCSTR err = _T("ERROR"); 84 85 86 87 WriteToLog("sessionS"); 88 89 // 获得当前Session的用户令牌 90 if (FALSE == ::WTSQueryUserToken(dwSessionID, &hToken)) 91 { 92 int i = GetLastError(); 93 94 WriteToLog("WTSQueryUserToken"); 95 WriteToLog(itoa1(i)); 96 bRet = FALSE; 97 return NULL; 98 } 99 100 // 复制令牌 101 if (FALSE == ::DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, 102 SecurityIdentification, TokenPrimary, &hDuplicatedToken)) 103 { 104 int i = GetLastError(); 105 106 WriteToLog("DuplicateTokenEx"); 107 WriteToLog(itoa1(i)); 108 bRet = FALSE; 109 return NULL; 110 } 111 112 // 创建用户Session环境 113 if (FALSE == ::CreateEnvironmentBlock(&lpEnvironment, 114 hDuplicatedToken, FALSE)) 115 { 116 int i = GetLastError(); 117 118 WriteToLog("CreateEnvironmentBlock"); 119 WriteToLog(itoa1(i)); 120 121 bRet = FALSE; 122 return NULL; 123 } 124 125 126 //L"calc.exe" 127 // 在复制的用户Session下执行应用程序,创建进程 128 if (FALSE == ::CreateProcessAsUser(hDuplicatedToken, 129 lpszFileName, NULL, NULL, NULL, FALSE, 130 NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT, 131 lpEnvironment, NULL, &si, &pi)) 132 { 133 int i = GetLastError(); 134 135 WriteToLog("CreateProcessAsUser"); 136 WriteToLog(itoa1(i)); 137 138 bRet = FALSE; 139 return NULL; 140 } 141 WriteToLog("sessionC"); 142 143 } while (FALSE); 144 // 关闭句柄, 释放资源 145 if (lpEnvironment) 146 { 147 ::DestroyEnvironmentBlock(lpEnvironment); 148 } 149 if (hDuplicatedToken) 150 { 151 ::CloseHandle(hDuplicatedToken); 152 } 153 if (hToken) 154 { 155 ::CloseHandle(hToken); 156 } 157 return pi.hProcess; 158 } 159 160 161 162 void WINAPI ServiceMain(int argc, char** argv) 163 { 164 WriteToLog("smain"); 165 166 servicestatus.dwServiceType = SERVICE_WIN32; 167 168 servicestatus.dwCurrentState = SERVICE_START_PENDING; 169 170 servicestatus.dwControlsAccepted = SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_STOP ; 171 172 servicestatus.dwWin32ExitCode = 0; 173 174 servicestatus.dwServiceSpecificExitCode = 0; 175 176 servicestatus.dwCheckPoint = 0; 177 178 servicestatus.dwWaitHint = 0; 179 180 hstatus = ::RegisterServiceCtrlHandler("boot", CtrlHandler); 181 182 if (hstatus == 0) 183 { 184 int i = GetLastError(); 185 WriteToLog(itoa1(i)); 186 WriteToLog("RegisterServiceCtrlHandler failed"); 187 188 return; 189 190 } 191 192 WriteToLog("RegisterServiceCtrlHandler success"); 193 194 //向SCM 报告运行状态 195 196 servicestatus.dwCurrentState = SERVICE_RUNNING; 197 198 if (!SetServiceStatus(hstatus, &servicestatus)) 199 { 200 int i = GetLastError(); 201 WriteToLog(itoa1(i)); 202 WriteToLog("SetServiceStatus failed"); 203 204 return; 205 206 } 207 208 //在此处添加你自己希望服务做的工作,在这里我做的工作是获得当前可用的物理和虚拟内存信息 209 210 brun = true; 211 212 213 214 while (brun) 215 { 216 WriteToLog("while1"); 217 218 219 //循环开启 220 221 222 char a[] = "C:\Windows\1.exe"; 223 hProcess = CreateUserProcess(a); 224 225 226 WaitForSingleObject(hProcess, INFINITE); 227 CloseHandle(hProcess); 228 hProcess = NULL; 229 230 231 Sleep(SLEEP_TIME); 232 233 234 } 235 236 WriteToLog("service stopped"); 237 238 } 239 240 void WINAPI CtrlHandler(DWORD request) 241 { 242 // 停止服务 243 switch (request) 244 { 245 case SERVICE_CONTROL_STOP: 246 247 brun = false; 248 249 servicestatus.dwCurrentState = SERVICE_STOPPED; 250 251 break; 252 253 case SERVICE_CONTROL_SHUTDOWN: 254 255 brun = false; 256 257 servicestatus.dwCurrentState = SERVICE_STOPPED; 258 259 break; 260 261 default: 262 263 break; 264 265 } 266 267 SetServiceStatus(hstatus, &servicestatus); 268 } 269 270 int main() 271 { 272 273 274 SERVICE_TABLE_ENTRY entrytable[2]; 275 276 const char* constc = "boot"; 277 278 char* c = nullptr; 279 280 c = const_cast<char*>(constc); 281 282 283 entrytable[0].lpServiceName = c; 284 285 entrytable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; 286 287 entrytable[1].lpServiceName = NULL; 288 289 entrytable[1].lpServiceProc = NULL; 290 291 StartServiceCtrlDispatcher(entrytable); 292 return 0; 293 294 }