Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CreateDesktop() with vista and UAC on (C, windows)

I asked this in CreateDesktop() with Vista UAC (C Windows) I set a bounty but in trying to vote down the only answer the "accept" was pressed by mistake (i've been awake for more than 48 hs). so I am asking it again.

I'm using CreateDesktop() to create a temporary desktop where an application will run, perform a cleanup action (while remaining out of the way) and terminate. I'm closing that desktop once the application is gone. Everything is fine when using Windows XP and even Vista. The problem arises when you enable the (annoying) UAC.

Everything is OK when you create a desktop, but when you call CreateProcess() to open a program on that desktop it causes the opened application to crash with an exception on User32.dll.

I've been reading a lot about the different desktops and layers on Windows and the restrictions of memory. However, most of the programs I open (as test scenarios) are OK, but a few (like IE, Notepad, Calc and my own application) cause the crash.

Anyone has any idea why this happen on Vista with UAC, or more specifically for those specific programs? and how to fix this?

Anyone has a good solid example on how to create a desktop and open an application there without switching to it under Vista with UAC on?

Code is appreciated.

Thanks

The code used is

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;
like image 931
wonderer Avatar asked Sep 08 '09 17:09

wonderer


2 Answers

The correct solution is given as a short comment by ChristianWimmer above:

The desktop must have a security descriptor that allows access to lower integrity level like IE has. Otherwise the GUI cannot access the desktop. – ChristianWimmer Jul 22 '10 at 17:00

Since the answer is a little bit hidden and there's no source code example, let me state it clearly here:

If IE runs in protected mode then the browser tabs are created as low integrity processes. The low integrity tab process will fail to initialize if the desktop does not have a low integrity mandatory label.

As a consequence, the main IE process terminates, too. An interesting observation is that if you start IE providing a command line URL from the secure zone, then IE will succeed to start, because protected mode is disabled by default for the secure zone.

I checked the integrity level of the default desktop, and indeed I was able to verify that the default desktop has a low integrity level! So the easiest solution to the problem is to (1) create the new desktop, (2) get the mandatory label from the default desktop, and (3) copy it into the new desktop. For (2) and (3), you can use the following code

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: Thanks for providing the hint to the correct solution. This saved my a lot of time!!

like image 189
msp Avatar answered Sep 30 '22 13:09

msp


You appear to have come across a bug in IE as it interacts with UAC. If protected mode is set to on you cannot run IE as an ordinary user in any desktop except the default one. In order to run IE in an alternate desktop you must be running as administrator or have protected mode set to off. This is true for Vista, W2K8 and Win7.

As to the other programs that you cannot run, unfortunately I can't confirm anything. I tried upwards of thirty different programs including notepad, calc, all the office apps, visual studio 2005, 2008 and 2010, MSDN help and a number of others and all worked as expected with the noted exception of IE. Is there something truly unusual about your app that might make it behave in an unexpected manner?

One note - if you attempt to run an application like this that needs elevation (such as regedit, etc.) it will fail in CreateProcess with the last error set to ERROR_ELEVATION_REQUIRED.

For your reference, in case I'm doing something different from you, the code I used is:

#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;
}
like image 42
Stephen Martin Avatar answered Sep 30 '22 12:09

Stephen Martin