Windows服务(system权限)程序显示界面与用户交互,Session0通知Session1里弹出对话框(真的很牛) good

源码资源下载:http://download.csdn.net/detail/stony1980/4512984

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

vc2008下新建一个 ATL 项目-》 选择创建一个“服务”类型的ATL 项目TestService,将生成如下代码,

class CTestServiceModule : public CAtlServiceModuleT< CTestServiceModule, IDS_SERVICENAME >

{

public :

DECLARE_LIBID(LIBID_TestServiceLib )

DECLARE_REGISTRY_APPID_RESOURCEID (IDR_TESTSERVICE, "{1FF78006-B225-4CC0-A7DE-E0C9D31C9937}" )

HRESULT InitializeSecurity () throw()

{

// TODO : 调用CoInitializeSecurity 并为服务提供适当的

// 安全设置

// 建议- PKT 级别的身份验证、

// RPC_C_IMP_LEVEL_IDENTIFY 的模拟级别

// 以及适当的非NULL 安全说明符。

return S_OK ;

}

//重写这个函数来启动任务啦

HRESULT Run (int nShowCmd = SW_HIDE ) throw()

{

HRESULT hr = 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();

return hr ;

}

//重写,服务退出处理

void OnShutdown () throw()

{

LogEvent(_T ("TestService 的服务退出咯,一点都不好玩呵呵 "));

}

};

CTestServiceModule _AtlModule;

//

extern "C" int WINAPI _tWinMain (HINSTANCE , HINSTANCE ,

LPTSTR  , int nShowCmd)

{

return _AtlModule .WinMain( nShowCmd);

}

我只要根据需要重写相应的函数来实现自己想要的功能就行了,比如你想创建的“服务”随系统启动,可以重写CAtlServiceModuleT   的Install函数,把里面的CreateService函数的参数修改一下,例如添加与用户交互可以使用 SERVICE_INTERACTIVE_PROCESS,具体可以去MSDN上查找CreateService这个API的说明。

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

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

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

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

这时候在Run函数中启动一个Notepad.exe,此时没有界面显示,在xp下可以使用下面的方法实现notepad与用户的交互:

//for xp system

DWORD _stdcall LaunchAppIntoSession0( LPTSTR lpCommand )

{

////////////////////////////////////////////system show dlg////////////////////

HDESK hdeskCurrent ;

HDESK hdesk ;

HWINSTA hwinstaCurrent ;

HWINSTA hwinsta ;

hwinstaCurrent = GetProcessWindowStation ();

if (hwinstaCurrent == NULL)

{

return FALSE ;

}

hdeskCurrent = GetThreadDesktop (GetCurrentThreadId());

if (hdeskCurrent == NULL){

return FALSE ;

}

//打开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){

return FALSE ;

}

if (!SetProcessWindowStation (hwinsta))

{

return FALSE ;

}

//打开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){

return FALSE ;

}

SetThreadDesktop(hdesk );

////////////////////////////////////////////end of system show dlg////////////////////

STARTUPINFO si = { sizeof( si) };

SECURITY_ATTRIBUTES saProcess , saThread;

PROCESS_INFORMATION piProcessB , 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))

return FALSE ;

if (!SetThreadDesktop (hdeskCurrent))

return FALSE ;

if (!CloseWindowStation (hwinsta))

return FALSE ;

if (!CloseDesktop (hdesk))

return FALSE ;

return TRUE ;

}

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

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

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

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

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

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

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

//for win7

DWORD _stdcall LaunchAppIntoDifferentSession( LPTSTR lpCommand )

{

DWORD dwRet = 0;

PROCESS_INFORMATION pi ;

STARTUPINFO si ;

DWORD dwSessionId ;

HANDLE hUserToken = NULL;

HANDLE hUserTokenDup = NULL;

HANDLE hPToken = NULL;

HANDLE hProcess = NULL;

DWORD dwCreationFlags ;

HMODULE hInstKernel32     = NULL;

typedef DWORD (WINAPI * WTSGetActiveConsoleSessionIdPROC)();

WTSGetActiveConsoleSessionIdPROC WTSGetActiveConsoleSessionId = NULL;

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

if (!hInstKernel32 )

{

return FALSE ;

}

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_PRIVILEGES tp ;

LUID luid ;

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;

LPVOID pEnv =NULL;

if( CreateEnvironmentBlock ( &pEnv, hUserTokenDup, TRUE ) )

{

dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT ;

}

else pEnv =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;

return dwRet ;

}

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

当然,在本例子启动进程的地方创建一个对话框也是可以

http://blog.sina.com.cn/s/blog_488cff5201017yug.html

时间: 2024-11-03 21:38:13

Windows服务(system权限)程序显示界面与用户交互,Session0通知Session1里弹出对话框(真的很牛) good的相关文章

Windows服务System权限下在当前用户桌面创建快捷方式C#实例程序

Windows服务一般运行在System权限下,这样权限比较高,方便执行一些高权限的操作. 但是,Environment.GetFolderPath等函数获取的也是System用户下的,而不是当前用户的. 解决方法 模拟当前用户,调用Environment.GetFolderPath等函数获取当前用户的路径,退出模拟 查看输出,可以看到模拟成功了: 第一行是当前用户的,第二行输出的是System用户的路径 获取完整的实例代码 支持WinXP及以上操作系统 原文地址:https://www.cnb

Windows服务器SYSTEM权限Webshell无法添加3389账户情况突破总结

转自:http://bbs.blackbap.org/thread-2331-1-1.html 近好多Silic的朋友在Windows下SYSTEM权限的php webshell下添加账户,但是却无法成功.SYSTEM的权限,权限是够了,却无法成功,原因是什么呢?原因有很多种,于是我总结了一下成因,并在下面文章进行了一一分析,然后附上了一点个人的突破绕过方法.提权不可能百分百成功,我只是总结了一些常见的情况,其他的我会慢慢补充作者:YoCo Smart来自:Silic Group Hacker

(转)为C# Windows服务添加安装程序

本文转载自:http://kamiff.iteye.com/blog/507129 最近一直在搞Windows服务,也有了不少经验,感觉权限方面确定比一般程序要受限很多,但方便性也很多.像后台运行不阻塞系统,不用用户登录之类.哈 哈,扯远了,今天讲一下那个怎么给Windows服务做个安装包.为什么做安装包?当然是方便了,不用每次调用InstallUtil,还有,就是看上去 正规些. 不多说了,先来看看怎么做吧.首先,当然是创建一个Windows服务的项目.这个大家应该都知道怎么做(这都不明白的留

为C# Windows服务添加安装程序

最近一直在搞Windows服务,也有了不少经验,感觉权限方面确定比一般程序要受限很多,但方便性也很多.像后台运行不阻塞系统,不用用户登录之类.哈哈,扯远了,今天讲一下那个怎么给Windows服务做个安装包.为什么做安装包?当然是方便了,不用每次调用InstallUtil,还有,就是看上去正规些. 不多说了,先来看看怎么做吧.首先,当然是创建一个Windows服务的项目.这个大家应该都知道怎么做(这都不明白的留言问我),然后要给服务“添加安装程序”,如图1所示:(这一步和自己用InstallUti

JavaScript-1.最简单的程序之网页弹出对话框,显示为Warning---ShinePans

show和set命令是两条用于维护SQLPlus系统变量的命令 : SQL> show all --查看所有系统变量值 SQL>show user --显示当前连接用户 SQL>show error --显示错误(编译function,procedure,package,pl/sql的时候,可以查看具体的错误提示) SQL>set sqlprompt SQL  --设置默认提示符,默认值就是SQL SQL>set linesize 1000 --设置屏幕显示行宽,默认100

Android 背景可滑动登录界面 「 实现不压缩背景弹出键盘 」

Android 背景可滑动登录界面 废话不多说,先看下实现后的效果: 实现思路 看到上边 gif 图的效果,主要列举一下实现过程过程中遇到的难点. 如何使键盘弹出时候不遮挡底部登录布局: 当键盘弹出的时候如何不压缩背景图片或者背景延伸至「屏幕以外」: 从 「 windowSoftInputMode 」 说起 相信大家都清楚,Google 官方提供给开发者控制软键盘显示隐藏的方法不多,「windowSoftInputMode」算是我们可控制的软键盘弹出模式的方法之一.关于其属性的说明Google

Selenium(八):其他操作元素的方法、冻结界面、弹出对话框、开发技巧

1. 其他操作元素的方法 之前我们对web元素做的操作主要是:选择元素,然后点击元素或者输入字符串. 还有没有其他的操作了呢?有. 比如:比如鼠标右键点击.双击.移动鼠标到某个元素.鼠标拖拽等. 这些操作,可以通过Selenium提供的ActionChains类来实现. ActionChains类里面提供了一些特殊的动作的模拟,我们可以通过 ActionChains 类的代码查看到,如下所示: 我们以移动鼠标到某个元素为例. 百度首页的右上角,有个更多产品选项,如下图所示: 如果我们把鼠标放在上

C# windows服务启动winform程序不显示UI问题解决

由于工作需要写一个解决winform程序自动更新下载重启的自动更新程序,之前用控制台全部实现,然而换成windows  service出现了两个问题,一个是路径问题(http://baidu.com),一个是服务启动其他winform程序不显示UI问题. 本篇解决UI显示问题. 以下为引用尤尼博文(原文地址:http://www.cnblogs.com/luxilin/p/3347212.html): 我开发的系统中有一接口程序(这里就称Task,是一个C#的Console Applicatio

第十三篇 一个安装、管理windows服务的桌面程序

在网上看到一个修改程序入口的程序去把windows 服务修改成控制台的程序,然后利用控制台的程序把服务安装和管理,也想起自己原来也写了一个对windows 报务管理的程序,不过是winform的. 界面如下(自己使用,界面比较丑陋): 首先需要添加一个帮助类: 代码如下: class Windows { /// <summary> /// 检查服务存在的存在性 /// </summary> /// <param name=" NameService "&g