【问题标题】:ImpersonateLoggedOnUser not working in windows serviceImpersonateLoggedOnUser 在 Windows 服务中不起作用
【发布时间】:2020-03-04 06:54:16
【问题描述】:

我正在尝试从 Windows 服务(以 SYSTEM 身份运行)调用 Windows api(似乎只在登录用户的上下文中工作)。我能够获得登录用户的令牌。当我调用 ImpersonateLoggedOnUser() 时,我没有收到任何错误,它返回 true。但是 DoSomethingInUserContext() 仍然在 SYSTEM 上下文中执行。我究竟做错了什么?

DWORD sessionIdDw = WTSGetActiveConsoleSessionId();
 
HANDLE hToken;
if (!WTSQueryUserToken(sessionIdDw, &hToken))
  LOG() << "WTSQueryUserToken failed: " << GetLastError();
 
HANDLE hDuplicated = NULL;
if (!DuplicateTokenEx(hToken, TOKEN_ALL_ACCESS, NULL, SecurityImpersonation, TokenImpersonation, &hDuplicated)) {
  LOG() << "DuplicateTokenEx failed: " <<GetLastError();
}
 
if (!ImpersonateLoggedOnUser(hDuplicated)) {
  LOG() << "ImpersonateLoggedOnUser failed " << GetLastError();
}
else {
      DoSomethingInUserContext();

      if (!RevertToSelf()) {
           LOG() << "RevertToSelf failed" << GetLastError();
      }
}
               
CloseHandle(hDuplicated);
CloseHandle(hToken);

【问题讨论】:

  • 不是因为我使用的winapi不接受用户令牌
  • @NGambit 模拟不是正确的解决方案。 EnumWindows() 枚举与调用线程关联的桌面窗口。模拟不会改变调用线程的桌面。因此,您正在枚举服务会话中的窗口,而不是用户会话。请参阅Why EnumWindows Not Working in service? 此外,由于会话 0 隔离,“允许服务与桌面交互”在 Vista+ 中不再有效。
  • “HKLM\System\CurrentControlSet\Services”中的服务模板条目将具有包含SERVICE_USER_SERVICE (0x40) 标志的类型。服务控制管理器为每个用户会话生成一个 LUID,并在会话中启动一个名称中包含此 LUID 的用户服务实例。一些示例:“CDPUserSvc_LUID”、“OneSyncSvc_LUID”、“WpnUserService_LUID”、“LxssManagerUser_LUID”。

标签: c++ windows winapi impersonation


【解决方案1】:

cmets 足够详细指出原因,EnumWindows 按会话枚举。

创建用户服务是一种可行的方法。而且下面的方法也有效:

TCHAR Command[MAX_PATH] = L"C:\\EnumWindows.exe";

DWORD sessionIdDw = WTSGetActiveConsoleSessionId();
logfile(sessionIdDw);
HANDLE hToken;
if (!WTSQueryUserToken(sessionIdDw, &hToken))
    LOG() << "WTSQueryUserToken failed: " << GetLastError();
PROCESS_INFORMATION pi;
STARTUPINFO si;
ZeroMemory(&pi, sizeof(pi));
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);

if(!CreateProcessAsUser(hToken,NULL,Command,NULL,NULL,FALSE,0,NULL,NULL,&si,&pi))
    LOG() << "CreateProcessAsUser failed: " << GetLastError();
else
{
    WaitForSingleObject(pi.hProcess, INFINITE);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
}

新进程正在用户会话中运行。

编辑:

感谢@Eryk 指出,Window Stations

每个会话都与它自己的交互式窗口站相关联

SetThreadDesktop:

桌面必须与当前窗口站相关联 过程。

SetProcessWindowStation:

窗口站必须与当前会话相关联。

所以SetThreadDesktop 在这里不起作用。

【讨论】:

  • EnumWindows 枚举桌面上的窗口,桌面包含在 WindowStation 中。进程只能连接到其会话中的 WindowStation。您的示例切换到会话 0“WinSta0”,它与用户会话的“WinSta0”无关。每个会话都有一个“WinSta0”。完全限定名称是“\Sessions\\Windows\WindowStations\WinSta0”。 API 仅限于使用非限定名称“WinSta0”,但由于无论如何我们都仅限于当前会话,因此不会丢失任何功能。
猜你喜欢
  • 2010-12-05
  • 2018-08-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-03-02
相关资源
最近更新 更多