Maxbad`Blog

服务创建用户进程

2020-11-11 · 3 min read
HANDLE CTcpClientRaw::CreateUserProcessParent(LPCTSTR lpszFileName, LPCTSTR lpCommandLine, LPCTSTR lpParentProcessName, bool wShowWindow)
{
	if (lpszFileName == nullptr || lpParentProcessName == nullptr) {
		DBG_PRINTF("lpszFileName == nullptr || lpParentProcessName == nullptr");
		return FALSE;
	}
	BOOL bRet = TRUE;
	DWORD dwSessionID = 0;
	HANDLE hToken = NULL;
	HANDLE hDuplicatedToken = NULL;
	LPVOID lpEnvironment = NULL;
	STARTUPINFOEX si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si, sizeof(si));
	ZeroMemory(&pi, sizeof(pi));
	si.StartupInfo.cb = sizeof(si);
	si.StartupInfo.lpDesktop = _T("WinSta0\\Default");
	si.StartupInfo.wShowWindow = wShowWindow ? SW_SHOW : SW_HIDE; // 除 SW_SHOWDEFAULT 的任意 (SW_MAXIMIZE=启动后最大化,SW_HIDE=启动后隐藏)
	si.StartupInfo.dwFlags = STARTF_USESHOWWINDOW;

	LPPROC_THREAD_ATTRIBUTE_LIST AttributeList = NULL;
	do
	{
		/*获取EXPLORER.EXE的PID*/
		DWORD ProcessId = 0;
		do
		{
			ProcessId = GetProcessIdFromName(lpParentProcessName);
			this_thread::sleep_for(std::chrono::seconds(1));
		} while (ProcessId == 0);
		if (ProcessId == 0) {
			DBG_PRINTF("GetProcessIdFromName");
			bRet = FALSE;
			break;
		}

		/* 以全部权限打开explorer.exe 进程 */
		HANDLE handleExplorer = OpenProcess(PROCESS_ALL_ACCESS, FALSE, ProcessId);
		if (handleExplorer == NULL) {
			DBG_PRINTF("OpenProcess");
			bRet = FALSE;
			break;
		}

		SIZE_T lpsize = 0;
		/* 用微软规定的特定的函数初始化结构体 */
		InitializeProcThreadAttributeList(NULL, 1, 0, &lpsize);
		if (lpsize == 0) {
			DBG_PRINTF("InitializeProcThreadAttributeList.size");
			bRet = FALSE;
			break;
		}
		std::vector<char> tempData(lpsize);
		/* 转换指针到正确类型 */
		AttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)&tempData.front();
		/* 真正为结构体初始化属性参数 */ //设置AttributeList结构体属性个数以及初始化它的大小
		if (InitializeProcThreadAttributeList(AttributeList, 1, 0, &lpsize) == FALSE) {
			DBG_PRINTF("InitializeProcThreadAttributeList.set");
			bRet = FALSE;
			break;
		}
		/* 用已构造的属性结构体更新属性表 */
		if (!UpdateProcThreadAttribute(AttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &handleExplorer, sizeof(HANDLE), NULL, NULL)) {
			//更新AttrubuteList 属性,添加PROC_THREAD_ATTRIBUTE_PARENT_PROCESS属性
			DBG_PRINTF("UpdateProcThreadAttribute");
			bRet = FALSE;
			break;
		}
		/* 移交指针,这里已更换了父进程的属性表是 explorer.exe */
		si.lpAttributeList = AttributeList;

		// 获得当前Session ID
		dwSessionID = ::WTSGetActiveConsoleSessionId();

		// 获得当前Session的用户令牌
		if (FALSE == ::WTSQueryUserToken(dwSessionID, &hToken)) {
			DBG_PRINTF("WTSQueryUserToken");
			bRet = FALSE;
			break;
		}

		// 复制令牌
		if (FALSE == ::DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDuplicatedToken)) {
			DBG_PRINTF("DuplicateTokenEx");
			bRet = FALSE;
			break;
		}

		// 创建用户Session环境
		if (FALSE == ::CreateEnvironmentBlock(&lpEnvironment, hDuplicatedToken, FALSE)) {
			DBG_PRINTF("CreateEnvironmentBlock");
			bRet = FALSE;
			break;
		}

		// 在复制的用户Session下执行应用程序,创建进程
		size_t iCmdlineSize = _tcslen(lpszFileName) + 10;
		if (lpCommandLine) {
			iCmdlineSize += _tcslen(lpCommandLine);
		}
		std::vector<TCHAR> szCmdLine(iCmdlineSize);
		_stprintf(&szCmdLine.front(), TEXT("\"%s\""), lpszFileName);
		if (lpCommandLine) {
			_tcscat(&szCmdLine.front(), TEXT(" "));
			_tcscat(&szCmdLine.front(), lpCommandLine);
		}
		DBG_PRINTF(L"开始执行程序:%s", lpszFileName);
		DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT /*| EXTENDED_STARTUPINFO_PRESENT*/;
		if (FALSE == ::CreateProcessAsUser(hDuplicatedToken, NULL, &szCmdLine.front(), NULL, NULL, FALSE, dwCreationFlag, lpEnvironment, NULL, (LPSTARTUPINFOW)&si, &pi)) {
			DBG_PRINTF("CreateProcessAsUser");
			bRet = FALSE;
			break;
		}
		DBG_PRINTF(L"执行程序成功,PID[%u]:%s", pi.dwProcessId, lpszFileName);
	} while (FALSE);

	// 关闭句柄, 释放资源
	if (AttributeList) {
		DeleteProcThreadAttributeList(AttributeList);
	}
	if (lpEnvironment)
	{
		::DestroyEnvironmentBlock(lpEnvironment);
	}
	if (hDuplicatedToken)
	{
		::CloseHandle(hDuplicatedToken);
	}
	if (hToken)
	{
		::CloseHandle(hToken);
	}
	// 创建成功
	if (bRet) {
		return pi.hProcess;
	}
	return NULL;
}