简体   繁体   中英

Impersonate and run any method using a logged in user context from SYSTEM level process (Windows Service):

I have created a template class which will create a thread with logged-in user token and run any method. I passed it to the template class with the help of std::function and run it in the user level context.

My Current Usage:

1.The class is used in a windows service process ( which is running as SYSTEM level).

2.The thread is created in a suspended state and SetThreadToken() is used to apply the Impersonated token created from "explorer.exe". ( I know it is not a feasible way in multiple logged-in users case but for time being I need this thing to get work out).

3.After these I will resume the thread to execute the passed util method in user level context.

Referred thread impersonation from : Create thread with specific privilege c++

Problem Facing:

Successfully impersonated the logged-in user and the created thread also is running in user-level context (verified using GetUserName() API ) but the execution of any API from the method I have passed to the template class is not as expected. (Example: I have tried to read HKCU entry of the impersonated user but it is always failed with error: ERROR_FILE_NOT_FOUND. 2 (0x2) ). PS: Cross Checked the registry tree and the respective key is present there.

NOTE: The above example( REG read ) is one of the util methods I have tried to pass to the Userimpersonator class and tried to run in user context from the service but in run time I will use this with any util method.

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 );

};

Method definitions:

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();
}

Example for Usage:

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

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

    BOOL res = ImpersonatedObj.ImpersonateAndRunAsThread(f);

Util Method:

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;
}

HKEY_CURRENT_USER this is Predefined Key - this handles is cached:

The HKEY_CURRENT_USER key maps to the root of the current user's branch in the HKEY_USERS key. It is cached for all threads in a process. Therefore, this value does not change when another user's profile is loaded. RegOpenCurrentUser uses the thread's token to access the appropriate key, or the default if the profile is not loaded.

so you need first open user root key via RegOpenCurrentUser and use this handle instead HKEY_CURRENT_USER . also possible use RegDisablePredefinedCache and RegDisablePredefinedCacheEx in case you indirect access user registry hive

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM