2016-07-28 23 views
0

システムレベルのWindowsサービスで以下のコードを実行しています。 CreateEnvironmentBlock()とCreateProcessAsUser()をコードに追加すると、そのコードは機能します。しかし、私は "LoadUserProfile()"を使用して、それは "アクセス拒否"を意味する必要がありますエラー5で失敗します。不足しているものを確認してください。私が望むのは、このシステムサービスからユーザーレベルのレジストリ値を取得することです。コード内のコメントは別の方法ですが、ユーザーレベルのレジストリ値を取得することもできませんでした。システムサービスで実行されているこのコードでLoadUserProfile()がエラー5で "失敗アクセス"に失敗しますか?

void GetUserRegistry() 
{ 
#ifdef Q_OS_WIN 

    DWORD lastError = 0; 

    DWORD sessionId = WTSGetActiveConsoleSessionId(); 
    qInfo() << "Session ID = " << sessionId; 

    wchar_t* ppUserName[100]; 
    DWORD sizeOfUserName; 
    WTSQuerySessionInformation(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, ppUserName, &sizeOfUserName); 
    qInfo() << "Windows User Name = " << QString::fromWCharArray(*ppUserName); 

    std::wstring strValueOfBinDir = L"Unknown Value"; 
    // LONG regOpenResult = ERROR_SUCCESS; 

    HANDLE hUserToken = NULL; 
    HANDLE hFakeToken = NULL; 

    if (WTSQueryUserToken(sessionId, &hUserToken)) 
    { 
     if (DuplicateTokenEx(hUserToken, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS, 0, SecurityImpersonation, TokenPrimary, &hFakeToken) == TRUE) 
     { 
      qInfo() << "Before ImpersonateLoggedOnUser()......"; 
      if (ImpersonateLoggedOnUser(hFakeToken)) 
      { 
       HKEY hKey; 

       // regOpenResult = RegOpenCurrentUser(KEY_READ, &hKey); 

       PROFILEINFO profileInfo; 
       ZeroMemory(&profileInfo, sizeof(PROFILEINFO)); 
       profileInfo.dwSize = sizeof(PROFILEINFO); 
       profileInfo.lpUserName = *ppUserName; 
       // wchar_t roamingPath[] = L"C:\\Users\\Finix"; // L"C:\\Users\\Finix\\AppData\\Roaming"; 
       // profileInfo.lpProfilePath = roamingPath; 

       if (LoadUserProfile(hFakeToken, &profileInfo)) 
       { 
        HANDLE hProfile = profileInfo.hProfile; 

        RegOpenKeyEx(HKEY_CURRENT_USER, 
           TEXT("Software\\Baidu\\BaiduYunGuanjia"), 
           0, 
           KEY_READ, 
           &hKey); 

        GetStringRegKey(hKey, TEXT("installDir"), strValueOfBinDir, TEXT("Unknown")); 

        UnloadUserProfile(hFakeToken, hProfile); 
       } 
       else 
       { 
        lastError = GetLastError(); 
       } 

       RevertToSelf(); 

      } 
      else 
      { 
       qCritical() << "Failed to ImpersonateLoggedOnUser..."; 
      } 

      CloseHandle(hFakeToken); 
     } 
     else 
     { 
      qCritical() << "Failed to call DuplicateTokenEx..."; 
     } 

     CloseHandle(hUserToken); 
    } 
    else 
    { 
     qCritical() << "Failed to get the user token of session " << sessionId; 
    } 

    if (lastError) 
    { 
     qCritical() << "Failed to LoadUserProfile(), The ERROR is " << lastError; 
    } 

// if (regOpenResult != ERROR_SUCCESS) 
// { 
//  qCritical() << "Failed to call RegOpenCurrentUser(), Error is " << regOpenResult; 
// } 

    qInfo() << "The value of Registry is " << QString::fromWCharArray(strValueOfBinDir.c_str()); 

#endif 
} 
+0

がシンプルであるためには、呼び出しは次のとおりです。()+ WTSQueryUserToken()+ DuplicateTokenEx()+ ImpersonateLoggedOnUser()+ LoadUserProfile()WTSGetActiveConsoleSessionId。 LoadUserProfile()がエラー5で失敗するのはなぜですか? LoadUserProfile()を呼び出す前に、何をする必要がありますか?私は上記のコードを示しています。私は何か見落としてますか? – Finix

+0

文字配列 'wchar_t * ppUserName [100]'へのポインタを宣言しています。 'wchar_t ppUserName [100];'に変更する必要がありますが、他のエラーがあるかもしれません。 –

+0

@BarmakShemirani上記のコードは正しいです。 WTSQuerySessionInformation()の4番目の引数は "LPWSTR *"なので、それはpointorまたはpointorです。そして、私が述べたように、LoadUserProfile()を "CreateEnvironmentBlock()+ CreateProcessAsUser()"に変更すると、このプログラムが動作します。それは残りの部分がすべて正常であることを意味しますが、LoadUserProfile()の呼び出しは失敗します。 – Finix

答えて

3

あなたができないコールLoadUserProfileの理由は、あなたがユーザーを偽装していることです。 LoadUserProfileには管理者権限が必要です。つまり、偽装されたコンテキストではなく、独自のコンテキストで呼び出す必要があります。ユーザーが自分のプロファイルを読み込む機能ではなく、通常はシステムがユーザーのためにそれを呼び出す。

を使用しないでください。LoadUserProfileと呼びます。これは、ユーザーが既にログオンしているため、プロファイルが既に読み込まれているためです。私たちを知っています。WTSQueryUserTokenは、使用していないユーザーのトークンを取得するために使用できないため、問題のユーザーはログオンしています。

は(まあ、ユーザーが現在ログオンまたはオフにします。しかし、ログオン中にLoadUserProfile関数を呼び出しているエッジケースがあるかもしれません/ログオフは、どのような場合でも、おそらく賢明ではありません。)

あなただけしたい場合はログオンしたユーザーのレジストリハイブを開き、RegOpenCurrentUserを使用します。 (文書としてあなたは、は、この機能で偽装を使用しますかことに注意してください。)

+0

私はあなたが 'RegOpenCurrentUser'を試してみて、動作しなかったと言います。コードとその失敗の詳細な説明など、別の質問を投稿することをお勧めします。 –

+1

https://blogs.msdn.microsoft.com/oldnewthing/20141121-00/?p=43563/ –

+0

ご意見ありがとうございます@HarryJohnstonも参照してください。私はRegOpenKeyEx()のいくつかのパラメータを調整した後に動作します。添付したブログについては、私もテストをしました。ブログの内容が正しいとは思われません。無効にした後、私はアクティブなユーザーの1つの特別なユーザーレジストリハイブを取得できます。その後、偽装終了後、コードを再度呼び出すと、それ以上同じハイブを取得することはできません。 – Finix

関連する問題