Nor*_*ert 4 winapi uac windows-security uipi sendinput
我们正在编写一个仅运行的远程桌面应用程序,它使用 SendInput 进行键盘(和鼠标)交互。但是它无法与 UAC 提示交互。
我们的应用程序为此需要什么权限/权利?
背景信息:该应用程序是由复制 winlogon.exe 的访问令牌的另一个进程生成的。这使得可以在具有系统完整性级别的 SYSTEM 帐户下运行,附加到物理控制台会话,并具有与 winlogon.exe 相同的 SE 权限(https://learn.microsoft.com/en-us/windows/desktop/secauthz/特权常量),尽管并非所有这些都已启用。
struct MY_TOKEN_PRIVILEGES {
  DWORD PrivilegeCount;
  LUID_AND_ATTRIBUTES Privileges[2];
};
int RunUnderWinLogon(LPCWSTR executableWithSendInput)
{
  DWORD physicalConsoleSessionId = WTSGetActiveConsoleSessionId();
  auto winlogonPid = GetWinLogonPid(); // external function
  if (!winlogonPid)
  {
    std::cout << "ERROR getting winlogon pid" << std::endl;
    return 0;
  }
  HANDLE hWinlogonToken, hProcess;
  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, &hWinlogonToken))
  {
    printf("Process token open Error: %u\n", GetLastError());
  }
  // Is security descriptor needed for SendInput?
  PSECURITY_DESCRIPTOR pSD = NULL;
  SECURITY_ATTRIBUTES saToken;
  ZeroMemory(&saToken, sizeof(SECURITY_ATTRIBUTES));
  saToken.nLength = sizeof (SECURITY_ATTRIBUTES);
  saToken.lpSecurityDescriptor = pSD;
  saToken.bInheritHandle = FALSE;
  HANDLE hWinlogonTokenDup;
  if (!DuplicateTokenEx(hWinlogonToken, TOKEN_ALL_ACCESS, &saToken, SecurityImpersonation, TokenPrimary, &hWinlogonTokenDup))
  {
    printf("DuplicateTokenEx Error: %u\n", GetLastError());
  }
  if (!SetTokenInformation(hWinlogonTokenDup, TokenSessionId, (void*)physicalConsoleSessionId, sizeof(DWORD)))
  {
    printf("SetTokenInformation Error: %u\n", GetLastError());
  }
  //Adjust Token privilege
  LUID luidSeDebugName;
  if (!LookupPrivilegeValue(NULL, SE_DEBUG_NAME, &luidSeDebugName))
  {
    printf("Lookup Privilege value Error: %u\n", GetLastError());
  }
  LUID luidSeTcbName;
  if (!LookupPrivilegeValue(NULL, SE_TCB_NAME, &luidSeTcbName))
  {
    printf("Lookup Privilege value Error: %u\n", GetLastError());
  }
  MY_TOKEN_PRIVILEGES tp;
  tp.PrivilegeCount = 2;
  tp.Privileges[0].Luid = luidSeDebugName;
  tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
  tp.Privileges[1].Luid = luidSeTcbName;
  tp.Privileges[1].Attributes = SE_PRIVILEGE_ENABLED;
  if (!AdjustTokenPrivileges(hWinlogonTokenDup, FALSE, (PTOKEN_PRIVILEGES)&tp, /*BufferLength*/0, /*PreviousState*/(PTOKEN_PRIVILEGES)NULL, NULL))
  {
    printf("Adjust Privilege value Error: %u\n", GetLastError());
  }
  if (GetLastError() == ERROR_NOT_ALL_ASSIGNED)
  {
    printf("Token does not have the privilege\n");
  }
  DWORD creationFlags;
  creationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE;
  LPVOID pEnv = NULL;
  if (CreateEnvironmentBlock(&pEnv, hWinlogonTokenDup, TRUE))
  {
    std::cout << "CreateEnvironmentBlock() success" << std::endl;
    creationFlags |= CREATE_UNICODE_ENVIRONMENT;
  }
  SECURITY_ATTRIBUTES saProcess, saThread;
  ZeroMemory(&saProcess, sizeof(SECURITY_ATTRIBUTES));
  ZeroMemory(&saThread, sizeof(SECURITY_ATTRIBUTES));
  saProcess.nLength = sizeof (SECURITY_ATTRIBUTES);
  saProcess.lpSecurityDescriptor = pSD;
  saProcess.bInheritHandle = FALSE;
  saThread.nLength = sizeof (SECURITY_ATTRIBUTES);
  saThread.lpSecurityDescriptor = pSD;
  saThread.bInheritHandle = FALSE;
  STARTUPINFO si;
  ZeroMemory(&si, sizeof(STARTUPINFO));
  si.cb = sizeof(STARTUPINFO);
  si.lpDesktop = (LPWSTR)L"winsta0\\default";
  PROCESS_INFORMATION pi;
  ZeroMemory(&pi, sizeof(pi));
  BOOL bResult = CreateProcessAsUser(
    hWinlogonTokenDup,   // client's access token
    executableWithSendInput,    // file using SendInput
    NULL,                 // command line
    &saProcess,            // pointer to process SECURITY_ATTRIBUTES
    &saThread,               // pointer to thread SECURITY_ATTRIBUTES
    FALSE,              // handles are not inheritable
    creationFlags,     // creation flags
    pEnv,               // pointer to new environment block
    NULL,               // name of current directory
    &si,               // pointer to STARTUPINFO structure
    &pi                // receives information about new process
  );
}
SendInput与 SendMessage 和 PostMessage 一样,仅限于同一登录会话中的进程之间以及与目标进程位于同一桌面内的进程之间的工作。UAC 提示符显示在Winlogon 的安全桌面( winsta0\Winlogon) 中,因此您需要定期轮询当前桌面,OpenInputDesktop()然后使用它SetThreadDesktop()来启用当前线程向用户桌面/安全桌面(以活动状态为准)发送消息。
对于 UAC,您需要在系统帐户下运行进程,以符合UIPI 完整性级别检查,就像您已经做的那样。
另请参阅:如何在默认桌面和 Winlogon 桌面之间切换进程?
| 归档时间: | 
 | 
| 查看次数: | 1234 次 | 
| 最近记录: |