【问题标题】:CreateDesktop() with vista and UAC on (C, windows)CreateDesktop() with vista and UAC on (C, windows)
【发布时间】:2019-10-10 18:47:33
【问题描述】:

我在CreateDesktop() with Vista UAC (C Windows) 中问过这个问题 我设置了赏金,但在试图否决唯一的答案时,错误地按下了“接受”(我已经醒了 48 小时以上)。所以我再问一遍。

我正在使用 CreateDesktop() 创建一个临时桌面,应用程序将在其中运行、执行清理操作(同时保持不碍事)并终止。应用程序消失后,我将关闭该桌面。使用 Windows XP 甚至 Vista 时一切正常。当您启用(烦人的)UAC 时,就会出现问题。

创建桌面时一切正常,但是当您调用 CreateProcess() 在该桌面上打开程序时,会导致打开的应用程序崩溃,并在 User32.dll 上出现异常。

我已经阅读了很多关于 Windows 上不同桌面和层以及内存限制的信息。但是,我打开的大多数程序(作为测试场景)都可以,但有一些程序(例如 IE、记事本、Calc 和我自己的应用程序)会导致崩溃。

任何人都知道为什么在带有 UAC 的 Vista 上会发生这种情况,或者更具体地说是针对那些特定程序?以及如何解决这个问题?

任何人都有一个很好的例子来说明如何在打开 UAC 的 Vista 下创建桌面并在其中打开应用程序而不切换到它?

感谢代码。

谢谢

使用的代码是

SECURITY_ATTRIBUTES sa;

HDESK dOld;
HDESK dNew;

BOOL switchdesk, switchdesk2, closedesk;
int AppPid;

sa.bInheritHandle = TRUE;
sa.lpSecurityDescriptor = NULL;
sa.nLength = sizeof(SECURITY_ATTRIBUTES);

//Get handle to current desktop
dOld = OpenDesktopA("default", 0, TRUE, DESKTOP_SWITCHDESKTOP| 
                                        DESKTOP_WRITEOBJECTS|
                                        DESKTOP_READOBJECTS|
                                        DESKTOP_ENUMERATE|
                                        DESKTOP_CREATEWINDOW|
                                        DESKTOP_CREATEMENU);
if(!dOld)
{
    printf("Failed to get current desktop handle !!\n\n");
    return 0;
}

//Make a new desktop
dNew = CreateDesktopA("kaka", 0, 0, 0, DESKTOP_SWITCHDESKTOP|
                                          DESKTOP_WRITEOBJECTS|
                                          DESKTOP_READOBJECTS|
                                          DESKTOP_ENUMERATE|
                                          DESKTOP_CREATEWINDOW|
                                          DESKTOP_CREATEMENU, &sa);

if(!dNew)
{
    printf("Failed to create new desktop !!\n\n");
    return 0;
}

AppPid = PerformOpenApp(SomeAppPath);
if(AppPid == 0)
{
    printf("failed to open app, err = %d\n", GetLastError());
}
else
{
    printf("App pid = %d\n", AppPid);
}


closedesk = CloseDesktop(dNew);

if(!closedesk)
{
    printf("Failed to close new desktop !!\n\n");
    return 0;
}


return 0;

【问题讨论】:

  • 您是在 UI 线程中执行此操作吗?
  • 意义?我的意思是,我正在从应用程序的主线程调用 CreateDesktop
  • 堆栈跟踪也很有帮助
  • 正如我在 cmets 关于我的答案中所说的,这可能不是您想要的答案,但它肯定是一个完全有效的答案。如果您需要更多帮助,我很乐意提供帮助,但不要任性地宣称您对您得到的答案感到失望,您最好使用它们来更深入地挖掘手头的问题。
  • 好吧,首先谢谢。我首先在这里问的原因是因为我已经浪费了几个星期试图自己挖掘答案。否则我不会问。我不想变得粗鲁,但 10 次中有 9 次我看到人们在编程论坛上提问,他们从来没有得到直接的答案。所有得到的是“尝试 X 并尝试 Y”,然后是“也许你可以尝试 Z”。这样的答案只会让人更加困惑。

标签: c windows windows-vista uac


【解决方案1】:

上面 ChristianWimmer 以简短的评论给出了正确的解决方案:

桌面必须有一个安全描述符,允许访问像 IE 一样的较低完整性级别。否则 GUI 无法访问桌面。 – ChristianWimmer 2010 年 7 月 22 日 17:00

由于答案有点隐蔽,而且没有源代码示例,所以我在这里说清楚:

如果 IE 在保护模式下运行,则浏览器选项卡将创建为低完整性进程。如果桌面没有低完整性强制标签,低完整性选项卡进程将无法初始化。

因此,主 IE 进程也终止了。一个有趣的观察是,如果您从安全区域提供命令行 URL 启动 IE,则 IE 将成功启动,因为默认情况下安全区域禁用保护模式。

我检查了默认桌面的完整性级别,并且确实能够验证默认桌面的完整性级别较低!所以解决这个问题最简单的方法是(1)创建新桌面,(2)从默认桌面获取强制标签,(3)将其复制到新桌面。对于(2)和(3),可以使用如下代码

PACL pSacl;
PSECURITY_DESCRIPTOR pSecurityDescriptor;
DWORD dwResult;

dwResult = GetSecurityInfo(hDefaultDesktop, SE_WINDOW_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, &pSacl, &pSecurityDescriptor);

if (dwResult == ERROR_SUCCESS) {
    if (pSacl != NULL) {
        dwResult = SetSecurityInfo(hNewDesktop, SE_WINDOW_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pSacl);

        if (dwResult != ERROR_SUCCESS)
            _tprintf(_T("SetSecurityInfo(hNewDesktop) failed, error = %d"), dwResult);
    }

    LocalFree(pSecurityDescriptor);
} else {
    _tprintf(_T("GetSecurityInfo(hDefaultDesktop) failed, error = %d"), dwResult);
}

@CristianWimmer:感谢您提供正确解决方案的提示。这节省了我很多时间!!

【讨论】:

    【解决方案2】:

    当 IE 与 UAC 交互时,您似乎遇到了一个错误。如果保护模式设置为 on,则除了默认桌面之外,您无法在任何桌面上以普通用户身份运行 IE。为了在备用桌面上运行 IE,您必须以管理员身份运行或将保护模式设置为关闭。 Vista、W2K8 和 Win7 都是如此。

    至于您无法运行的其他程序,很遗憾我无法确认任何事情。我尝试了超过 30 种不同的程序,包括记事本、calc、所有办公应用程序、visual studio 2005、2008 和 2010、MSDN 帮助和许多其他程序,除了 IE 之外,所有程序都按预期工作。您的应用是否存在真正不寻常的地方,可能会导致其行为异常?

    注意 - 如果您尝试运行像这样需要提升的应用程序(例如 regedit 等),它将在 CreateProcess 中失败,最后一个错误设置为 ERROR_ELEVATION_REQUIRED。

    供您参考,如果我做的事情与您不同,我使用的代码是:

    #ifndef _WIN32_WINNT            // Specifies that the minimum required platform is Windows Vista.
    #define _WIN32_WINNT 0x0600     // Change this to the appropriate value to target other versions of Windows.
    #endif
    
    #include <stdio.h>
    #include <tchar.h>
    
    #include "windows.h"
    
    HANDLE PerformOpenApp(TCHAR* appPath);
    
    int _tmain(int argc, _TCHAR* argv[])
    {
        HDESK dNew;
        BOOL closedesk;
        HANDLE hApp;
    
        //Make a new desktop
        dNew = CreateDesktop(_T("kaka"), 0, 0, 0, DESKTOP_SWITCHDESKTOP|
                                                  DESKTOP_WRITEOBJECTS|
                                                  DESKTOP_READOBJECTS|
                                                  DESKTOP_ENUMERATE|
                                                  DESKTOP_CREATEWINDOW|
                                                  DESKTOP_CREATEMENU, NULL);
    
        if(!dNew)
        {
            _tprintf(_T("Failed to create new desktop !!\n\n"));
            return 0;
        }
    
        TCHAR path[MAX_PATH];
        _putts(_T("Enter the path of a program to run in the new desktop:\n"));
        _getts(path);
    
        while(_tcslen(path) > 0)
        {
            hApp = PerformOpenApp(path);
            if(hApp == 0)
            {
                _tprintf(_T("Failed to open app, err = %d\n"), GetLastError());
            }
            else
            {
                _tprintf(_T("App pid = %d\n"), GetProcessId(hApp));
                _putts(_T("Press any key to close the app.\n"));
                _gettchar();
                TerminateProcess(hApp, 0);
                CloseHandle(hApp);
             }
             _putts(_T("Enter the path of a program to run in the new desktop:\n"));
             _getts(path);
        }
    
        closedesk = CloseDesktop(dNew);
    
        if(!closedesk)
        {
            _tprintf(_T("Failed to close new desktop !!\n\n"));
            return 0;
        }
        return 0;
    }
    
    HANDLE PerformOpenApp(TCHAR* appPath)
    {
        STARTUPINFO si = {0};
        PROCESS_INFORMATION pi;
    
        si.cb = sizeof(si);
        si.lpDesktop = _T("kaka");
    
        BOOL retVal = CreateProcess(NULL, appPath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL,
            NULL, &si, &pi);
    
        if (retVal)
        {
            CloseHandle(pi.hThread);
        }
        return pi.hProcess;
    }
    

    【讨论】:

    • 这很奇怪,因为我对 Windows 7 没有问题,不是 IE,不是我的应用程序,也不是任何完全开启 UAC 的应用程序
    • 我用几个不同的配置仔细检查了 Win7,但我仍然无法在另一个桌面上运行 IE。虽然在 Win7 上该进程简单地消失了,但没有崩溃对话框或应用程序崩溃事件日志条目。
    • 为了完整起见,这个问题被自动授予答案。这不是一个答案。我没有把它设置为答案。
    • 这可能不是您想要的答案,但它肯定是一个答案,并且是您在没有更多信息的情况下可能得到的最佳答案。我按照说明重新创建了您的环境,并尝试重现您的问题。重新创建了 IE 的问题并给出了原因。无法重现其他程序的问题 - 因此您要么对问题有误,要么环境与所述情况不符。我很乐意帮助您解决此问题,但您需要提供更多信息。特别是,一个重现问题的小程序将是非常宝贵的。
    • 桌面必须有一个安全描述符,允许访问像 IE 一样的较低完整性级别。否则 GUI 无法访问桌面。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-21
    • 1970-01-01
    • 2017-11-02
    • 2010-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多