最近碰到个问题, 需要在服务中检测用户桌面的情况。但是服务程序都是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 版权协议,转载请附上原文出处链接和本声明。