我有一个用.NET编写的应用程序。它需要保持运行并访问UAC对话框窗口打开的桌面,并使用键盘和鼠标事件与该桌面交互。
这有点像VNC程序。想象一下,您正在运行VNC程序并弹出一个UAC窗口,您希望您的VNC程序仍然可以通过其中的UAC窗口控制桌面,以便用户可以移动鼠标并单击UAC对话框上的“确定”按钮。谁能告诉我怎么做呢?
由于
答案 0 :(得分:6)
我建议你先阅读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 Background Window”,“$$$ Secure UAP Background Fake Client Window”等)。我不知道如何确定何时显示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);
}
}
我测试的方法是坚持睡眠(5000);在/客户端代码中。然后我启动服务并立即执行触发UAC提示的操作(即运行regedit)。 5秒后,/客户端代码将被唤醒并找到并单击“是”按钮。您可以在Winlogon桌面上运行其他进程; cmd.exe和spyxx.exe(Spy ++)最有用。不幸的是,explorer.exe在Winlogon桌面上运行时出现了很多问题并且不是很有用。要进入Winlogon桌面,您可以运行regedit,然后按Alt + Tab切换到其他应用程序。如果您想获得想象,您可以编写自己的桌面切换实用程序(使用SwitchDesktop功能),这样您就不必触发UAC提示即可访问Winlogon桌面。如果你想真正想要你可以设置一个全局窗口挂钩来监视窗口创建;当即将显示UAC对话框时,您可以准备单击其“是”按钮。不过,我并没有那么深入。
答案 1 :(得分:4)
问题是UAC提示不会在当前桌面上打开,而是在全新的Secure Desktop中打开,它会挂起任何当前打开的桌面。
这是故意的,因为不允许程序与此对话框进行交互。
根据this blog entry,有一个例外:“受信任的SYSTEM进程可以在安全桌面上运行”。
答案 2 :(得分:0)
我认为您可能需要作为Windows服务运行才能在UAC处于活动状态时执行。
答案 3 :(得分:0)
我相信您在UAC提示期间在屏幕上看到的所有内容都是截图(对话框本身除外)
答案 4 :(得分:-1)
你不能这样做。默认情况下,当出现UAC提示时,它实际上在一个独立的WinStation中运行,该WinStation与运行“普通”应用程序的WinStation不同。此WinStation专门用于防止用户应用程序与UAC提示交互。它看起来像您的桌面,因为该WinStation的背景实际上是桌面的静态位图图像,就像显示UAC提示之前一样。
我怀疑这可能是您正在运行的VNC版本中的一个问题,因为我相当确定远程桌面提供了正确的行为,并允许用户仍然通过远程桌面客户端与UAC提示进行交互。请记住,在运行任何类型的远程客户端(远程桌面,VNC等)时,我们的想法是,如果您实际坐在键盘上,客户应该允许您执行通常能够执行的任何操作。