[置顶] Windows服务(Windows Service,system权限)程序显示界面与用户交互(xp,win7通用)

来源:互联网 发布:北方周末网络电视台 编辑:程序博客网 时间:2024/06/16 19:30

[置顶]

[置顶] Windows服务(Windows Service,system权限)程序显示界面与用户交互(xp,win7通用)

673人阅读 评论(1)收藏举报

1、VC2008中编写“Windows服务”(Windows Service)程序

源码资源下载:http://download.csdn.net/detail/stony1980/4512984
vc2008下新建一个 ATL 项目-》 选择创建一个“服务”类型的ATL 项目TestService,将生成如下代码,

classCTestServiceModule:publicCAtlServiceModuleT<CTestServiceModule,IDS_SERVICENAME>
{
public:
DECLARE_LIBID(LIBID_TestServiceLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_TESTSERVICE,"{1FF78006-B225-4CC0-A7DE-E0C9D31C9937}")
HRESULTInitializeSecurity()throw()
{
// TODO : 调用CoInitializeSecurity并为服务提供适当的
//安全设置
//建议- PKT 级别的身份验证、
// RPC_C_IMP_LEVEL_IDENTIFY 的模拟级别
//以及适当的非NULL安全说明符。

returnS_OK;
}
//重写这个函数来启动任务啦
HRESULTRun(intnShowCmd=SW_HIDE)throw()
{
HRESULThr=S_OK;
hr=__super::PreMessageLoop(nShowCmd);
if(hr==S_OK)
{
if(m_bService)
{
//需要定义#define_ATL_NO_COM_SUPPORT才能启动服务时走到这里
//可以在这里启动线程,或者什么其他东西来做自己的工作的啦
//这里是什么都没有做了,只输出一条信息

LogEvent(_T("widebright的服务启动咯,呵呵"));
SetServiceStatus(SERVICE_RUNNING);
}
//进入消息循环,不停的处理消息,可能最后分发到Handler去处理,调用了OnShutdown等函数的。
__super::RunMessageLoop();
}
if(SUCCEEDED(hr))
{
hr=__super::PostMessageLoop();
}

//可以在适当的时候调用Uninstall函数来卸载掉服务
//__super::Uninstall();
returnhr;
}
//重写,服务退出处理
voidOnShutdown()throw()
{
LogEvent(_T("TestService的服务退出咯,一点都不好玩呵呵"));
}

};

CTestServiceModule_AtlModule;



//
extern"C"intWINAPI_tWinMain(HINSTANCE,HINSTANCE,
LPTSTR,intnShowCmd)
{
return_AtlModule.WinMain(nShowCmd);
}
2、我只要根据需要重写相应的函数来实现自己想要的功能就行了
比如你想创建的“服务”随系统启动,可以重写CAtlServiceModuleT的Install函数,把里面的CreateService函数的参数修改一下,例如添加与用户交互可以使用 SERVICE_INTERACTIVE_PROCESS,具体可以去MSDN上查找CreateService这个API的说明。

如果想处理服务 停止和启动的动作,可以参考CAtlServiceModuleT 的源代码重写OnStop ()等函数。我上面简单到重写了Run函数,输出一条“事件”其实具体 工作是可以放到这里来完成的吧。

编译,生成程序之后就可以测试了,

执行“TestService -/Service” 就可以把服务注册到系统了,命令行参数其实是在CAtlServiceModuleT::ParseCommandLine 这个函数里面处理,可以去看一下,必要的话重写也是可以的,加上调用 UnInstall来删除服务的代码也很不错的吧。

注册后,就看用“sc start” 或者“net start” 等命令来操纵服务了。在“服务”控制器里面控制与可以:如图


3、这时候在Run函数中启动一个Notepad.exe,此时没有界面显示,在xp下可以使用下面的方法实现notepad与用户的交互:
//for xp system
DWORD_stdcallLaunchAppIntoSession0(LPTSTRlpCommand)
{
////////////////////////////////////////////system show dlg////////////////////

HDESKhdeskCurrent;
HDESKhdesk;
HWINSTAhwinstaCurrent;
HWINSTAhwinsta;
hwinstaCurrent=GetProcessWindowStation();
if(hwinstaCurrent==NULL)
{
returnFALSE;
}
hdeskCurrent=GetThreadDesktop(GetCurrentThreadId());
if(hdeskCurrent==NULL){
returnFALSE;
}
//打开winsta0
//打开winsta0
hwinsta=OpenWindowStation(L"Winsta0",FALSE,WINSTA_ALL_ACCESS);
//WINSTA_ACCESSCLIPBOARD|
//WINSTA_ACCESSGLOBALATOMS |
//WINSTA_ENUMDESKTOPS |
//WINSTA_CREATEDESKTOP |
//WINSTA_CREATEDESKTOP |
//WINSTA_ENUMERATE |
//WINSTA_EXITWINDOWS |
//WINSTA_READATTRIBUTES |
//WINSTA_READSCREEN |
//WINSTA_WRITEATTRIBUTES);
if(hwinsta==NULL){
returnFALSE;
}
if(!SetProcessWindowStation(hwinsta))
{
returnFALSE;
}
//打开desktop
hdesk=OpenDesktop(L"default", 0,FALSE,
DESKTOP_CREATEMENU|
DESKTOP_CREATEWINDOW|
DESKTOP_ENUMERATE|
DESKTOP_HOOKCONTROL|
DESKTOP_JOURNALPLAYBACK|
DESKTOP_JOURNALRECORD|
DESKTOP_READOBJECTS|
DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS);
if(hdesk==NULL){
returnFALSE;
}
SetThreadDesktop(hdesk);
////////////////////////////////////////////end of system show dlg////////////////////
STARTUPINFOsi= {sizeof(si) };
SECURITY_ATTRIBUTESsaProcess,saThread;
PROCESS_INFORMATIONpiProcessB,piProcessC;


// Prepare to spawn Process B from Process A.
// The handle identifying the new process
// object should be inheritable.
saProcess.nLength=sizeof(saProcess);
saProcess.lpSecurityDescriptor=NULL;
saProcess.bInheritHandle=TRUE;

// The handle identifying the new thread
// object should NOT be inheritable.
saThread.nLength=sizeof(saThread);
saThread.lpSecurityDescriptor=NULL;
saThread.bInheritHandle=FALSE;

CreateProcess(NULL,lpCommand, & saProcess, &saThread,
FALSE, 0, NULL,NULL, & si, &piProcessB);


if(!SetProcessWindowStation(hwinstaCurrent))
returnFALSE;
if(!SetThreadDesktop(hdeskCurrent))
returnFALSE;
if(!CloseWindowStation(hwinsta))
returnFALSE;
if(!CloseDesktop(hdesk))
returnFALSE;
returnTRUE;
}

这种方法的关键是OpenWindowStation、SetProcessWindowStation、OpenDesktopSetThreadDesktop这四个函数。这种方法的思路是:当前进程所处于的Session必须有界面交互能力,这样才能显示出对话框。由于第一个交互式用户会登录到拥有WinSta0Session 0,所以,强制性地把服务所在的进程与WinSta0关联起来,并且打开当前的桌面,把工作线程挂到该桌面上,就可以显示出对话框。


4、这种方法在WinXPWindows2003下工作得不错,很遗憾,在VistaWindows2008下,一旦执行到OpenWindowStation,试图代开WinSta0工作站时,程序就会出异常。

首先了解一下程序要具备怎样的条件才能与界面交互。Windows提供了三类对象:用户界面对象(User Interface)、GDI对象和内核对象。内核对象有安全性,而前两者没有。为了对前两者提供安全性,通过工作站对象(Window station)和桌面对象(Desktop)来管理用户界面对象,因为工作站对象和桌面对象有安全特性。简单说来,工作站是一个带有安全特性的对象,它与进程相关联,包含了一个或多个桌面对象。当工作站对象被创建时,它被关联到调用进程上,并且被赋给当前Session。交互式工作站WinSta0,是唯一一个可以显示用户界面,接受用户输入的工作站。它被赋给交互式用户的登录Session,包含了键盘、鼠标和显示设备。所有其他工作站都是非交互式的,这就意味着它们不能显示用户界面,不能接受用户的输入。当用户登录到一台启用了终端服务的计算机上时,每个用户都会启动一个Session。每个Session都会与自己的交互式工作站相联系。桌面是一个带有安全特性的对象,被包含在一个窗口工作站对象中。一个桌面对象有一个逻辑的显示区域,包含了诸如窗口、菜单、钩子等等这样的用户界面对象。

Vista之前,之所以可以通过打开Winsta0和缺省桌面显示对话框,是因为不管是服务还是第一个登录的交互式用户,都是登录到Session 0中。因此,服务程序可以通过强制打开WinSta0和桌面来获得交互能力。

然而,在VistaWindows2008中,Session 0专用于服务和其他不与用户交互的应用程序。第一个登录进来,可以进行交互式操作的用户被连到Session 1上。第二个登录进行的用户被分配给Session 2,以此类推。Session 0完全不支持要与用户交互的进程。如果采取在服务进程中启动子进程来显示对话框,子对话框将无法显示;如果采取用OpenWindowStation系统API打开WinSta0的方法,函数调用会失败。总之,VistaWindows2008已经堵上了在Session 0中产生界面交互的路。这就是原因所在。

那么,是否真的没法在服务中弹出对话框了呢?对于服务进程自身来说,确实如此,操作系统已经把这条路堵上了。但是,我们想要的并不是“在服务进程中弹出对话框”,我们想要的不过是“当服务出现某些状况的时候,在桌面上弹出对话框”。既然在Session 0中无法弹出对话框,而我们看到的桌面是Session X,并非Session 0,很自然的一个想法是:能不能让Session 0通知其他的Session,让当前桌面正显示着的Session弹一个对话框呢?

幸运的是,还真可以这样做。

//for win7
DWORD_stdcallLaunchAppIntoDifferentSession(LPTSTRlpCommand)
{
DWORDdwRet= 0;
PROCESS_INFORMATIONpi;
STARTUPINFOsi;
DWORDdwSessionId;
HANDLEhUserToken=NULL;
HANDLEhUserTokenDup=NULL;
HANDLEhPToken=NULL;
HANDLEhProcess=NULL;
DWORDdwCreationFlags;

HMODULEhInstKernel32=NULL;
typedefDWORD(WINAPI*WTSGetActiveConsoleSessionIdPROC)();
WTSGetActiveConsoleSessionIdPROCWTSGetActiveConsoleSessionId=NULL;

hInstKernel32=LoadLibrary(L"Kernel32.dll");

if(!hInstKernel32)
{
returnFALSE;
}

OutputDebugString(L"LaunchAppIntoDifferentSession 1\n");
WTSGetActiveConsoleSessionId= (WTSGetActiveConsoleSessionIdPROC)GetProcAddress(hInstKernel32,"WTSGetActiveConsoleSessionId");


// Log the client on to the local computer.
dwSessionId=WTSGetActiveConsoleSessionId();

do
{
WTSQueryUserToken(dwSessionId,&hUserToken);
dwCreationFlags=NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE;
ZeroMemory( &si,sizeof(STARTUPINFO) );
si.cb=sizeof(STARTUPINFO);
si.lpDesktop=L"winsta0\\default";
ZeroMemory( &pi,sizeof(pi) );
TOKEN_PRIVILEGEStp;
LUIDluid;

if( !::OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID
|TOKEN_READ|TOKEN_WRITE, &hPToken) )
{
dwRet=GetLastError();
break;
}
else;

if( !LookupPrivilegeValue(NULL,SE_DEBUG_NAME, &luid) )
{
dwRet=GetLastError();
break;
}
else;
tp.PrivilegeCount=1;
tp.Privileges[0].Luid=luid;
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;

if( !DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary, & hUserTokenDup) )
{
dwRet=GetLastError();
break;
}
else;

//Adjust Token privilege
if( !SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)&dwSessionId,sizeof(DWORD) ) )
{
dwRet=GetLastError();
break;
}
else;

if( !AdjustTokenPrivileges(hUserTokenDup,FALSE, &tp,sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL,NULL) )
{
dwRet=GetLastError();
break;
}
else;

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

// Launch the process in the client's logon session.
if(CreateProcessAsUser(hUserTokenDup,// client's access token
NULL,// file to execute
lpCommand,// 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
) )
{
}
else
{
dwRet=GetLastError();
break;
}
}
while( 0 );

//Perform All the Close Handles task
if(NULL!=hUserToken)
{
CloseHandle(hUserToken);
}
else;

if(NULL!=hUserTokenDup)
{
CloseHandle(hUserTokenDup);
}
else;

if(NULL!=hPToken)
{
CloseHandle(hPToken);
}
else;

returndwRet;
}

5、启动服务后显示了system权限的Notepad.exe,并且可以与用户进行交互



当然,在本例子启动进程的地方创建一个对话框也是可以显示对话框的。
673人阅读 评论(1)收藏 举报

1、VC2008中编写“Windows服务”(Windows Service)程序

源码资源下载:http://download.csdn.net/detail/stony1980/4512984
vc2008下新建一个 ATL 项目-》 选择创建一个“服务”类型的ATL 项目TestService,将生成如下代码,

classCTestServiceModule:publicCAtlServiceModuleT<CTestServiceModule,IDS_SERVICENAME>
{
public:
DECLARE_LIBID(LIBID_TestServiceLib)
DECLARE_REGISTRY_APPID_RESOURCEID(IDR_TESTSERVICE,"{1FF78006-B225-4CC0-A7DE-E0C9D31C9937}")
HRESULTInitializeSecurity()throw()
{
// TODO : 调用CoInitializeSecurity并为服务提供适当的
//安全设置
//建议- PKT 级别的身份验证、
// RPC_C_IMP_LEVEL_IDENTIFY 的模拟级别
//以及适当的非NULL安全说明符。

returnS_OK;
}
//重写这个函数来启动任务啦
HRESULTRun(intnShowCmd=SW_HIDE)throw()
{
HRESULThr=S_OK;
hr=__super::PreMessageLoop(nShowCmd);
if(hr==S_OK)
{
if(m_bService)
{
//需要定义#define_ATL_NO_COM_SUPPORT才能启动服务时走到这里
//可以在这里启动线程,或者什么其他东西来做自己的工作的啦
//这里是什么都没有做了,只输出一条信息

LogEvent(_T("widebright的服务启动咯,呵呵"));
SetServiceStatus(SERVICE_RUNNING);
}
//进入消息循环,不停的处理消息,可能最后分发到Handler去处理,调用了OnShutdown等函数的。
__super::RunMessageLoop();
}
if(SUCCEEDED(hr))
{
hr=__super::PostMessageLoop();
}

//可以在适当的时候调用Uninstall函数来卸载掉服务
//__super::Uninstall();
returnhr;
}
//重写,服务退出处理
voidOnShutdown()throw()
{
LogEvent(_T("TestService的服务退出咯,一点都不好玩呵呵"));
}

};

CTestServiceModule_AtlModule;



//
extern"C"intWINAPI_tWinMain(HINSTANCE,HINSTANCE,
LPTSTR,intnShowCmd)
{
return_AtlModule.WinMain(nShowCmd);
}
2、我只要根据需要重写相应的函数来实现自己想要的功能就行了
比如你想创建的“服务”随系统启动,可以重写CAtlServiceModuleT的Install函数,把里面的CreateService函数的参数修改一下,例如添加与用户交互可以使用 SERVICE_INTERACTIVE_PROCESS,具体可以去MSDN上查找CreateService这个API的说明。

如果想处理服务 停止和启动的动作,可以参考CAtlServiceModuleT 的源代码重写OnStop ()等函数。我上面简单到重写了Run函数,输出一条“事件”其实具体 工作是可以放到这里来完成的吧。

编译,生成程序之后就可以测试了,

执行“TestService -/Service” 就可以把服务注册到系统了,命令行参数其实是在CAtlServiceModuleT::ParseCommandLine 这个函数里面处理,可以去看一下,必要的话重写也是可以的,加上调用 UnInstall来删除服务的代码也很不错的吧。

注册后,就看用“sc start” 或者“net start” 等命令来操纵服务了。在“服务”控制器里面控制与可以:如图


3、这时候在Run函数中启动一个Notepad.exe,此时没有界面显示,在xp下可以使用下面的方法实现notepad与用户的交互:
//for xp system
DWORD_stdcallLaunchAppIntoSession0(LPTSTRlpCommand)
{
////////////////////////////////////////////system show dlg////////////////////

HDESKhdeskCurrent;
HDESKhdesk;
HWINSTAhwinstaCurrent;
HWINSTAhwinsta;
hwinstaCurrent=GetProcessWindowStation();
if(hwinstaCurrent==NULL)
{
returnFALSE;
}
hdeskCurrent=GetThreadDesktop(GetCurrentThreadId());
if(hdeskCurrent==NULL){
returnFALSE;
}
//打开winsta0
//打开winsta0
hwinsta=OpenWindowStation(L"Winsta0",FALSE,WINSTA_ALL_ACCESS);
//WINSTA_ACCESSCLIPBOARD|
//WINSTA_ACCESSGLOBALATOMS |
//WINSTA_ENUMDESKTOPS |
//WINSTA_CREATEDESKTOP |
//WINSTA_CREATEDESKTOP |
//WINSTA_ENUMERATE |
//WINSTA_EXITWINDOWS |
//WINSTA_READATTRIBUTES |
//WINSTA_READSCREEN |
//WINSTA_WRITEATTRIBUTES);
if(hwinsta==NULL){
returnFALSE;
}
if(!SetProcessWindowStation(hwinsta))
{
returnFALSE;
}
//打开desktop
hdesk=OpenDesktop(L"default", 0,FALSE,
DESKTOP_CREATEMENU|
DESKTOP_CREATEWINDOW|
DESKTOP_ENUMERATE|
DESKTOP_HOOKCONTROL|
DESKTOP_JOURNALPLAYBACK|
DESKTOP_JOURNALRECORD|
DESKTOP_READOBJECTS|
DESKTOP_SWITCHDESKTOP|
DESKTOP_WRITEOBJECTS);
if(hdesk==NULL){
returnFALSE;
}
SetThreadDesktop(hdesk);
////////////////////////////////////////////end of system show dlg////////////////////
STARTUPINFOsi= {sizeof(si) };
SECURITY_ATTRIBUTESsaProcess,saThread;
PROCESS_INFORMATIONpiProcessB,piProcessC;


// Prepare to spawn Process B from Process A.
// The handle identifying the new process
// object should be inheritable.
saProcess.nLength=sizeof(saProcess);
saProcess.lpSecurityDescriptor=NULL;
saProcess.bInheritHandle=TRUE;

// The handle identifying the new thread
// object should NOT be inheritable.
saThread.nLength=sizeof(saThread);
saThread.lpSecurityDescriptor=NULL;
saThread.bInheritHandle=FALSE;

CreateProcess(NULL,lpCommand, & saProcess, &saThread,
FALSE, 0, NULL,NULL, & si, &piProcessB);


if(!SetProcessWindowStation(hwinstaCurrent))
returnFALSE;
if(!SetThreadDesktop(hdeskCurrent))
returnFALSE;
if(!CloseWindowStation(hwinsta))
returnFALSE;
if(!CloseDesktop(hdesk))
returnFALSE;
returnTRUE;
}

这种方法的关键是OpenWindowStation、SetProcessWindowStation、OpenDesktopSetThreadDesktop这四个函数。这种方法的思路是:当前进程所处于的Session必须有界面交互能力,这样才能显示出对话框。由于第一个交互式用户会登录到拥有WinSta0Session 0,所以,强制性地把服务所在的进程与WinSta0关联起来,并且打开当前的桌面,把工作线程挂到该桌面上,就可以显示出对话框。


4、这种方法在WinXPWindows2003下工作得不错,很遗憾,在VistaWindows2008下,一旦执行到OpenWindowStation,试图代开WinSta0工作站时,程序就会出异常。

首先了解一下程序要具备怎样的条件才能与界面交互。Windows提供了三类对象:用户界面对象(User Interface)、GDI对象和内核对象。内核对象有安全性,而前两者没有。为了对前两者提供安全性,通过工作站对象(Window station)和桌面对象(Desktop)来管理用户界面对象,因为工作站对象和桌面对象有安全特性。简单说来,工作站是一个带有安全特性的对象,它与进程相关联,包含了一个或多个桌面对象。当工作站对象被创建时,它被关联到调用进程上,并且被赋给当前Session。交互式工作站WinSta0,是唯一一个可以显示用户界面,接受用户输入的工作站。它被赋给交互式用户的登录Session,包含了键盘、鼠标和显示设备。所有其他工作站都是非交互式的,这就意味着它们不能显示用户界面,不能接受用户的输入。当用户登录到一台启用了终端服务的计算机上时,每个用户都会启动一个Session。每个Session都会与自己的交互式工作站相联系。桌面是一个带有安全特性的对象,被包含在一个窗口工作站对象中。一个桌面对象有一个逻辑的显示区域,包含了诸如窗口、菜单、钩子等等这样的用户界面对象。

Vista之前,之所以可以通过打开Winsta0和缺省桌面显示对话框,是因为不管是服务还是第一个登录的交互式用户,都是登录到Session 0中。因此,服务程序可以通过强制打开WinSta0和桌面来获得交互能力。

然而,在VistaWindows2008中,Session 0专用于服务和其他不与用户交互的应用程序。第一个登录进来,可以进行交互式操作的用户被连到Session 1上。第二个登录进行的用户被分配给Session 2,以此类推。Session 0完全不支持要与用户交互的进程。如果采取在服务进程中启动子进程来显示对话框,子对话框将无法显示;如果采取用OpenWindowStation系统API打开WinSta0的方法,函数调用会失败。总之,VistaWindows2008已经堵上了在Session 0中产生界面交互的路。这就是原因所在。

那么,是否真的没法在服务中弹出对话框了呢?对于服务进程自身来说,确实如此,操作系统已经把这条路堵上了。但是,我们想要的并不是“在服务进程中弹出对话框”,我们想要的不过是“当服务出现某些状况的时候,在桌面上弹出对话框”。既然在Session 0中无法弹出对话框,而我们看到的桌面是Session X,并非Session 0,很自然的一个想法是:能不能让Session 0通知其他的Session,让当前桌面正显示着的Session弹一个对话框呢?

幸运的是,还真可以这样做。

//for win7
DWORD_stdcallLaunchAppIntoDifferentSession(LPTSTRlpCommand)
{
DWORDdwRet= 0;
PROCESS_INFORMATIONpi;
STARTUPINFOsi;
DWORDdwSessionId;
HANDLEhUserToken=NULL;
HANDLEhUserTokenDup=NULL;
HANDLEhPToken=NULL;
HANDLEhProcess=NULL;
DWORDdwCreationFlags;

HMODULEhInstKernel32=NULL;
typedefDWORD(WINAPI*WTSGetActiveConsoleSessionIdPROC)();
WTSGetActiveConsoleSessionIdPROCWTSGetActiveConsoleSessionId=NULL;

hInstKernel32=LoadLibrary(L"Kernel32.dll");

if(!hInstKernel32)
{
returnFALSE;
}

OutputDebugString(L"LaunchAppIntoDifferentSession 1\n");
WTSGetActiveConsoleSessionId= (WTSGetActiveConsoleSessionIdPROC)GetProcAddress(hInstKernel32,"WTSGetActiveConsoleSessionId");


// Log the client on to the local computer.
dwSessionId=WTSGetActiveConsoleSessionId();

do
{
WTSQueryUserToken(dwSessionId,&hUserToken);
dwCreationFlags=NORMAL_PRIORITY_CLASS|CREATE_NEW_CONSOLE;
ZeroMemory( &si,sizeof(STARTUPINFO) );
si.cb=sizeof(STARTUPINFO);
si.lpDesktop=L"winsta0\\default";
ZeroMemory( &pi,sizeof(pi) );
TOKEN_PRIVILEGEStp;
LUIDluid;

if( !::OpenProcessToken(GetCurrentProcess(),TOKEN_ADJUST_PRIVILEGES|TOKEN_QUERY
|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY|TOKEN_ADJUST_SESSIONID
|TOKEN_READ|TOKEN_WRITE, &hPToken) )
{
dwRet=GetLastError();
break;
}
else;

if( !LookupPrivilegeValue(NULL,SE_DEBUG_NAME, &luid) )
{
dwRet=GetLastError();
break;
}
else;
tp.PrivilegeCount=1;
tp.Privileges[0].Luid=luid;
tp.Privileges[0].Attributes=SE_PRIVILEGE_ENABLED;

if( !DuplicateTokenEx(hPToken,MAXIMUM_ALLOWED,NULL,SecurityIdentification,TokenPrimary, & hUserTokenDup) )
{
dwRet=GetLastError();
break;
}
else;

//Adjust Token privilege
if( !SetTokenInformation(hUserTokenDup,TokenSessionId,(void*)&dwSessionId,sizeof(DWORD) ) )
{
dwRet=GetLastError();
break;
}
else;

if( !AdjustTokenPrivileges(hUserTokenDup,FALSE, &tp,sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL,NULL) )
{
dwRet=GetLastError();
break;
}
else;

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

// Launch the process in the client's logon session.
if(CreateProcessAsUser(hUserTokenDup,// client's access token
NULL,// file to execute
lpCommand,// 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
) )
{
}
else
{
dwRet=GetLastError();
break;
}
}
while( 0 );

//Perform All the Close Handles task
if(NULL!=hUserToken)
{
CloseHandle(hUserToken);
}
else;

if(NULL!=hUserTokenDup)
{
CloseHandle(hUserTokenDup);
}
else;

if(NULL!=hPToken)
{
CloseHandle(hPToken);
}
else;

returndwRet;
}

5、启动服务后显示了system权限的Notepad.exe,并且可以与用户进行交互



当然,在本例子启动进程的地方创建一个对话框也是可以显示对话框的。
原创粉丝点击