以System用户运行的系统及服务,无法显示界面

在开发守护进程时,遇到一个问题,发了一天时间,才找到问题的思路。特记录下:

[问题]

将A.exe注册为服务,通过执行WinExec("B.exe的完整路径"{非注册服务}, SW_HIDE),启动B.exe时,在任务管理器中也存在相应进程,但是**无法显示界面**,这是什么原因?

[原因]

因为A.exe是系统权限,它在session 0,而B.exe他是session1.当A程序运行在session0,也就是系统服务窗口,所以你当前桌面上是看不到的。这种情况你需要用CreateProcessAsUser()API等方式模拟当前登陆用户方式。

[解决方案]

virtual bool DoStart(int tryInterval, int tryTime) {
int error;
bool result;
HANDLE hToken = NULL;
HANDLE hDupedToken = NULL;
// HANDLE hUserToken = NULL;

PROCESS_INFORMATION pi;
ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));

STARTUPINFO si;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = sizeof(STARTUPINFO);
si.lpDesktop = L"winsta0\\default";

SECURITY_ATTRIBUTES sa;
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));

sa.nLength = sizeof(SECURITY_ATTRIBUTES);

DWORD dwSessionId, winlogonPid;

// Loag the client on to the local computer
dwSessionId = WTSGetActiveConsoleSessionId();

/////////////////////////////////////////////////////
// Find the FSI.SnifferClient.UI.exe process
/////////////////////////////////////////////////
PROCESSENTRY32 procEntry;

HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if (hSnap == INVALID_HANDLE_VALUE) {
return false;
}

procEntry.dwSize = sizeof(PROCESSENTRY32);

if (!Process32First(hSnap, &procEntry)) {
error = GetLastError();
return false;
}

do {
char output[256];
WCHAR* wc = procEntry.szExeFile;
sprintf(output, "%ws", wc);

if (_stricmp(output, "winlogon.exe") == 0) {
// We found a winlogon process...
// make sure it's running in the console session
DWORD fsiSnifferClientSessId = 0;
if (ProcessIdToSessionId(procEntry.th32ProcessID, &fsiSnifferClientSessId)
&& fsiSnifferClientSessId == dwSessionId) {
winlogonPid = procEntry.th32ProcessID;
break;
}
}
} while (Process32Next(hSnap, &procEntry));

HANDLE hProcess = OpenProcess(MAXIMUM_ALLOWED, FALSE, winlogonPid);

if (!::OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY
| TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID
| TOKEN_READ | TOKEN_WRITE, &hToken)) {
error = GetLastError();
return false;
}

TOKEN_PRIVILEGES tp;
LUID luid;
if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luid)) {
error = GetLastError();
return false;
}
tp.PrivilegeCount = 1;
tp.Privileges[0].Luid = luid;
tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

result = DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDupedToken);
SetTokenInformation(hDupedToken, TokenSessionId, (void*)dwSessionId, sizeof(DWORD));

if (!AdjustTokenPrivileges(hDupedToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES),
(PTOKEN_PRIVILEGES)NULL, NULL)) {
error = GetLastError();
return false;
}

if (GetLastError() == ERROR_NOT_ALL_ASSIGNED) {
error = GetLastError();
return false;
}

string ClientAppPath = ""; // APP的完整路径
Util::GetRegValue(GetSubKey().c_str(), "AppPath", ClientAppPath);

ClientAppPath += "\\xxx.exe"; 

LPVOID pEnv = NULL;
DWORD dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;

if (CreateEnvironmentBlock(&pEnv, hDupedToken, TRUE)) {
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
}

result = CreateProcessAsUser(
hDupedToken,
ConvertCharToLPWSTR(ClientAppPath.c_str()),
NULL,
NULL,
NULL,
FALSE,
dwCreationFlags,
pEnv,
NULL,
&si,
&pi);

CloseHandle(hProcess);
CloseHandle(hDupedToken);

CloseHandle(hToken);

int ret;
do {
Sleep(tryInterval);
ExeInfo info;
info.ProcessName = GetExeName();
ret = FindProcess(info);
} while (--tryTime && (ret != 1));
return ret == 1;
}

参考链接:

(1) https://blog.csdn.net/findsafety/article/details/45971161

(2) https://www.codeproject.com/Articles/18367/Launch-your-application-in-Vista-under-the-local-s

(3) http://ask.csdn.net/questions/192521

(4) https://blog.csdn.net/tpriwwq/article/details/45221301

(5) https://blog.csdn.net/theone10211024/article/details/14001943

(6) https://blog.csdn.net/jeanphorn/article/details/45745739

猜你喜欢

转载自blog.csdn.net/n_fly/article/details/79672455