【问题标题】:How do I run my application while a UAC dialog window is showing?在显示 UAC 对话窗口时如何运行我的应用程序?
【发布时间】:2011-02-18 18:48:30
【问题描述】:

我有一个用 .NET 编写的应用程序。它需要保持运行并能够访问 UAC 对话窗口打开的桌面,并使用键盘和鼠标事件与该桌面交互。

它有点像 VNC 程序。假设您正在运行一个 VNC 程序并弹出一个 UAC 窗口,您希望您的 VNC 程序仍然能够控制 包含 UAC 窗口的桌面,以便用户可以移动鼠标并单击UAC 对话框上的 OK 按钮。谁能告诉我我会怎么做?

谢谢

【问题讨论】:

  • 不,鼠标和键盘不起作用,因为我的应用程序仍在原始桌面上运行,并且 UAC 窗口位于安全桌面上,我的程序无法访问该桌面。我需要能够找到那个安全的桌面然后在上面运行我的程序。
  • 如果你能做到这一点,它不会使它成为一个安全的桌面,它会......;)

标签: .net windows vb.net uac


【解决方案1】:

我建议您从阅读documentation 开始。我想也许你可以打开窗口站并将你的进程附加到它,但我对 Windows 的这方面不是很熟悉。

编辑 1:

在 Windows XP 中,当以 SYSTEM 身份运行时,我能够通过 OpenDesktop 访问安全桌面(“winlogon”);安全桌面上的 ACL 只允许访问 SYSTEM 帐户。打开它后,我可以列举它上面的窗户,虽然只有少数几个。也许您可以设置一个窗口挂钩并监听特定对话框的创建。我不确定 Vista 是否改变了这个模型,所以它可能行不通;我面前没有要测试的 Vista 机器。

编辑 2:

好的,我得到了最有效的东西(在 Windows 7 上测试)。首先,您必须有一个以 SYSTEM 身份运行的服务。从该服务中,您需要在用户会话中启动一个单独的应用程序。为此,请枚举所有查找 winlogon.exe 的进程,打开其令牌,然后 CreateProcessAsUser。为 STARTUPINFO 的 lpDesktop 参数指定“WinSta0\Winlogon”。现在,您在“Winlogon”桌面上的用户会话中以 SYSTEM 身份运行了一个进程。在新的流程中,你可以为所欲为;我使用 EnumDesktopWindows 进行了快速测试,我能够获取各种 UAC 相关窗口的窗口类和文本(“$$$Secure UAP 背景窗口”、“$$$Secure UAP 背景假客户端窗口”等)。不过,我不确定如何确定何时显示 UAC 提示;作为一种快速破解,您可以每 100 毫秒运行一次循环以查找 UAC 窗口或其他东西。如果有帮助,我可以粘贴一些代码。

编辑 3:

好的。我编写了一个 Win32 服务,它采用以下参数:

/install - 安装服务
/uninstall - 卸载服务
/service - 作为服务运行;通过 SCM 调用
/client - 作为客户端运行;通过 CreateProcessAsUser 调用

唯一有趣的代码是 /service 和 /client 模式。

在 /service 模式下,它通过 EnumProcesses 和 GetModuleFileNameEx 枚举正在运行的进程以查找“winlogon.exe”。当它找到一个时,它会打开它的令牌并通过 CreateProcessAsUser 以 /client 模式启动自己:

HANDLE hProcess = ...;
// winlogon.exe runs as SYSTEM in user's session; we need to run the same way
HANDLE hToken = NULL;
if(OpenProcessToken(hProcess, TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY, &hToken))
{
    TCHAR szCommandLine[MAX_PATH];
    GetModuleFileName(NULL, szCommandLine, MAX_PATH);
    PathQuoteSpaces(szCommandLine);
    // run in /client mode
    _tcscat_s(szCommandLine, MAX_PATH, _T(" /client"));
    STARTUPINFO StartupInfo;
    ZeroMemory(&StartupInfo, sizeof(STARTUPINFO));
    StartupInfo.cb = sizeof(STARTUPINFO);
    // run on the Winlogon desktop
    StartupInfo.lpDesktop = _T("WinSta0\\Winlogon");
    PROCESS_INFORMATION ProcessInformation;
    ZeroMemory(&ProcessInformation, sizeof(PROCESS_INFORMATION));
    if(CreateProcessAsUser(hToken, NULL, szCommandLine, NULL, NULL, FALSE, 0, NULL, NULL, &StartupInfo, &ProcessInformation))
    {
        CloseHandle(ProcessInformation.hThread);
        ProcessInformation.hThread = NULL;
        CloseHandle(ProcessInformation.hProcess);
        ProcessInformation.hProcess = NULL;
    }
    CloseHandle(hToken);
    hToken = NULL;
}

在 /client 模式下,它通过一堆 FindWindow 和 FindWindowEx 调用单击 UAC 提示符上的“是”按钮。您可以使用 Spy++ 来确定窗口层次结构。

HWND hWnd = ...;
HWND hWndButton = FindWindowEx(hWnd, NULL, _T("Button"), NULL);
if(hWndButton != NULL)
{
    // see if this is the "Yes" button
    TCHAR szText[32];
    if(GetWindowText(hWndButton, szText, 32) && _tcsicmp(szText, _T("&Yes")) == 0)
    {
        // click it
        SendMessage(hWndButton, BM_CLICK, 0, 0);
    }
}

我测试这个的方法是坚持 Sleep(5000);在 /client 代码中。然后我启动服务并立即执行一些触发 UAC 提示的操作(即运行 regedit)。 5 秒后 /client 代码将唤醒并找到并单击“是”按钮。您可以在 Winlogon 桌面上运行其他进程; cmd.exe 和 spyxx.exe (Spy++) 是最有用的。不幸的是,explorer.exe 在 Winlogon 桌面上运行时会出现很多问题并且不是很有用。要进入 Winlogon 桌面,您可以运行 regedit 然后 Alt+Tab 切换到其他应用程序。如果您想变得花哨,您可以编写自己的桌面切换实用程序(使用 SwitchDesktop 函数),这样您就不必触发 UAC 提示符即可进入 Winlogon 桌面。如果你想变得非常花哨,你可以设置一个全局窗口挂钩来监控窗口的创建;当 UAC 对话框即将显示时,您可以准备单击其“是”按钮。不过,我并没有走那么远。

【讨论】:

  • 感谢您的代码。有兴趣在合同基础上为我工作吗?
  • 我在 vb.net 中编译并运行了它。每一步都返回真,但我在“ProcessInformation”中得到一个零进程 ID,即使函数返回真,所以它似乎没有创建进程。当这工作时,我会在我的 Windows 登录屏幕上看到我的应用程序的窗口吗?运行此程序时是否必须在登录屏幕上?在 winlogon 桌面上运行它与在 UAC 窗口显示的桌面上运行它相同吗?您可以提供的任何提示将不胜感激。谢谢!
  • 时间太长了,具体内容我已经记不太清了。如果我没记错的话,我相信它出现在 UAC 提示出现的同一个桌面上。我想我通过运行 regedit 对其进行了测试,它显示出来了,所以它总是显示 UAC 提示符。一旦在 UAC 桌面上,您可以 ALT+TAB 到另一个应用程序。
  • @Luke:你的帖子很有帮助!您介意提供此服务的完整代码吗?
  • 我确定我没有它了,对不起。
【解决方案2】:

问题是 UAC 提示没有在当前桌面上打开,而是在一个全新的Secure Desktop 中打开,它会暂停所有当前打开的桌面。

这是故意的,因为不允许程序与此对话框交互。

有一个例外:根据this blog entry,“受信任的 SYSTEM 进程可以在安全桌面上运行”。

【讨论】:

  • 是的,这是正确的,但是当 UAC 窗口打开时,仍然可以让您的程序在安全桌面上运行。 VNC 程序会这样做,否则它们将毫无用处。
  • 好吧,它们不会完全没用。如果它是您的机器,您可以随时关闭 UAC。 GotoMyPC 显然已经解决了这个问题,但我不知道如何。
  • 关闭 UAC 实际上并不是一个好的选择,因为这样做会禁用操作系统的一些其他功能。
  • 有一个例外:以 SYSTEM 用户身份运行的受信任进程仍然可以与安全桌面交互。
  • @Ray:“用户模式”应用程序无法与显示 UAC 提示的 WinStation(安全桌面)交互。否则,此类用户模式应用程序可能会与 UAC 提示交互并自动为您“单击”按钮,这将完全违背最初显示提示的目的。
【解决方案3】:

我想您可能需要作为 Windows 服务运行才能在 UAC 处于活动状态时被允许执行。

【讨论】:

  • 是的,但作为服务运行是不够的。
【解决方案4】:

我相信您在 UAC 提示期间在屏幕上看到的所有内容都是屏幕截图(对话框本身除外)

【讨论】:

  • 它会创建一个新桌面并使用您桌面的屏幕截图作为背景,但它仍然是一个功能齐全的桌面,可以在其上运行其他程序。
  • @Ray:它不是“功能齐全的桌面”(实际上它甚至不是桌面,它是 WinStation),其他程序无法在其上运行,因为它是孤立的。
【解决方案5】:

你不能这样做。默认情况下,当出现 UAC 提示时,它实际上是在一个独立的 WinStation 中运行,该 WinStation 不同于运行“正常”应用程序的 WinStation。此 WinStation 是专门隔离的,以防止用户应用程序与 UAC 提示进行交互。它看起来像您的桌面,因为 WinStation 的背景实际上是您桌面的静态位图图像,就在显示 UAC 提示符之前。

我怀疑这可能是您正在运行的 VNC 版本中的问题,因为我相当确定远程桌面提供了正确的行为,并允许您的用户仍然通过远程桌面客户端与 UAC 提示进行交互。请记住,在运行任何类型的远程客户端(远程桌面、VNC 等)时,这个想法是客户端应该允许您执行您通常坐在键盘前能够执行的任何操作。

【讨论】:

  • 有可能。很多 VNC 程序都可以做到这一点,包括 logmein.com。
猜你喜欢
  • 2010-11-03
  • 1970-01-01
  • 2010-09-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多