Олицетворять и запускать любой метод, используя зарегистрированный пользовательский контекст из процесса уровня SYSTEM (Windows Service): - PullRequest
0 голосов
/ 25 февраля 2019

Я создал шаблонный класс, который создаст поток с авторизованным токеном пользователя и запустит любой метод.Я передал его в шаблонный класс с помощью std :: function и запустил в контексте уровня пользователя.

Мое текущее использование:

1. Классиспользуется в процессе службы Windows (который работает как уровень SYSTEM).

2. Поток создается в приостановленном состоянии, а SetThreadToken () используется для применения олицетворенного токена, созданного из «explorer.exe».,(Я знаю, что это не выполнимо в случае нескольких вошедших в систему пользователей, но на данный момент мне нужно, чтобы эта штука заработала).

3.После этого я возобновлю поток для выполнения переданного утилиты.метод в контексте уровня пользователя.

Олицетворение указанного потока от: Создание потока с определенной привилегией c ++

Проблема:

Успешно выдал себя за вошедшего в систему пользователя, и созданный поток также работает в контексте уровня пользователя (проверено с помощью GetUserName () API), но выполнение любого API из метода, который я передал классу шаблона,не так, как ожидалось.(Пример: я попытался прочитать запись HKCU от имени другого пользователя, но она всегда завершается ошибкой: ERROR_FILE_NOT_FOUND. 2 (0x2) ). PS: Перекрестно проверил дерево реестра и там присутствует соответствующий ключ.

ПРИМЕЧАНИЕ: Приведенный выше пример ( REG read ) одиниз методов util, которые я пытался передать классу Userimpersonator, и пытался запускать их в пользовательском контексте из службы, но во время выполнения я буду использовать это с любым методом util.

UserImpersonator.h

class UserImpersonator
{

public:

    UserImpersonator();

    UserImpersonator(ImpersonationType typeVal,bool b_ImpersonateAndRunAsThreadNeeded = false);

   ~UserImpersonator();

    T1 ImpersonateAndRun(T2 callback_function);

    T1 ImpersonateAndRunAsThread(T2 callback_function);

private:

    ImpersonationType ImpersonationTypeVal;
    CString m_processname;
    HANDLE hToken;

    HANDLE impToken;

    bool m_ImpersonateAndRunAsThreadNeeded;

    T1 return_value;
    T2 callable_function_object;

    HANDLE hThread;

    BOOL InitializeImpersonation();
    BOOL RevertImpersonation();

    static DWORD WINAPI SpawnImpersonatedThread ( LPVOID lpParam );

};

Определения методов:

template<typename T1,typename T2>
UserImpersonator<T1,T2>::UserImpersonator()
{
    ImpersonationTypeVal = ImpersonationType::IMPERSONATION_USING_WINLOGON;
    m_processname = _T("winlogon.exe");
    hToken = NULL;
    m_ImpersonateAndRunAsThreadNeeded = false;
    hThread = NULL;
    impToken = NULL;

    InitializeImpersonation();
}

template<typename T1,typename T2>
UserImpersonator<T1,T2>::UserImpersonator(ImpersonationType typeVal,bool b_ImpersonateAndRunAsThreadNeeded)
{
    ImpersonationTypeVal = typeVal;
    m_processname = (typeVal == ImpersonationType::IMPERSONATION_USING_WINLOGON) ? _T("winlogon.exe") : _T("explorer.exe");
    hToken = NULL;
    m_ImpersonateAndRunAsThreadNeeded = b_ImpersonateAndRunAsThreadNeeded;
    hThread = NULL;
    impToken = NULL;

    InitializeImpersonation();
}

template<typename T1,typename T2>
DWORD WINAPI UserImpersonator<T1,T2> :: SpawnImpersonatedThread ( LPVOID lpParam )
{
    TRY
    {
        UserImpersonator* ImpersonatorObject = (UserImpersonator*) lpParam;

        TCHAR   UserName[200] =  _T("");
    DWORD size = 200 ; //sizeof ( UserName ) ;
    GetUserName ( UserName  , &size  ) ;

    CString name = CString(UserName);

        ImpersonatorObject->return_value = ImpersonatorObject->ImpersonateAndRun(ImpersonatorObject->callable_function_object);
    }
    CATCH_ALL( e )
    {
        LogDebug ( _T("Exception occurs:%s"),__FUNCTIONW__ ) ;
        return FALSE ;
    }
    END_CATCH_ALL

return 0;
}

template<typename T1,typename T2>
BOOL UserImpersonator<T1,T2>::InitializeImpersonation()
{
    BOOL res = TRUE;

    try
    {
        TCHAR   UserName[200] =  _T("");
    DWORD size = 200 ; //sizeof ( UserName ) ;
    GetUserName ( UserName  , &size  ) ;

    CString name = CString(UserName);

        HANDLE process_handle = GetProcessHandleByName(m_processname);

        if ( OpenProcessToken(process_handle, TOKEN_ALL_ACCESS, &hToken) == 0 )
        {
            res = FALSE;
            CloseHandle(process_handle);
            LogCritical(_T("%s : OpenProcessToken Failed with error-%d"), __FUNCTIONW__, GetLastError());
        }
    }
    catch(...)
    {
        LogDebug(_T("%s::Exception occurred"),__FUNCTIONW__);
    }

return res;
}

template<typename T1,typename T2>
T1 UserImpersonator<T1,T2>::ImpersonateAndRunAsThread(T2 callback_function)
{

    try
    {

        callable_function_object = callback_function;   

        hThread = ::CreateThread(0,0,SpawnImpersonatedThread,this,CREATE_SUSPENDED,0); //without using sb

        BOOL b = DuplicateTokenEx(hToken,MAXIMUM_ALLOWED,NULL,SecurityImpersonation,TokenImpersonation,&impToken);

        if( hThread )
        {
            if(SetThreadToken(&hThread,impToken))
            {
                DWORD thread_suspended_count = ResumeThread(hThread);

                if( thread_suspended_count == (DWORD) 0 || thread_suspended_count == (DWORD) 1 )
                {

                    DWORD thread_return_status = WaitForSingleObject(hThread,INFINITE);

                    if( thread_return_status == WAIT_OBJECT_0 )
                    {
                        LogDebug(_T("%s::SpawnImpersonatedThread successfully executed the callback function"),__FUNCTIONW__);
                    }
                    else
                        LogDebug(_T("%s::WaitForSingleObject failed with error=%d"),__FUNCTIONW__,GetLastError());
                }
            }
            else
                LogDebug(_T("%s::SetThreadToken failed with error=%d"),__FUNCTIONW__,GetLastError());
        }
        else
            LogDebug(_T("%s::CreateThread failed with error=%d"),__FUNCTIONW__,GetLastError());

    }
    catch(...)
    {
        LogDebug(_T("%s::Exception occurred"),__FUNCTIONW__);
    }

return return_value;
}

template<typename T1,typename T2>
T1 UserImpersonator<T1,T2>:: ImpersonateAndRun(T2 callback_function)
{
    try
    {
        return_value = callback_function();
    }
    catch(...)
    {
        LogDebug(_T("%s::Exception occurred"),__FUNCTIONW__);
    }

return return_value;
}

template<typename T1,typename T2>
BOOL UserImpersonator<T1,T2>::RevertImpersonation()
{
    if(hToken)
        CloseHandle(hToken) ;
    if(impToken)
        CloseHandle(impToken) ;

return RevertToSelf();
}

template<typename T1,typename T2>
UserImpersonator<T1,T2>::~UserImpersonator()
{
    RevertImpersonation();
}

Пример использования:

    UserImpersonator< bool,std::function<bool()> > ImpersonatedObj(ImpersonationType::IMPERSONATION_USING_EXPLORER,true);

    auto f = std::bind(&IsRegKeyExists);

    BOOL res = ImpersonatedObj.ImpersonateAndRunAsThread(f);

Метод использования:

bool IsRegKeyExists()
{
    HKEY phKey = NULL;
    bool res = false;

    is64bit = Is64BitConfiguration();

    CString subkey = _T("Volatile Environment\\USERPROFILE");

    if(is64bit)
    {
        lRes = RegOpenKeyEx( HKEY_CURRENT_USER, subkey.GetBuffer(), 0, KEY_ALL_ACCESS | KEY_WOW64_64KEY, &phKey );
    }
    else
    {
        lRes = RegOpenKeyEx( HKEY_CURRENT_USER, subkey.GetBuffer(), 0, KEY_ALL_ACCESS, &phKey );
    }

    if(lRes == ERROR_SUCCESS)
    {
        res = true;
    }
    else
    {
       LogDebug ( _T("Key open failure! %d"), GetLastError() );
    } 
return res;
}

1 Ответ

0 голосов
/ 25 февраля 2019

HKEY_CURRENT_USER это Предопределенный ключ - этот дескриптор кэшируется:

Ключ HKEY_CURRENT_USER сопоставляется с корнем текущего пользователяветка в ключе HKEY_USERS. кэшируется для всех потоков в процессе.Следовательно, это значение не изменяется при загрузке профиля другого пользователя.RegOpenCurrentUser использует токен потока для доступа к соответствующему ключу или по умолчанию, если профиль не загружен.

, поэтому вам необходимо сначала открыть корневой ключ пользователя с помощью RegOpenCurrentUserи используйте эту ручку вместо HKEY_CURRENT_USER.также возможно использование RegDisablePredefinedCache и RegDisablePredefinedCacheEx в случае, если вы косвенно обращаетесь к кусту реестра пользователей

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...