【发布时间】:2015-09-17 19:39:14
【问题描述】:
我尝试混合使用代码 here 和 here 从通过 QtService 初始化的服务运行 GUI exe,但是每当我运行下面的代码时,我都会从 CreateProcessAsUser 收到错误 5。
另外,我看到了类似问题的答案here on StackOverflow,但无法弄清楚 DACL 与问题的关系,并且无法使用 Harry Johnson 的答案,因为我没有登录信息来自用户。
那么,谁能帮我理解为什么我从下面的代码中收到错误 5(拒绝访问)?
if(initUiWin())
log->write("InitUiWin executed.");
else {
QString errorNumber = QString::number(GetLastError());
log->write("InitUiWin error: " + errorNumber);
}
-
bool initUiWin()
{
// obtain the currently active session id; every logged on
// User in the system has a unique session id
uint dwSessionId = WTSGetActiveConsoleSessionId();
// obtain the process id of the winlogon process that
// is running within the currently active session
QString processName("winlogon.exe");
DWORD winlogonPID = FindProcessId(processName.toStdWString(),dwSessionId);
if( winlogonPID != 0 ) {
HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, winlogonPID);
HANDLE hToken;
OpenProcessToken(hProcess,TOKEN_READ,&hToken);
// Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
SECURITY_ATTRIBUTES sa;
sa.nLength = static_cast<DWORD>(sizeof(SECURITY_ATTRIBUTES));
// copy the access token of the winlogon process;
// the newly created token will be a primary token
HANDLE hUserTokenDup;
if (!DuplicateTokenEx(hToken,MAXIMUM_ALLOWED,&sa,
SecurityIdentification,TokenPrimary,&hUserTokenDup)) {
CloseHandle(hProcess);
CloseHandle(hToken);
return false;
}
// Get Handle to the interactive window station
HWINSTA hwinsta = NULL;
hwinsta = OpenWindowStation(
_T(L"winsta0"), // the interactive window station
FALSE, // handle is not inheritable
READ_CONTROL | WRITE_DAC); // rights to read/write the DACL
if(hwinsta == NULL)
return false;
// To get the correct default desktop, set the caller's
// window station to the interactive window station.
if (!SetProcessWindowStation(hwinsta))
return false;
// Get a handle to the interactive desktop.
HDESK hdesk = NULL;
hdesk = OpenDesktop(
_T(L"default"), // the interactive window station
0, // no interaction with other desktop processes
FALSE, // handle is not inheritable
READ_CONTROL | // request the rights to read and write the DACL
WRITE_DAC |
DESKTOP_WRITEOBJECTS |
DESKTOP_READOBJECTS);
if(hdesk == NULL)
return false;
// Get the SID for the client's logon session.
PSID pSid = NULL;
if (!GetLogonSID(hUserTokenDup, &pSid))
return false;
// Allow logon SID full access to interactive window station.
if (!AddAceToWindowStation(hwinsta, pSid) )
return false;
// Allow logon SID full access to interactive desktop.
if (!AddAceToDesktop(hdesk, pSid) )
return false;
// Impersonate client to ensure access to executable file.
if (!ImpersonateLoggedOnUser(hUserTokenDup) )
return false;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb = static_cast<DWORD>(sizeof(STARTUPINFO));
// interactive window station parameter; basically this indicates
// that the process created can display a GUI on the desktop
wchar_t auxBuffer[16] = L"winsta0\\default";
si.lpDesktop = auxBuffer;
// flags that specify the priority and creation method of the process
int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB;
// create a new process in the current User's logon session
bool result = CreateProcessAsUser(hUserTokenDup, // client's access token
L"test-ui-systray.exe", // file to execute
NULL, // command line
&sa, // pointer to process SECURITY_ATTRIBUTES
&sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
dwCreationFlags, // creation flags
NULL, // pointer to new environment block
NULL, // name of current directory
&si, // pointer to STARTUPINFO structure
&pi // receives information about new process
);
if (pSid)
FreeLogonSID(&pSid);
if (hdesk)
CloseDesktop(hdesk);
if (hwinsta)
CloseWindowStation(hwinsta);
CloseHandle(pi.hThread);
CloseHandle(pi.hProcess);
return result;
}
return false;
}
【问题讨论】:
-
如果某个函数(如
CreateProcessAsUser)失败,您应该在该点调用GetLastError()并保存错误代码。目前您正在调用其他函数,如CloseDesktop、CloseWindowStation等,所有这些都可能与GetLastError()返回的错误代码相混淆。 -
您的服务是否以
LocalSystem运行?如果是这样,MSDN 文章非常清楚该怎么做。 (WTSQueryUserToken (WTSGetActiveConsoleSessionId (), &hToken);然后CreateProcessAsUser(hToken, ...)如果您不是以LocalSystem运行,那么“没有合法 方法来获取具有正确会话ID 的登录用户令牌”。 -
更改窗口站和桌面权限的逻辑错误 - 该代码更改了您的窗口站和桌面上的权限,而不是用户的窗口站和桌面上的权限会议。但在这种情况下,您无论如何都不需要更改权限。您确定是 CreateProcessAsUser 失败而不是其他功能之一吗?
-
最明显的问题是
sa没有初始化。 -
我认为这是为@JonathanPotter 准备的。我在问您的服务是否以
LocalSystem运行。