我有一个 C++ 程序,它使用 BitBlt 捕获屏幕并通过网络将其发送到另一台计算机。现在,为了使其正常工作,我的程序需要在用户会话中运行,因为像 BitBlt 或桌面复制 Api 这样的函数会捕获当前会话的屏幕。由于我的程序有一些需要管理员权限的其他功能,我在用户登录时自动启动时遇到了一些问题。这是因为如前所述,它需要在用户会话中运行。
我尝试使用自己编写的 Windows 服务和 CreateProcessAsUser 来运行我的程序,但是如果用户不是管理员,则它不会以这些权限运行。当具有管理员权限的用户登录时,它会按预期工作。我还尝试使用任务计划程序和缓存的凭据;但是,这会导致我的程序在缓存凭据的用户的会话中运行。
在我发布问题后,我发现了一个旧的论坛帖子,里面有解决方案。 在 32 位和 64 位架构中颠覆 Vista UAC
DWORD GetWinlogonPIDInSession(DWORD dwSessionId) {
DWORD dwWinlogonPID = 0;
PWTS_PROCESS_INFO pProcessInfo = NULL;
DWORD dwProcessCount = 0;
if (WTSEnumerateProcesses(WTS_CURRENT_SERVER_HANDLE, 0, 1,
&pProcessInfo, &dwProcessCount)) {
for (DWORD i = 0; i < dwProcessCount; ++i) {
if (_wcsicmp(pProcessInfo[i].pProcessName, L"winlogon.exe") == 0 && pProcessInfo[i].SessionId == dwSessionId) {
dwWinlogonPID = pProcessInfo[i].ProcessId;
break;
}
}
WTSFreeMemory(pProcessInfo);
}
else {
std::cerr << "WTSEnumerateProcesses failed. Error: " << GetLastError() << std::endl;
}
return dwWinlogonPID;
}
const wchar_t* exePath = L"Program.exe";
DWORD winlogonPID = GetWinlogonPIDInSession(newSessionId);
if (winlogonPID == 0) {
return 1;
}
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, winlogonPID);
if (hProcess == NULL) {
return 1;
}
// Get access token of winlogon.exe
HANDLE hToken = NULL;
if (!OpenProcessToken(hProcess, TOKEN_DUPLICATE, &hToken)) {
CloseHandle(hProcess);
return 1;
}
// Duplicate the token to get a primary token
HANDLE hPrimaryToken = NULL;
if (!DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hPrimaryToken)) {
CloseHandle(hToken);
CloseHandle(hProcess);
return 1;
}
// Close handles
CloseHandle(hToken);
CloseHandle(hProcess);
// Start the process in the user's session with elevated privileges
STARTUPINFO si = { sizeof(si) };
si.lpDesktop = L"winsta0\\default"; // Ensure it runs on the interactive desktop
PROCESS_INFORMATION pi;
if (!CreateProcessAsUser(
hPrimaryToken, // User token
exePath, // Path to the executable
NULL, // Command line
NULL, // Process attributes
NULL, // Thread attributes
FALSE, // Inherit handles
CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT | CREATE_NEW_PROCESS_GROUP | CREATE_BREAKAWAY_FROM_JOB, // Creation flags
NULL, // Environment
NULL, // Current directory
&si, // Startup info
&pi // Process information
)) {
CloseHandle(hPrimaryToken);
}
else {
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hPrimaryToken);
}