0

我在 Windows 8 中面临一个问题,其中模拟登录用户的提升的应用程序/服务无法正确识别映射的驱动器路径。

我有一个 Windows 服务,用于将文件从 / 复制到不同的源路径/目标,包括映射的网络驱动器。路径通过 xml 文件提供给服务。然后服务从 xml 读取源和目标并复制文件。我从来没有遇到过在 Vista 和 7 中映射驱动器的问题,因为该服务总是通过获取资源管理器令牌和所有 my CreateFile, ReadFiles来模拟登录的用户,并且WriteFile运行良好。

这就是我模仿用户的方式

首先,我使用以下代码获取会话令牌

DWORD GetActiveSessionId(DWORD& ret)
{
    ret=0;
    DWORD active_session_id = WTSGetActiveConsoleSessionId();
    if (IsSessionActive(active_session_id)) 
    {
        return active_session_id;
    }

    DWORD console_session_ID = active_session_id;
    active_session_id = -2;
    WTS_SESSION_INFO* session_info = NULL;
    DWORD num_sessions = 0;
    if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1,
        &session_info, &num_sessions)) 
    {
            // Pick the first active session we can find
            for (DWORD i = 0 ; i < num_sessions; ++i) 
            {
                if (session_info[i].State == WTSActive) 
                {
                    // There is a user logged on to the WinStation associated with the
                    // session.
                    active_session_id = session_info[i].SessionId;
                    break;
                }
            }
            WTSFreeMemory(session_info);
            return active_session_id;
    }

    ret=::GetLastError();
    return -2;
}


BOOL GetSessionUserToken( HANDLE * phUserToken, DWORD& retCode )
{
    if( NULL == phUserToken )
    {
        return FALSE;
    }

    BOOL bRet = FALSE;
    HANDLE hImpersonationToken = NULL;

    BOOL bWin2K = FALSE;
    OSVERSIONINFOEX osv;
    ZeroMemory( & osv, sizeof( OSVERSIONINFOEX ) );
    osv.dwOSVersionInfoSize  = sizeof( OSVERSIONINFOEX );
    if( GetVersionEx( (OSVERSIONINFO*) & osv ) )
    {
        if( 0 == osv.dwMinorVersion && osv.dwMajorVersion == 5)
        {
            return FALSE;
        }
    }

    DWORD dwActiveSession= CGSSystem::GetActiveSessionId(retCode);

    if (dwActiveSession==GSInvalidSessionId)
        return FALSE;

    if( 0 != WTSQueryUserToken( dwActiveSession, & hImpersonationToken ) )
    {
        bRet = TRUE;
    }
    else
    {

    }


    DWORD neededSize = 0;
    HANDLE *realToken = new HANDLE;
    if(GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize))
    {
        CloseHandle(hImpersonationToken);
        hImpersonationToken = *realToken;
    }
    DWORD lastError = GetLastError();
    delete realToken;


    if( TRUE == bRet )
    {
        bRet = DuplicateTokenEx( hImpersonationToken,
                                0,
                                NULL,
                                SecurityImpersonation,
                                TokenPrimary,
                                phUserToken );

        CloseHandle( hImpersonationToken );
    }

    return bRet;
}

然后我有我的CopyFile函数,它是一个线程。这是一个巨大的功能,所以我只会提到重要的(模拟/安全)部分。

BOOL CopyFile(LPCTSTR source, LPCTSTR destination)
{

    //Some variables initializations
    //...

    HRESULT hrInternal = CoInitializeSecurity(
        NULL,                           //  Allow *all* VSS writers to communicate back!
        -1,                             //  Default COM authentication service
        NULL,                           //  Default COM authorization service
        NULL,                           //  reserved parameter
        RPC_C_AUTHN_LEVEL_PKT_PRIVACY,  //  Strongest COM authentication level
        RPC_C_IMP_LEVEL_IDENTIFY,       //  Minimal impersonation abilities
        NULL,                           //  Default COM authentication settings
        EOAC_NONE,                      //  No special options
        NULL                            //  Reserved parameter
        );

    //Initialize security descriptors
    SECURITY_DESCRIPTOR    SD;
    SECURITY_ATTRIBUTES copyMutexAttrib;
    copyMutexAttrib.nLength = sizeof( SECURITY_ATTRIBUTES );
    copyMutexAttrib.lpSecurityDescriptor = & SD;
    copyMutexAttrib.bInheritHandle = TRUE;

    if(!InitializeSecurityDescriptor( & SD, SECURITY_DESCRIPTOR_REVISION ) )
    {
        //Error handling;           
    }

    // add a NULL disc. ACL to the security descriptor.
    //
    if( ! SetSecurityDescriptorDacl( & SD, TRUE, (PACL) NULL, FALSE ) )
    {
        //Error handling;           
    }

    HRESULT hr=S_OK;
    hr=ModifyThreadPrivilege( SE_BACKUP_NAME, TRUE , m_hUserToken==NULL ? FALSE : TRUE  );
    if (FAILED(hr))
    {
        //Error Handling and logs
    }

    hr=S_OK;
    hr=ModifyThreadPrivilege( SE_TCB_NAME, TRUE , m_hUserToken==NULL ? FALSE : TRUE  );
    if (FAILED(hr))
    {
        //Error Handling and logs
    }
    hr=ModifyThreadPrivilege( SE_IMPERSONATE_NAME, TRUE , m_hUserToken==NULL ? FALSE : TRUE  );
    if (FAILED(hr))
    {
        //Error Handling and logs
    }

    hr=ModifyThreadPrivilege( SE_MANAGE_VOLUME_NAME, TRUE , m_hUserToken==NULL ? FALSE : TRUE  );
    if (FAILED(hr))
    {
        //Error Handling and logs
    }

    hr=ModifyThreadPrivilege( SE_SYSTEM_PROFILE_NAME, TRUE , m_hUserToken==NULL ? FALSE : TRUE  );
    if (FAILED(hr))
    {
        //Error Handling and logs
    }

    hr=ModifyThreadPrivilege( SE_DEBUG_NAME, TRUE , m_hUserToken==NULL ? FALSE : TRUE  );
    if (FAILED(hr))
    {
        //Error Handling and logs
    }


    //Other variable initializations
    //...

    //Create the destination file
    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(sa);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;

    HANDLE hFile = ::CreateFile(destination, GENERIC_WRITE, FILE_SHARE_WRITE | FILE_SHARE_READ, &sa,
                                CREATE_ALWAYS, FILE_FLAG_WRITE_THROUGH|FILE_FLAG_BACKUP_SEMANTICS, NULL);  //---> creates the file in the wrong location


}

这是我的 ModifyThreadPrivilage 代码:

HRESULT ModifyThreadPrivilege(IN LPCTSTR szPrivilege,IN BOOL fEnable,IN BOOL OpenAsSelf)
    {
        HRESULT hr = S_OK;
        TOKEN_PRIVILEGES NewState;
        LUID luid;
        HANDLE hToken = NULL;

        // Open the process token for this process.
        if (!OpenThreadToken(GetCurrentThread(),
            TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY,
            OpenAsSelf,
            &hToken ))
        {
            int iLast=::GetLastError();
            if (iLast != ERROR_NO_TOKEN) 
            {
                return ERROR_FUNCTION_FAILED;
            }

            /*
            * No access token for the thread so impersonate the security context
            * of the process.
            */
            if (!ImpersonateSelf(SecurityImpersonation)) 
            {
                return ERROR_FUNCTION_FAILED;
            }

            if (!OpenThreadToken(GetCurrentThread(),
                TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY,
                FALSE,
                &hToken)) 
            {
                return ERROR_FUNCTION_FAILED;
            }   

        }

        // Get the local unique ID for the privilege.
        if ( !LookupPrivilegeValue( NULL,
            szPrivilege,
            &luid ))
        {
            CloseHandle( hToken );
            printf("Failed LookupPrivilegeValue\n");
            return ERROR_FUNCTION_FAILED;
        }

        // Assign values to the TOKEN_PRIVILEGE structure.
        NewState.PrivilegeCount = 1;
        NewState.Privileges[0].Luid = luid;
        NewState.Privileges[0].Attributes = 
            (fEnable ? SE_PRIVILEGE_ENABLED : 0);


        // Adjust the token privilege.
        if (!AdjustTokenPrivileges(hToken,
            FALSE,
            &NewState,
            0,
            NULL,
            NULL))
        {
            hr = ERROR_FUNCTION_FAILED;
        }

        // Close the handle.
        CloseHandle(hToken);

        return hr;
    }

在 Windows 8 中,当目标是映射驱动器时,"Z:\MyFile.txt"它会将文件写入错误的位置,如下所示:

我已经映射了Z:映射到 \\nsa\public\myfolder1\subfolder\函数的网络驱动器将文件写入 \\nsa\public\

我在 Windows Vista 或 7 中从未遇到过此类行为,但似乎 MS 引入了一些导致此类行为的新特权或证券。

我注意到很多人抱怨 Windows 8 中的映射驱动器,特别是对于提升的进程,但所有解决方案都建议使用 UNC 路径而不是映射驱动器号。

我还注意到启用/禁用 UAC 对此没有影响。

有人可以解释我如何实现复制文件的目标吗?

4

0 回答 0