windows服务程序中创建用户进程

  • Post author:
  • Post category:其他

最近碰到个问题, 需要在服务中检测用户桌面的情况。但是服务程序都是SYSTEM账户下运行, 属于Session0, 不能检测到用户桌面的情况。所以就需要另启一个用户进程来获取这些信息, 然后发送给服务。所以就用到了 CreateProcessAsUser来创建用户进程。

#include <Windows.h>
#include <iostream>
#include <fstream>
#include <Wtsapi32.h>
#include <TlHelp32.h>
#pragma comment(lib, "wtsapi32.lib")
#include <Userenv.h>
#pragma comment(lib,"userenv.lib")
using namespace std;

typedef struct _TOKEN_LINKED_TOKEN {
	HANDLE LinkedToken;
} TOKEN_LINKED_TOKEN, *PTOKEN_LINKED_TOKEN;
SERVICE_STATUS_HANDLE hServiceStatus;
SERVICE_STATUS ServiceStatus; 


DWORD GetActiveSessionID()
{

	DWORD dwSessionId = 0;
	PWTS_SESSION_INFO pSessionInfo = NULL;
	DWORD dwCount = 0;

	WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount);

	for(DWORD i = 0; i < dwCount; i++)
	{
		WTS_SESSION_INFO si = pSessionInfo[i];
		if(WTSActive == si.State)
		{
			dwSessionId = si.SessionId;
			break;
		}
	}

	WTSFreeMemory(pSessionInfo);
	return dwSessionId;

}

BOOL ServiceExecute(std::wstring wstrCmdLine, INT32& n32ExitResult)
{
	ofstream ofile("C:\\logEvent.txt");
	ofile<<"start excute"<<std::endl;
	DWORD dwProcesses = 0;
	BOOL bResult = FALSE;

	DWORD dwSid = GetActiveSessionID();

	DWORD dwRet = 0;
	PROCESS_INFORMATION pi;
	STARTUPINFO si;
	HANDLE hProcess = NULL, hPToken = NULL, hUserTokenDup = NULL;
	if (!WTSQueryUserToken(dwSid, &hPToken))
	{
		ofile<<"get token error 1"<<std::endl;
		PROCESSENTRY32 procEntry;
		DWORD dwPid = 0;
		HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
		if (hSnap == INVALID_HANDLE_VALUE)
		{
			return FALSE;
		}

		procEntry.dwSize = sizeof(PROCESSENTRY32);
		if (Process32First(hSnap, &procEntry))
		{
			do
			{
				if (_tcsicmp(procEntry.szExeFile, _T("explorer.exe")) == 0)
				{
					DWORD exeSessionId = 0;
					if (ProcessIdToSessionId(procEntry.th32ProcessID, &exeSessionId) && exeSessionId == dwSid)
					{
						dwPid = procEntry.th32ProcessID;
						break;
					}
				}

			} while (Process32Next(hSnap, &procEntry));
		}
		CloseHandle(hSnap);

		// explorer进程不存在
		if (dwPid == 0)
		{
			return FALSE;
		}

		hProcess = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, dwPid);
		if (hProcess == NULL)
		{
			return FALSE;
		}

		if(!::OpenProcessToken(hProcess, TOKEN_ALL_ACCESS_P,&hPToken))
		{
			CloseHandle(hProcess);
			return FALSE;
		}
	}

	if (hPToken == NULL)
		return FALSE;

	TOKEN_LINKED_TOKEN admin;
	bResult = GetTokenInformation(hPToken, (TOKEN_INFORMATION_CLASS)19, &admin, sizeof(TOKEN_LINKED_TOKEN), &dwRet);

	if (!bResult) // vista 以前版本不支持TokenLinkedToken
	{
		ofile<<"Get token info error" <<std::endl;
		TOKEN_PRIVILEGES tp;
		LUID luid;
		if (LookupPrivilegeValue(NULL,SE_DEBUG_NAME,&luid))
		{
			tp.PrivilegeCount =1;
			tp.Privileges[0].Luid =luid;
			tp.Privileges[0].Attributes =SE_PRIVILEGE_ENABLED;
		}
		DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary,&hUserTokenDup);
	}
	else
	{
		hUserTokenDup = admin.LinkedToken;
		ofile<<"token: "<<hUserTokenDup<<std::endl;
	}

	LPVOID pEnv =NULL;
	DWORD dwCreationFlags = CREATE_PRESERVE_CODE_AUTHZ_LEVEL;

	if(CreateEnvironmentBlock(&pEnv,hUserTokenDup,TRUE))
	{
		dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT;
	}
	else
	{
		pEnv = NULL;
	}

	ZeroMemory( &si, sizeof(si) );
	si.cb = sizeof(si);
	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_SHOWNORMAL;
	ZeroMemory( &pi, sizeof(pi) );

	bResult = CreateProcessAsUser(
		hUserTokenDup,                     // client's access token
		NULL,    // file to execute
		(LPTSTR) wstrCmdLine.c_str(),                 // command line
		NULL,            // pointer to process SECURITY_ATTRIBUTES
		NULL,               // pointer to thread SECURITY_ATTRIBUTES
		FALSE,              // handles are not inheritable
		dwCreationFlags,     // creation flags
		pEnv,               // pointer to new environment block
		NULL,               // name of current directory
		&si,               // pointer to STARTUPINFO structure
		&pi                // receives information about new process
		);	

	if(pi.hProcess)
	{
		if(WAIT_OBJECT_0 == WaitForSingleObject(pi.hProcess, 180000))
		{
			DWORD dwResult = 0;
			if(GetExitCodeProcess(pi.hProcess,  &dwResult))
			{
				n32ExitResult = dwResult;
			}
			else
			{
				n32ExitResult = -1;
			}

			CloseHandle(pi.hThread);
			CloseHandle(pi.hProcess);
		}
		else
		{
			CloseHandle(pi.hThread);
			CloseHandle(pi.hProcess);
			n32ExitResult = -1;
		}
	}



	if (hUserTokenDup != NULL)
		CloseHandle(hUserTokenDup);
	if (hProcess != NULL)
		CloseHandle(hProcess);
	if (hPToken != NULL)
		CloseHandle(hPToken);
	if (pEnv != NULL)
		DestroyEnvironmentBlock(pEnv);

	return TRUE;

}

void CreateProcess2()
{
	HANDLE hTokenThis = NULL;
	HANDLE hTokenDup = NULL;
	HANDLE hThisProcess = GetCurrentProcess();
	BOOL bResult = FALSE;
	bResult = OpenProcessToken(hThisProcess, TOKEN_ALL_ACCESS, &hTokenThis);
	if(!bResult)
	{
		printf("OpenProcessToken Failed! Error = 0x%08lx\n", GetLastError());
		return;
	}

	bResult = DuplicateTokenEx(hTokenThis, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hTokenDup);
	if(!bResult)
	{
		printf("DuplicateTokenEx Failed! Error = 0x%08lx\n", GetLastError());
		return;
	}

	DWORD dwSessionId = WTSGetActiveConsoleSessionId();
	bResult = SetTokenInformation(hTokenDup, TokenSessionId, &dwSessionId, sizeof(DWORD));
	if(!bResult)
	{
		printf("SetTokenInformation Failed! Error = 0x%08lx\n", GetLastError());
		return;
	}

	STARTUPINFO si;
	PROCESS_INFORMATION pi;
	ZeroMemory(&si, sizeof(STARTUPINFO));
	ZeroMemory(&pi, sizeof(PROCESS_INFORMATION));
	si.cb = sizeof(STARTUPINFO);
	//si.lpDesktop = "WinSta0\\Default";

	si.dwFlags = STARTF_USESHOWWINDOW;
	si.wShowWindow = SW_SHOWNORMAL;

	LPVOID pEnv = NULL;
	DWORD dwCreationFlag = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT;

	bResult = CreateEnvironmentBlock(&pEnv, hTokenDup, FALSE);
	if(!bResult)
	{
		printf("CreateEnvironmentBlock Failed! Error = 0x%08lx\n", GetLastError());
		return;
	}

	TCHAR szApp[MAX_PATH] = _T("notepad.exe");
	bResult = CreateProcessAsUser(hTokenDup, NULL, szApp, NULL, NULL, FALSE, dwCreationFlag, pEnv, NULL, &si, &pi);
	if(!bResult)
	{
		return;
	}
}

void WINAPI ServiceMain(DWORD argc, char**argv)
{
	ServiceStatus.dwCurrentState=SERVICE_START_PENDING;
	ServiceStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP;

	//注册服务控制函数
	//hServiceStatus=RegisterServiceCtrlHandler(L"ATestService",ServiceStrl);
	//if(!hServiceStatus)
	//{
	//	MessageBox(NULL,"注册控制服务失败!","",MB_OK);
	//	return;
	//}

	//设置服务状态
	SetServiceStatus(hServiceStatus,&ServiceStatus);

	ServiceStatus.dwWin32ExitCode=S_OK;
	ServiceStatus.dwCheckPoint=0;
	ServiceStatus.dwWaitHint=0;
	ServiceStatus.dwCurrentState=SERVICE_RUNNING;
	SetServiceStatus(hServiceStatus,&ServiceStatus);

	//服务任务部分
	ofstream ofile("C:\\logEvent.txt");
	ofile<<"Service Start"<<std::endl;


	while(1)
	{
		ofile<<"run...open process as user"<<std::endl;
		ofile.close();
		wchar_t buf[MAX_PATH] = L"notepad.exe";
		int ret = 0;
		//ServiceExecute(L"notepad.exe", ret);
		CreateProcess2();
		break;
	}

	//退出服务
	ServiceStatus.dwCurrentState=SERVICE_STOPPED;
	SetServiceStatus(hServiceStatus,&ServiceStatus);
}
int _tmain(int argc, _TCHAR* argv[])
{
	DWORD nRet = 0;

	SECURITY_ATTRIBUTES SecAttr;
	SECURITY_DESCRIPTOR SecDesc;
	SecAttr.nLength = sizeof(SecAttr);
	SecAttr.bInheritHandle = FALSE;
	SecAttr.lpSecurityDescriptor = &SecDesc;
	InitializeSecurityDescriptor(&SecDesc, SECURITY_DESCRIPTOR_REVISION);
	SetSecurityDescriptorDacl(&SecDesc, TRUE, 0, FALSE);
	HANDLE hTest = CreateEvent(&SecAttr,TRUE,FALSE,L"Global\\Service_Test_Handle");

	HANDLE hClientTest = CreateEvent(NULL,TRUE,FALSE,L"Global\\User_Test_Handle");

	DWORD dwLastError = GetLastError();
	if (hClientTest && ERROR_ALREADY_EXISTS == dwLastError)
	{
		ofstream ofile("C:\\logHandle.txt");
		ofile<<"open user handle ok"<<std::endl;
		ofile.close();
	}
	ofstream ofile("C:\\logHandle.txt");
	ofile<<"GetLastError: "<<dwLastError<<std::endl;
	ofile.close();

	SERVICE_TABLE_ENTRY dispatchTable[] =
	{
		{ L"ATestService", (LPSERVICE_MAIN_FUNCTION)ServiceMain},
		{NULL, NULL}
	};

	// Call the service control dispatcher with our entry table
	if (!StartServiceCtrlDispatcher(dispatchTable))
	{
		return GetLastError();
	}
	return 0;
}

ServiceExecute比CreateProcess2的实现更加完善, 实际运行中用ServiceExecute更好。


版权声明:本文为linfengmove原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。