[英]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.
我借助std :: function将其传递给模板类,并在用户级别的上下文中运行它。
My Current Usage: 我目前的用法:
1.The class is used in a windows service process ( which is running as SYSTEM level). 1.该类在Windows服务进程(以SYSTEM级别运行)中使用。
2.The thread is created in a suspended state and SetThreadToken() is used to apply the Impersonated token created from "explorer.exe". 2.线程在挂起状态下创建,并且SetThreadToken()用于应用从“ 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. 3.之后,我将继续线程以在用户级别上下文中执行传递的util方法。
Referred thread impersonation from : Create thread with specific privilege c++ 引用的线程模拟来自: 创建具有特定特权的线程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. 成功模拟了已登录的用户,并且创建的线程也在用户级上下文中运行(已使用GetUserName() API进行了验证),但是从我传递给模板类的方法中执行的任何API均与预期不符。 (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) ).
(示例:我试图读取模拟用户的HKCU条目,但它总是失败,并显示错误: ERROR_FILE_NOT_FOUND。2(0x2) )。 PS: Cross Checked the registry tree and the respective key is present there.
PS:交叉检查了注册表树,并且那里有相应的注册表项。
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. 注意:上面的示例( REG read )是我尝试传递给Userimpersonator类并尝试从服务在用户上下文中运行的util方法之一,但是在运行时,我将将此方法与任何util方法一起使用。
UserImpersonator.h
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: HKEY_CURRENT_USER
这是预定义的密钥 -此句柄已缓存:
The
HKEY_CURRENT_USER
key maps to the root of the current user's branch in theHKEY_USERS
key.HKEY_CURRENT_USER
键映射到HKEY_USERS
键中当前用户分支的根。 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.RegOpenCurrentUser
使用线程的令牌访问相应的密钥,如果未加载配置文件,则使用默认值。
so you need first open user root key via RegOpenCurrentUser
and use this handle instead HKEY_CURRENT_USER
. 因此,您首先需要通过
RegOpenCurrentUser
打开用户根密钥,然后使用此句柄HKEY_CURRENT_USER
。 also possible use RegDisablePredefinedCache
and RegDisablePredefinedCacheEx
in case you indirect access user registry hive 如果您间接访问用户注册表配置单元,也可以使用
RegDisablePredefinedCache
和RegDisablePredefinedCacheEx
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.