system进程启动普通用户进程调研

system进程启动普通用户进程

关键函数是CreateProcessAsUser

主要思路是先取得目的用户的token,然后用上面的函数启动

1、从explorer中取token

BOOL GetTokenByName(HANDLE &hToken,LPSTR lpName)
{
	if(!lpName)
	{
		return FALSE;
	}
	HANDLE         hProcessSnap = NULL; 
	BOOL           bRet      = FALSE; 
	PROCESSENTRY32 pe32      = {0}; 

	hProcessSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); 
	if (hProcessSnap == INVALID_HANDLE_VALUE) 
		return (FALSE); 

	pe32.dwSize = sizeof(PROCESSENTRY32); 

	if (Process32First(hProcessSnap, &pe32)) 
	{  
		do 
		{
			if(!strcmp(_strupr(pe32.szExeFile),_strupr(lpName)))
			{
				HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION,
					FALSE,pe32.th32ProcessID);
				bRet = OpenProcessToken(hProcess,TOKEN_ALL_ACCESS,&hToken);
				CloseHandle (hProcessSnap); 
				return (bRet);
			}
		} 
		while (Process32Next(hProcessSnap, &pe32)); 
		bRet = TRUE; 
	} 
	else 
		bRet = FALSE;

	CloseHandle (hProcessSnap); 
	return (bRet);
}

BOOL RunProcess(LPCSTR lpImage)
{
	if(!lpImage)
	{
		return FALSE;
	}
	HANDLE hToken;
	if(!GetTokenByName(hToken,"EXPLORER.EXE"))
	{
		return FALSE;
	}
	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	ZeroMemory(&si, sizeof(STARTUPINFO));
	si.cb= sizeof(STARTUPINFO);
	si.lpDesktop = TEXT("winsta0\default");

	BOOL bResult = CreateProcessAsUser(hToken,lpImage,NULL,NULL,NULL,
		FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi);
	CloseHandle(hToken);
	if(bResult)
	{
		OutputDebugString("CreateProcessAsUser ok!
");
	}
	else
	{
		OutputDebugString("CreateProcessAsUser false!
");
	}
	return bResult;
}

这种方式的缺点是,如果当前有多个用户登陆,则进程中会有多个explorer进程,需额外控制从哪个explorer中取token

2、从当前活动的session中查询token,再启动

BOOL RunProcess1(LPCSTR lpImage, LPSTR lpCmd = "")
{
	if(!lpImage)
	{
		return FALSE;
	}

	DWORD dwSID =  WTSGetActiveConsoleSessionId(); 
	HANDLE hToken;
	WTSQueryUserToken(dwSID, &hToken);

	STARTUPINFO si;
	PROCESS_INFORMATION pi;

	ZeroMemory(&si, sizeof(STARTUPINFO));
	si.cb= sizeof(STARTUPINFO);
	si.lpDesktop = TEXT("winsta0\default");
	//si.dwFlags = STARTF_USESHOWWINDOW;
	//si.wShowWindow = SW_HIDE;

	BOOL bResult = CreateProcessAsUser(hToken,lpImage,lpCmd,NULL,NULL,
		FALSE,NORMAL_PRIORITY_CLASS,NULL,NULL,&si,&pi);
	CloseHandle(hToken);
	if(bResult)
	{
		OutputDebugString("CreateProcessAsUser ok!
");
	}
	else
	{
		OutputDebugString("CreateProcessAsUser false!
");
	}
	return bResult;
}

这种方式相对于上一种就是可以创建一个当前活动用户的进程,但在使用过程中发现,如果以非system用户调用WTSQueryUserToken,可能会失败

3、CreateProcessAsUser的命令行参数问题

在实际使用中,想给新进程传递参数,一直没传对,后来才发现,CreateProcessCreateProcessAsUser中,cmdline参数的使用比较特别,要注意

比较保险的两种用法是

  • appname参数置空,cmdline参数为完整命令行,这种用法的限制在于,cmdline长度最大为MAX_PATH
  • appname参数为要启动的程序的完整路径,cmdline参数为完整命令行,这种用法的好处是,长度可以达到32K(MSDN中写的,未试验),限制在于,一定要使用完整命令行,包括要启动的程序的路径。因为该函数不会将appname和cmdline拼在一起

另外需注意的一点是,cmdline在函数调用期间,值会被修改,不能使用常量

原文地址:https://www.cnblogs.com/fatterbetter/p/4203094.html