• 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在函数调用期间,值会被修改,不能使用常量

  • 相关阅读:
    Flex 布局
    前端跨域之jsonp
    vs code 自定义代码片段
    vue中使用axios进行http通信
    Table边框合并
    getElementsBy 系列方法相比querySelector系列的区别
    vue中watch简单使用
    png图标任意赋色
    pc端与移动端适配解决方案之rem
    Express post请求无法解析参数的原因
  • 原文地址:https://www.cnblogs.com/fatterbetter/p/4203094.html
Copyright © 2020-2023  润新知