2

i have a problem in an application using Windows API CreateProcessAsUser from local system admin in order to run an application as a different user. Everything works fine so far, but the Windows window and frame style are not applied somehow. The window always looks like a Windows 2000 window with huge frames. I also attached some screenshot

Broken style window

I also wrote some example code of how we do all the magic in C++ without taking care of handles and stuff.

Just make sure that you have locally some user "test" with password "test" set and try to run the posted source code as local system administrator. Other user will cause an error code 1413 if you try to execute the code.

The problem occurres mainly on Windows 7 VMs in VirtualBox, on some Windows 7 systems and on all Windows 8.1 systems. Very strange. Can anyone help me to solve this problem? Thanks!

#include <iostream>
#include <Windows.h>
#include <UserEnv.h>
#include <WinWlx.h>

int AddAceToWindowStation( HWINSTA  hwinsta, PSID psid )
{
    DWORD lengthNeeded;

    SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
    if( !GetUserObjectSecurity( hwinsta, &secInfo, NULL, NULL, &lengthNeeded ) )
    {
        if ( GetLastError() != 122 )
        {
            std::cout << "GetUserObjectSecurity1 error: " << GetLastError() << std::endl;
            return 0;
        }
    }

    PSECURITY_DESCRIPTOR pSecDescriptor = ( PSECURITY_DESCRIPTOR ) HeapAlloc(
        GetProcessHeap(),
        HEAP_ZERO_MEMORY,
        lengthNeeded );

    if ( pSecDescriptor == NULL )
    {
        std::cout << "Allocating memory for pSecDescriptor failed: " << GetLastError() << std::endl;
        return 0;
    }

    PSECURITY_DESCRIPTOR pSecDescriptorNew = ( PSECURITY_DESCRIPTOR ) HeapAlloc(
        GetProcessHeap(),
        HEAP_ZERO_MEMORY,
        lengthNeeded );

    if ( pSecDescriptorNew == NULL )
    {
        std::cout << "Allocating memory for pSecDescriptorNew failed: " << GetLastError() << std::endl;
        return 0;
    }

    if ( !GetUserObjectSecurity( hwinsta, &secInfo, pSecDescriptor, lengthNeeded, &lengthNeeded ) )
    {
        std::cout << "GetUserObjectSecurity2 error: " << GetLastError() << std::endl;
        return 0;
    }

    if ( !InitializeSecurityDescriptor( pSecDescriptorNew, SECURITY_DESCRIPTOR_REVISION ) )
    {
        std::cout << "InitializeSecurityDescriptor error: " << GetLastError() << std::endl;
        return 0;
    }

    BOOL DaclPresent;
    PACL pOldDacl;
    BOOL DaclDefaulted;
    if ( !GetSecurityDescriptorDacl( pSecDescriptor, &DaclPresent, &pOldDacl, &DaclDefaulted ) )
    {
        std::cout << "GetSecurityDescriptorDacl error: " << GetLastError() << std::endl;
        return 0;
    }

    // Get size information for DACL
    ACL_SIZE_INFORMATION AclInfo;
    AclInfo.AceCount = 0; // Assume NULL DACL.
    AclInfo.AclBytesFree = 0;
    AclInfo.AclBytesInUse = sizeof( ACL );

    if ( pOldDacl == NULL )
        DaclPresent = FALSE;

    // If not NULL DACL, gather size information from DACL.
    if ( DaclPresent )
    {
        if ( !GetAclInformation( pOldDacl, &AclInfo,
            sizeof( ACL_SIZE_INFORMATION ), AclSizeInformation ) )
        {
            std::cout << "GetAclInformation error: " << GetLastError() << std::endl;
            return 0;
        }
    }

    DWORD cbNewACL = AclInfo.AclBytesInUse + sizeof( ACCESS_ALLOWED_ACE ) + sizeof( ACL ) + sizeof( ACL ) + sizeof( ACCESS_ALLOWED_ACE ) + sizeof( ACL ) + sizeof( ACL );

    PACL pNewACL = ( PACL ) HeapAlloc(
        GetProcessHeap(),
        HEAP_ZERO_MEMORY,
        cbNewACL );

    if ( !InitializeAcl( pNewACL, cbNewACL, ACL_REVISION ) )
    {
        std::cout << "InitializeAcl error: " << GetLastError() << std::endl;
        return 0;
    }

    LPVOID         pTempAce = NULL;

    // Copy old Ace to new DACL
    if ( DaclPresent && AclInfo.AceCount )
    {
        std::cout << "AclInfo.AceCount:" << AclInfo.AceCount << std::endl;
        for ( int i = 0; i < AclInfo.AceCount; ++i )
        {
            if ( !GetAce( pOldDacl, i, &pTempAce ) )
            {
                std::cout << "GetAce[" << i << "] error: " << GetLastError() << std::endl;
                return 0;
            }

            if ( !AddAce( pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
                ( ( PACE_HEADER ) pTempAce )->AceSize ) )
            {
                std::cout << "AddAce[" << i << "] error: " << GetLastError() << std::endl;
                return 0;
            }
        }
    }

    if ( !AddAccessAllowedAceEx( pNewACL, ACL_REVISION, CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE, GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL, psid ) )
    {
        std::cout << "AddAccessAllowedAceEx1 error: " << GetLastError() << std::endl;
        return 0;
    }

    if ( !AddAccessAllowedAceEx( pNewACL, ACL_REVISION, NO_PROPAGATE_INHERIT_ACE, WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN | STANDARD_RIGHTS_REQUIRED, psid ) )
    {
        std::cout << "AddAccessAllowedAceEx2 error: " << GetLastError() << std::endl;
        return 0;
    }

    if ( !SetSecurityDescriptorDacl( pSecDescriptorNew, TRUE, pNewACL, FALSE ) )
    {
        std::cout << "SetSecurityDescriptorDacl error: " << GetLastError() << std::endl;
        return 0;
    }

    if ( !SetUserObjectSecurity( hwinsta, &secInfo, pSecDescriptorNew ) )
    {
        std::cout << "SetUserObjectSecurity error: " << GetLastError() << std::endl;
        return 0;
    }

    return 1;
}

int AddAceToDesktop( HDESK  hdesk, PSID psid )
{
    DWORD lengthNeeded;

    SECURITY_INFORMATION secInfo = DACL_SECURITY_INFORMATION;
    if ( !GetUserObjectSecurity( hdesk, &secInfo, NULL, NULL, &lengthNeeded ) )
    {
        if ( GetLastError() != 122 )
        {
            std::cout << "GetUserObjectSecurity1 error: " << GetLastError() << std::endl;
            return 0;
        }
    }

    PSECURITY_DESCRIPTOR pSecDescriptor = ( PSECURITY_DESCRIPTOR ) HeapAlloc(
        GetProcessHeap(),
        HEAP_ZERO_MEMORY,
        lengthNeeded );

    if ( pSecDescriptor == NULL )
    {
        std::cout << "Allocating memory for pSecDescriptor failed: " << GetLastError() << std::endl;
        return 0;
    }

    PSECURITY_DESCRIPTOR pSecDescriptorNew = ( PSECURITY_DESCRIPTOR ) HeapAlloc(
        GetProcessHeap(),
        HEAP_ZERO_MEMORY,
        lengthNeeded );

    if ( pSecDescriptorNew == NULL )
    {
        std::cout << "Allocating memory for pSecDescriptorNew failed: " << GetLastError() << std::endl;
        return 0;
    }

    if ( !GetUserObjectSecurity( hdesk, &secInfo, pSecDescriptor, lengthNeeded, &lengthNeeded ) )
    {
        std::cout << "GetUserObjectSecurity2 error: " << GetLastError() << std::endl;
        return 0;
    }

    if ( !InitializeSecurityDescriptor( pSecDescriptorNew, SECURITY_DESCRIPTOR_REVISION ) )
    {
        std::cout << "InitializeSecurityDescriptor error: " << GetLastError() << std::endl;
        return 0;
    }

    BOOL DaclPresent;
    PACL pOldDacl;
    BOOL DaclDefaulted;
    if ( !GetSecurityDescriptorDacl( pSecDescriptor, &DaclPresent, &pOldDacl, &DaclDefaulted ) )
    {
        std::cout << "GetSecurityDescriptorDacl error: " << GetLastError() << std::endl;
        return 0;
    }

    // Get size information for DACL
    ACL_SIZE_INFORMATION AclInfo;
    AclInfo.AceCount = 0; // Assume NULL DACL.
    AclInfo.AclBytesFree = 0;
    AclInfo.AclBytesInUse = sizeof( ACL );

    if ( pOldDacl == NULL )
        DaclPresent = FALSE;

    // If not NULL DACL, gather size information from DACL.
    if ( DaclPresent )
    {
        if ( !GetAclInformation( pOldDacl, &AclInfo,
            sizeof( ACL_SIZE_INFORMATION ), AclSizeInformation ) )
        {
            std::cout << "GetAclInformation error: " << GetLastError() << std::endl;
            return 0;
        }
    }

    DWORD cbNewACL = AclInfo.AclBytesInUse + sizeof( ACCESS_ALLOWED_ACE ) + sizeof( ACL ) + sizeof( ACL );

    PACL pNewACL = ( PACL ) HeapAlloc(
        GetProcessHeap(),
        HEAP_ZERO_MEMORY,
        cbNewACL );

    if ( !InitializeAcl( pNewACL, cbNewACL, ACL_REVISION ) )
    {
        std::cout << "InitializeAcl error: " << GetLastError() << std::endl;
        return 0;
    }

    LPVOID         pTempAce = NULL;

    // Copy old Ace to new DACL
    if ( DaclPresent && AclInfo.AceCount )
    {
        std::cout << "AclInfo.AceCount:" << AclInfo.AceCount << std::endl;
        for ( int i = 0; i < AclInfo.AceCount; ++i )
        {
            if ( !GetAce( pOldDacl, i, &pTempAce ) )
            {
                std::cout << "GetAce[" << i << "] error: " << GetLastError() << std::endl;
                return 0;
            }

            if ( !AddAce( pNewACL, ACL_REVISION, MAXDWORD, pTempAce,
                ( ( PACE_HEADER ) pTempAce )->AceSize ) )
            {
                std::cout << "AddAce[" << i << "] error: " << GetLastError() << std::endl;
                return 0;
            }
        }
    }

    if ( !AddAccessAllowedAce( pNewACL, ACL_REVISION, DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED, psid ) )
    {
        std::cout << "AddAccessAllowedAce error: " << GetLastError() << std::endl;
        return 0;
    }

    if ( !SetSecurityDescriptorDacl( pSecDescriptorNew, TRUE, pNewACL, FALSE ) )
    {
        std::cout << "SetSecurityDescriptorDacl error: " << GetLastError() << std::endl;
        return 0;
    }

    if ( !SetUserObjectSecurity( hdesk, &secInfo, pSecDescriptorNew ) )
    {
        std::cout << "SetUserObjectSecurity error: " << GetLastError() << std::endl;
        return 0;
    }

    return 1;
}

int AddAceToBaseNameObjectsDirectory( PSID psid, TOKEN_INFORMATION_CLASS tClass )
{
    return 0;
}

int main( int argc, TCHAR *argv[] )
{
    HANDLE userToken;

    if ( !LogonUser( L"test", L"", L"test", LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &userToken ) )
    {
        std::cout << "LogonUser error: " << GetLastError() << std::endl;
        return -1;
    }

    HANDLE token;

    if ( !DuplicateTokenEx( userToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &token ) )
    {
        std::cout << "DuplicateTokenEx error: " << GetLastError() << std::endl;
        return -1;
    }

    PROFILEINFO profileInfo;
    profileInfo.lpUserName = L"test";
    profileInfo.dwFlags = NULL;
    profileInfo.lpProfilePath = L"C:\\Users\\test";

    LoadUserProfile( token, &profileInfo );

    LUID tcb_privilege_flag;

    if ( !LookupPrivilegeValue( NULL, SE_SECURITY_NAME, &tcb_privilege_flag ) )
    {
        std::cout << "LookupPrivilegeValue error: " << GetLastError() << std::endl;
        return -1;
    }

    TOKEN_PRIVILEGES tp;

    tp.PrivilegeCount = 1;
    tp.Privileges[0].Luid = tcb_privilege_flag;
    tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;

    if ( !AdjustTokenPrivileges( token, FALSE, &tp, sizeof( TOKEN_PRIVILEGES ), ( PTOKEN_PRIVILEGES ) NULL, ( PDWORD ) NULL ) )
    {
        std::cout << "AdjustTokenPrivileges error: " << GetLastError() << std::endl;
        return -1;
    }

    HWINSTA hwinstasave = GetProcessWindowStation();
    HWINSTA hwinsta = OpenWindowStation( L"winsta0", FALSE, READ_CONTROL | WRITE_DAC );

    HDESK hdesk = OpenDesktop( L"default", NULL, FALSE, READ_CONTROL | WRITE_DAC | DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS );

    DWORD token_group_size;

    if ( !GetTokenInformation( token, TokenGroups, NULL, 0, &token_group_size ) )
    {
        if ( GetLastError() != 122 )
        {
            std::cout << "GetTokenInformation1 error: " << GetLastError() << std::endl;
            return -1;
        }
    }

    PTOKEN_GROUPS pTokenGroup = ( PTOKEN_GROUPS ) new BYTE[token_group_size];
    memset( pTokenGroup, 0, token_group_size );

    if ( !GetTokenInformation( token, TokenGroups, pTokenGroup, token_group_size, &token_group_size ) )
    {
        std::cout << "GetTokenInformation2 error: " << GetLastError() << std::endl;
        return -1;
    }

    PSID pSid = NULL;
    for ( int i = 0; i < pTokenGroup->GroupCount; ++i )
    {
        if ( ( pTokenGroup->Groups[i].Attributes & SE_GROUP_LOGON_ID ) == SE_GROUP_LOGON_ID )
        {
            pSid = pTokenGroup->Groups[i].Sid;
        }
    }

    if ( pSid == NULL )
    {
        std::cout << "Unable to get logonSID error! No entry found!!!" << std::endl;
        return -1;
    }

    if ( !AddAceToWindowStation( hwinsta, pSid ) )
    {
        std::cout << "AddAceToWindowStation error: " << GetLastError() << std::endl;
        return -1;
    }

    if ( !AddAceToDesktop( hdesk, pSid ) )
    {
        std::cout << "AddAceToDesktop error: " << GetLastError() << std::endl;
        return -1;
    }

    //if ( !AddAceToBaseNameObjectsDirectory( pSid, TokenSessionId ) )
    //{
    //  std::cout << "AddAceToBaseNameObjectsDirectory error: " << GetLastError() << std::endl;
    //  return -1;
    //}

    if ( !ImpersonateLoggedOnUser( token ) )
    {
        std::cout << "ImpersonateLoggedOnUser error: " << GetLastError() << std::endl;
        return -1;
    }

    STARTUPINFO startupInfo;

    memset( &startupInfo, 0, sizeof( startupInfo ) );

    startupInfo.dwFlags = STARTF_USESHOWWINDOW;
    startupInfo.wShowWindow = SW_SHOWNORMAL;
    startupInfo.lpDesktop = L"winsta0\\default";
    startupInfo.cb = sizeof( startupInfo );

    PROCESS_INFORMATION procInfo;

    memset( &procInfo, 0, sizeof( procInfo ) );

    if ( !SetCurrentDirectory( L"C:\\Windows" ) )
    {
        std::cout << "SetCurrentDirectory error: " << GetLastError() << std::endl;
        return -1;
    }

    if ( !CreateProcessAsUserW( token, L"Notepad.exe", L"Notepad.exe", NULL, NULL, FALSE, DETACHED_PROCESS, NULL, NULL, &startupInfo, &procInfo ) )
    {
        std::cout << "CreateProcessAsUser error: " << GetLastError() << std::endl;
        return -1;
    }

    if ( !WaitForSingleObject( token, INFINITE ) )
    {
        std::cout << "WaitForSingleObject error: " << GetLastError() << std::endl;
        return -1;
    }
}
caschulz88
  • 91
  • 1
  • 4
  • 1
    Has the user account "test" ever been logged in interactively? If the user profile hasn't been fully configured, this sort of behaviour is to be expected. – Harry Johnston Feb 04 '15 at 21:41
  • That doesn't metter at all. Even if the user account has been logged in interactively and the profile is fully configured the styles are not applied somehow. Do you think it might be something with extra permissions that are needed since some version of Windows 7? But the strange thing is that it never works on Windows 7 in VM (VirtualBox), but mostly it works on Windows 7 native machines. – caschulz88 Feb 05 '15 at 08:10
  • Why are you messing around with ACEs, the CWD, or impersonation? You don't need any of that just to call `CreateProcessAsUser()`. And if you have the user's credentials, consider using `CreateProcessWithLogonW()` instead, which handles user logon and profile loading for you. – Remy Lebeau Feb 05 '15 at 20:32
  • Hey, this is not the case if you are trying to execute the command from local system user as running in a service. Then CreateProvessWithLogonW is not possible and always returns error code 5 (access denied). – caschulz88 Feb 19 '15 at 10:54
  • @caschulz88 Did you ever find a solution to this? – Dave Sibiski Mar 20 '19 at 02:53

0 Answers0