当UAC对话框窗口显示时,我该如何运行我的应用程序?

8
我有一个用.NET编写的应用程序。它需要保持运行状态并访问UAC对话框窗口所在的桌面,并使用键盘和鼠标事件与该桌面进行交互。
这有点像VNC程序。想象一下,你正在运行一个VNC程序,然后出现了一个UAC窗口,你希望你的VNC程序仍然能够控制包含UAC窗口的桌面,以便用户可以移动鼠标并单击UAC对话框上的“确定”按钮。请问有谁知道我应该如何做到这一点?
谢谢。

不,鼠标和键盘无法工作,因为我的应用程序仍在原始桌面上运行,而UAC窗口位于安全桌面上,我的程序无法访问。我需要能够找到该安全桌面,然后在其上运行我的程序。 - Ray
1
如果你能做到那样,那就不会是一个安全的桌面了,对吧...;) - siride
5个回答

7
我建议您先阅读文档。我猜您可以打开窗口工作站并将您的进程附加到它,但我对Windows的这个领域不是很熟悉。
编辑1: 在Windows XP中,当以SYSTEM身份运行时,我能够通过OpenDesktop访问安全桌面("winlogon");安全桌面的ACL仅允许SYSTEM帐户访问。打开后,我可以枚举其上的窗口,尽管只有少数几个。也许您可以设置一个窗口挂钩并监听特定对话框的创建。我不确定Vista是否改变了这个模型,所以也许它不起作用;我没有一台Vista机器来测试。
编辑2: 好的,我找到了基本可行的方法(在Windows 7上测试过)。首先,您必须拥有一个以SYSTEM身份运行的服务。从该服务中,您需要在用户会话中启动一个单独的应用程序。为此,枚举所有进程,查找winlogon.exe,打开其令牌,并使用CreateProcessAsUser创建进程。将“WinSta0\Winlogon”指定为STARTUPINFO的lpDesktop参数。现在,在“Winlogon”桌面上有一个以SYSTEM身份运行的进程在用户会话中运行。在新进程中,您可以做任何想做的事情;我使用EnumDesktopWindows进行了快速测试,并能够获取各种与UAC相关的窗口的窗口类和文本(“$$$Secure UAP Background Window”,“$$$Secure UAP Background Fake Client Window”等)。但我不确定如何确定何时显示UAC提示;作为一个快速的hack,您可以每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;
}

在客户端模式下,它通过一系列的FindWindow和FindWindowEx调用来点击UAC提示上的"Yes"按钮。您可以使用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);
    }
}

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

谢谢你提供的代码。有没有兴趣以合同方式为我工作? - Ray
我已经在vb.net中编译并运行了这个程序。每一步都返回true,但是在“ProcessInformation”中我得到了一个零的进程ID,尽管函数返回true,所以它似乎没有创建进程。当这个程序工作时,我会真正看到我的应用程序窗口显示在我的Windows登录屏幕上吗?我必须在登录屏幕上运行它吗?在winlogon桌面上运行它是否与在UAC窗口显示的桌面上运行它相同?如果您能提供任何提示,将不胜感激。谢谢! - Ray
已经很久了,我真的不记得具体细节了。如果我没记错的话,我相信它是出现在与UAC提示相同的桌面上的。我想我通过运行regedit进行了测试,因为它被清单化了,所以它总是显示UAC提示。一旦在UAC桌面上,您可以使用ALT+TAB切换到其他应用程序。 - Luke
@Luke:你的帖子非常有用!你介意提供这个服务的完整代码吗? - divB
抱歉,我确定我已经没有它了。 - Luke

5
问题在于UAC提示框不会在当前桌面上打开,而是在一个全新的安全桌面中打开,这会暂停任何当前打开的桌面。
这是有意为之的,因为程序不允许与此对话框交互。
但有一个例外:“可信系统进程可以在安全桌面上运行”,根据这篇博客文章

是的,那是正确的,但当UAC窗口打开时,仍然有可能让您的程序在安全桌面上运行。VNC程序就是这样做的,否则它们将毫无用处。 - Ray
好吧,它们不会完全没用。如果这是你自己的机器,你可以随时关闭UAC。GotoMyPC显然已经解决了这个问题,但我不知道具体是怎么做到的。 - Robert Harvey
关闭UAC实际上并不是一个好的选择,因为这样做会禁用操作系统的一些其他功能。 - Ray
2
有一个例外:以SYSTEM用户身份运行的受信任进程仍然可以与安全桌面交互。 - Powerlord
@Ray:一个“用户模式”应用程序无法与显示UAC提示的WinStation(安全桌面)进行交互。否则,这样的用户模式应用程序可以与UAC提示交互并自动为您“点击”按钮,这将完全击败首次显示提示的目的。 - Scott Dorman
作为一个服务,它应该能够做到。我的应用程序也使用证书签名。 - Ray

0

我想你可能需要作为Windows服务运行,才能在UAC激活时被允许执行。


是的,但作为服务运行还不够。 - Ray

0

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


它创建一个新的桌面,并使用你的桌面截图作为背景,但它仍然是一个完全功能的桌面,其他程序可以在其上运行。 - Ray
@Ray:它不是“完全功能的桌面”(实际上它甚至不是一个桌面,而是一个WinStation),其他程序无法在其上运行,因为它是隔离的。 - Scott Dorman

-1

你做不到这件事。默认情况下,当UAC提示出现时,它实际上在运行一个与运行“正常”应用程序不同的隔离WinStation。这个WinStation是专门隔离的,以防止用户应用程序与UAC提示交互。它看起来像你的桌面,因为那个WinStation的背景实际上是一个静态位图图像,显示了UAC提示显示前的桌面。

我怀疑这可能是VNC版本中的问题,因为我相当确定远程桌面提供了正确的行为,并允许您通过远程桌面客户端与UAC提示进行交互。请记住,在运行任何类型的远程客户端(远程桌面,VNC等)时,理念是客户端应该允许您执行与您在物理键盘上坐在那里时相同的任何操作。


2
可以的。许多VNC程序都能够做到,包括logmein.com。 - Ray

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接