Windows系统服务的编写。
实验资源下载地址:点击打开链接
只是不知道能不能从服务向桌面进程传递消息,,就像两个桌面进程之间用Sendmessage似的。。希望有知道的大神可以指点一下。。不胜感激。。
因为微软在Vista之后,对系统服务进行了隔离,即服务层为会话0 层,,而登录用户为1,2.。。。层,,因此,,假设须要服务层与用户进行交互,,仅仅能绕过Session 0 层。。因此己不能进行复杂的UI操作。。
服务是整合在Microsoft Windows操作系统中的结构。服务与用户的应用程序不同,由于你能够对他们进行配置,不须要一个激活的用户登录,就能够使这些服务在系统启动的时候执行,直到系统关闭。Windows中的服务,负责全部种类的后台活动,但不包含从远程过程调用(RPC)服务到网络位置服务的用户。
一些服务可能会试图显示一些用户界面对话框,或者与用户的应用程序进行通信。那么这些服务将会遇到与Windows 7 的兼容性问题。可能你有一个服务,试图显示一个对话框,可是,可能不过在任务栏中出现一个闪烁的图标。无独有偶,你的服务可能会多多少少遇到以下的一些现象。这些服务:
• 正在执行,可是没有做他们本希望去做的事情
• 正在执行,可是其它的一些进程却不能和这个服务进行通信
• 试图通过窗口消息,与用户的应用程序进行通信,可是窗口消息并没有被目标所接收到
• 在任务栏中,显示一个闪烁的图标,说明此服务希望与桌面信息进行交互
这些是Windows 7的服务的Session 0隔离机制的一些症状。它们能够大致分为两大类:
• 服务显示用户界面失败,或者只显示了一个简化的用户界面
当一个服务试图去展示不论什么有关用户界面的元素(即使这个服务被同意与桌面信息进行交互),一个叫做Interactive services dialog detection的简单对话框也会弹出,用于提示用户。用户能够进入Session 0的安全桌面中查看服务的用户界面,可是,工作流中的干扰,使得这个变成了一个严重的应用程序兼容性问题。
• 非常难实现服务和应用程序共享对象,而且这个对象将不可见
当一个对象由服务创建出来,而且同意标准应用程序訪问(以标准用户权限执行),那么这个对象将不能在全局命名空间中找到(它将被Session 0 中私有)。此外,安全变更,也将保证即使对象是可见的,但它也是不能被訪问的。这些将有可能影响其它的与你的服务进行交互的进程(比方普通用户的应用程序)。
真正的问题是Windows 7 服务的Session 0 隔离机制
在Windows XP, Windows Server 2003或者更早期的Windows操作系统中,全部的服务和应用程序都是执行在与第一个登录到控制台的用户得Session中。这个Session叫做Session 0。在Session 0 中一起执行服务和用户应用程序,因为服务是以高权限执行的,所以会造成一些安全风险。这些因素使得一些恶意代理利用这点,来寻找提升他们自身权限的结构。
在Windows Vista中,服务在一个叫做Session 0 的特殊Session中承载。因为应用程序执行在用户登录到系统后所创建的Session 0 之后的Session中,所以应用程序和服务也就隔离开来:第一个登录的用户在Session 1中,第二个在Session 2中,以此类推。其实执行在不同的Session中,假设没有特别将其放入全局命名空间(而且设置了对应的訪问控制配置),是不能互相传递窗口消息,共享UI元素或者共享kernel对象。以下的图例中,将进行图解:
了解很多其它关于Session 0 隔离机制,阅读Windows Vista 中的驱动和服务的Session 0 隔离机制的影响:http://www.microsoft.com/whdc/system/vista/services.mspx
解决方式
• 假设一个服务,须要向用户传递一条消息,那么能够使用WTSSendMessage方法。这种方法和MessageBox基本同样。它将能够给不须要复杂的UI界面的服务,一个简单而有效的解决方式,同一时候,因为所显示的消息对话框不能用于控制底层的服务,所以,这个解决方式也是安全的。
• 假设须要使用一个复杂的UI界面,那么能够使用CreateProcessAsUser方法,在提出请求的用户桌面中创建一个进程。
• 假设这两种交互方式都须要,那么能够使用诸如Windows Communication Foundation (WCF),.NET远程处理,命名管道或者其它的进程间通信(IPC)结构(除窗口消息之外)来跨Session通信。
• 安全通信和其它共享对象(比方,命名管道,文件地图),能够使用随意訪问控制列表(DACL)来严格控制用户的权限设置。使用系统訪问控制列表(SACL),来确保中低权限的进程依旧能够訪问由系统或高权限服务所创建的结构。
• 确保跨Session訪问的kernel对象是以Global\字符串为首字母进行命名,这意味着他们是属于全局Session命名空间中的。
解决方式步骤
眼下,我们已经遇到了全部的Windows服务的Session 0 隔离机制的情况,解释了什么是服务隔离,它是怎样影响你的服务和应用程序的,而且提出了一些解决方式。以下的一些測试和一些操作,能够帮助你找到问题,而且解决它。
试验 #1
1. 打开进程浏览器。
a. 下载或了解很多其它关于进程浏览器,请在Microsoft TechNet站点參看Process Explorer Web site 。
2. 确保进程浏览器显示了全部的进程:
a. 点击 File.
b. 选择 Show processes from all users.
3. 定位到可疑的服务,而且查看它的属性:
a. 右键点击进程。
b. 选择 Properties 。
c. 导航到 Security 标签。
d. 请注意服务执行在哪个Session中(通常在Session 0),而且它的所有级别。
以下是两个进程的样例-当中一个以中级权限执行(在Session 1),另外一个则以系统权限执行(在Session 1):
假设你的服务是以高权限执行在Session 0中,那么它将不能直接显示UI。只是即使这样,当你与服务进行共享kernel对象或者文件的时候,你可能还会遇到一些问题。
试验 #2
1. 打开进程浏览器。
2. 确保进程浏览器显示了全部的进程:
a. 点击 File.
b. 选择 Show processes from all users.
3. 定位到可疑的服务。
4. 假设服务包括了你已知的与用户应用程序共享的对象,请在以下的Handles窗体中检查他们的句柄(使用CTRL+H查看,或者从View菜单中进入)。
a. 右键点击每个能够的句柄,选择Properties。
b. 切换到Security标签页,查看当前用户和组是否同意使用当前句柄来訪问对象。
以下的图中,展示了一个无论是否是在Session 0 中执行的系统服务中,全部人都能够訪问的共享对象(“同步”权限):
以下的图中,展示了一个仅仅同意管理员和系统组才干訪问的共享对象:
5. 假设服务须要创建一个用户应用程序能够訪问的文件,请按照下面步骤:
a. 打开命令行窗体:
i. 点击 Start
ii. 指向 Programs
iii. 点击 Accessories
iv. 点击 Command Prompt
b. 执行icacls工具查看文件或者文件夹的集合权限和DACL信息,而且改动它们。
(请在Microsoft TechNet站点查看关于icacls的文档,以获取很多其它信息。)
c. 执行icacls MyFile来显示叫MyFile的文件的訪问控制列表。
d. 执行icacls MyFile /setintegritylevel Medium来将MyFile的集合权限级别改动为中级(这将使它能够訪问大部分用户应用程序。)
工具
• 进程浏览器 –Windows进程的监视工具,能够显示进程的集合级别和对象的安全信息。
o 很多其它信息: http://technet.microsoft.com/en-us/sysinternals/bb896645.aspx
o 下载: http://download.sysinternals.com/Files/ProcessExplorer.zip
• icacls –Windows有用工具中的一个,用于更改文件系统对象的ACL和整合级别。
o 很多其它信息: http://technet.microsoft.com/en-us/library/cc753525.aspx
代码演示样例
以下包括了一些演示样例代码,用来演示怎样:
• 使用WTSSendMessage从服务端向当前活动用户的桌面发送消息
• 当须要显示一个相对复杂的UI界面时,怎样在当前活动用户的桌面创建一个进程
• 创建一个属于全局命名空间的事件,而且包括安全配置,以便于它能够被当前活动用户所訪问。
使用WTSSendMessage 从服务端向当前活动用户的桌面发送消息:
void ShowMessage(LPWSTR lpszMessage, LPWSTR lpszTitle)
{
DWORD dwSession = WTSGetActiveConsoleSessionId();
DWORD dwResponse = 0;
WTSSendMessage(WTS_CURRENT_SERVER_HANDLE, dwSession,
lpszTitle,
static_cast<DWORD>((wcslen(lpszTitle) + 1) * sizeof(wchar_t)),
lpszMessage,
static_cast<DWORD>((wcslen(lpszMessage) + 1) * sizeof(wchar_t)),
0, 0, &dwResponse, FALSE);
}
当须要显示一个相对复杂的UI 界面时,怎样在当前活动用户的桌面创建一个进程:
BOOL bSuccess = FALSE;
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
si.cb = sizeof(si);
DWORD dwSessionID = WTSGetActiveConsoleSessionId();
HANDLE hToken = NULL;
if (WTSQueryUserToken(dwSessionID, &hToken) == FALSE)
{
goto Cleanup;
}
HANDLE hDuplicatedToken = NULL;
if (DuplicateTokenEx(hToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification, TokenPrimary, &hDuplicatedToken) == FALSE)
{
goto Cleanup;
}
LPVOID lpEnvironment = NULL;
if (CreateEnvironmentBlock(&lpEnvironment, hDuplicatedToken, FALSE) == FALSE)
{
goto Cleanup;
}
WCHAR lpszClientPath[MAX_PATH];
if (GetModuleFileName(NULL, lpszClientPath, MAX_PATH) == 0)
{
goto Cleanup;
}
PathRemoveFileSpec(lpszClientPath);
wcscat_s(lpszClientPath, sizeof(lpszClientPath)/sizeof(WCHAR), L"\\TimeServiceClient.exe");
if (CreateProcessAsUser(hDuplicatedToken, lpszClientPath, NULL, NULL, NULL, FALSE,
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
lpEnvironment, NULL, &si, &pi) == FALSE)
{
goto Cleanup;
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
bSuccess = TRUE;
Cleanup:
if (!bSuccess)
{
ShowMessage(L"An error occurred while creating fancy client UI", L"Error");
}
if (hToken != NULL)
CloseHandle(hToken);
if (hDuplicatedToken != NULL)
CloseHandle(hDuplicatedToken);
if (lpEnvironment != NULL)
DestroyEnvironmentBlock(lpEnvironment);
创建一个属于全局命名空间的事件,而且包括安全配置,以便于它能够被当前活动用户所訪问(从DACL 和SACL ):
DWORD dwSessionID = WTSGetActiveConsoleSessionId();
HANDLE hToken = NULL;
if (WTSQueryUserToken(dwSessionID, &hToken) == FALSE)
{
goto Cleanup;
}
DWORD dwLength;
TOKEN_USER* account = NULL;
if (GetTokenInformation(hToken, TokenUser, NULL, 0,& dwLength) == FALSE &&
GetLastError() != ERROR_INSUFFICIENT_BUFFER)
{
goto Cleanup;
}
account = (TOKEN_USER*)new BYTE[dwLength];
if (GetTokenInformation(hToken, TokenUser, (LPVOID)account, dwLength, &dwLength) == FALSE)
{
goto Cleanup;
}
LPWSTR lpszSid = NULL;
if (ConvertSidToStringSid(account->User.Sid,& lpszSid) == FALSE)
{
goto Cleanup;
}
WCHAR sddl[1000];
wsprintf(sddl, L"O:SYG:BAD:(A;;GA;;;SY)(A;;GA;;;%s)S:(ML;;NW;;;ME)", lpszSid);
PSECURITY_DESCRIPTOR sd = NULL;
if (ConvertStringSecurityDescriptorToSecurityDescriptor(sddl, SDDL_REVISION_1,& sd, NULL) == FALSE)
{
goto Cleanup;
}
SECURITY_ATTRIBUTES sa;
sa.bInheritHandle = FALSE;
sa.lpSecurityDescriptor = sd;
sa.nLength = sizeof(sa);
g_hAlertEvent = CreateEvent(&sa, FALSE, FALSE, L"Global\\AlertServiceEvent");
if (g_hAlertEvent == NULL)
{
goto Cleanup;
}
while (!g_Stop)
{
Sleep(5000);
SetEvent(g_hAlertEvent);
}
Cleanup:
if (hToken != NULL)
CloseHandle(hToken);
if (account != NULL)
delete[] account;
if (lpszSid != NULL)
LocalFree(lpszSid);
if (sd != NULL)
LocalFree(sd);
if (g_hAlertEvent == NULL)
CloseHandle(g_hAlertEvent);
而相同的,,假设须要用共享内存进行与桌面的进程通信的话,,在创建共享内存过程中,也须要进行权限的设置。。代码例如以下。。
此为服务内建立共享内存
HANDLE hFileMap;
LPBYTE pcMap;
//PSECURITY_DESCRIPTOR securityDescriptorPointer1 = NULL;
//ServiceContext serviceContext1 = {0}; //serviceContext1.StatusHandle = RegisterServiceCtrlHandlerEx(argv[0], ControlHandlerEx, &serviceContext1);
//if (!serviceContext1.StatusHandle) {
// goto cleanup;
//} // if (!ConvertStringSecurityDescriptorToSecurityDescriptor(L"D:(A;;0x00000002;;;IU)(A;;GA;;;LS)", SDDL_REVISION_1, & securityDescriptorPointer1, NULL)) {
// goto cleanup;
// }
// SECURITY_ATTRIBUTES sa1 = {sizeof(SECURITY_ATTRIBUTES), securityDescriptorPointer1, FALSE};
// WriteToLog((char*)&sa1);
SECURITY_DESCRIPTOR secutityDese;
::InitializeSecurityDescriptor(&secutityDese, SECURITY_DESCRIPTOR_REVISION);
::SetSecurityDescriptorDacl(&secutityDese,TRUE,NULL,FALSE);
SECURITY_ATTRIBUTES securityAttr;
securityAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
securityAttr.bInheritHandle = FALSE;
securityAttr.lpSecurityDescriptor = &secutityDese;
// hMapping = CreateFileMappingW(INVALID_HANDLE_VALUE,&securityAttr,PAGE_READWRITE,0,0x100,L"Global\\z22"); hFileMap = CreateFileMapping(INVALID_HANDLE_VALUE,&securityAttr/*&sa1*/, PAGE_READWRITE, 0, 0x100, L"Global\\ShareData");
if(hFileMap == NULL)
{
WriteToLog("CreateFileMapping shibai");
return ;
}
// while(1)
// {
// WriteToLog("CreateFileMapping shibai");
//
// }
pcMap = (LPBYTE)MapViewOfFile(hFileMap, FILE_MAP_READ|FILE_MAP_WRITE,0, 0, 0);
if(pcMap == NULL)
{
WriteToLog("MapViewOfFile shibai");
return ;
}
int i = 0;
for(i = 0; i < len; i++)
{
pcMap[i] = IpaPath[i];
}
pcMap[i] = 0;
WriteToLog((char*)pcMap);
UnmapViewOfFile(pcMap); LPBYTE Get;
Get = (LPBYTE)MapViewOfFile(hFileMap,FILE_MAP_READ,0,0,0);
WriteToLog((char*)Get);
// CloseHandle(hFileMap); // delete []pChStr;
Windows系统服务的编写。的更多相关文章
- 将Tomcat加入windows系统服务
将Tomcat加入windows系统服务 将Tomcat加入服务 1.修改bin目录中的service.bat: REM 添加下面的一行 set CATALINA_HOME=%cd% 如果从来没有安装 ...
- MongoDB安装,启动,注册为windows系统服务
MongoDB安装与启动 周建旭 2014-08-10 解压完后配置环境变量 下载Windows 32-bit或64-bit版本并解压缩,程序文件都在bin目录中,其它两个目录分别是C++调用是的头文 ...
- VC Windows系统服务创建代码
Windows系统服务创建步骤,常用类封装,废话不多说,直接上代码 // ServceDemo.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" ...
- windows后台服务程序编写
Windows后台服务程序编写 1. 为什么要编写后台服务程序 工作中有一个程序需要写成后台服务的形式,摸索了一下,跟大家分享. 在windows操作系统中后台进程被称为 service. 服务是一种 ...
- 二、Windows 下 ShellCode 编写初步
第二章.Windows 下 ShellCode 编写初步 (一)shellcode 定义:最先的 Shell 指的是人机交互界面,ShellCode 是一组能完成我们想要的功能的机器代码,通常以十六进 ...
- windows服务的编写,手动安装与卸载
windows服务的编写 1.要添加的引用 using System.ServiceProcess; using System.ServiceModel ; using WcfServiceLibra ...
- C#开发奇技淫巧一:调试windows系统服务
原文:C#开发奇技淫巧一:调试windows系统服务 windows系统服务不能直接运行,只能在安装完服务之后启动.暂停.继续.停止服务,导致服务的调试不能使用一般的断点调试. 要调试系统服务,可以采 ...
- 把Jar包加入windows系统服务
之前在服务器上不一个Java服务时候,总是开着一堆黑框框,非常不雅,重点是极其容易误关,所以把可执行Jar文件加入Windows系统服务,看起来是个非常不错的选择!(实际上也确实是非常不错的选择) ! ...
- 将elasticsearch设置为windows系统服务
目前我都是在windows的环境下操作是Elasticsearch,并且喜欢使用命令行 启动时通过cmd直接在elasticsearch的bin目录下执行elasticsearch 这样直接启动的话集 ...
随机推荐
- [Ext JS 4] 实战Chart 协调控制(单一的坐标,两个坐标)
前言
- HDU ACM 1290 献给杭电五十周年校庆的礼物
解析: 1.n条直线把平面切割成的区域数为: f(n)=f(n-1)+n=n(n+1)/2+1; 2.把空间切割为最多区域数的时候,第n个平面与前(n-1)个平面相交.且无三面共线,因此该平面与前(n ...
- 超过lua上帝的语言
上帝的语言(god)它是基于lua和RPP新一代编程语言 为什么需要它? 1.好多人不喜欢lua语法,god的语法更像C 2.god支持元编程.闭包.协程 3.凡是lua支持的特性god也支持,lua ...
- Centos 7 学习加入用户
正在使用 Centos 许多人前使用Ubuntu,因此, useradd 和 adduser 两个命令歧义,于Ubuntu这是在系统上两个命令,于Centos在这同一个命令,adduser 在一个链接 ...
- 我的第一次windows规划
#include <windows.h> LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ; //WinMain功能被分配一 ...
- Python 实现类似PHP的strip_tags功能,并能够定义他们自己的一套保留标记
最近的研究 Python ,发现还是很习惯使用,多PHP这是非常easy该功能Python 这不得不找了半天,而且非常灵活不得不实现自己的. 我们今天聚集,需要过滤的内容标签,搞一个PM.外形似终于想 ...
- C#程序(含多个Dll)合并成一个Exe
把C#程序(含多个Dll)合并成一个Exe的超简单方法 开发程序的时候经常会引用一些第三方的DLL,然后编译生成的exe文件就不能脱离这些DLL独立运行了. 但是,很多时候我们本想开发一款只需要一 ...
- EasyARM i.mx287学习笔记——minicom配置和使用
0 前言 在windows中有非常多串口调试软件,比如putty. 而ubuntu中也有非常多串口调试软件,当中最简单有用的便是minicom了. 本文说明虚拟机中怎样使用minico ...
- 谈话ZooKeeper(一个)分析ZooKeeper的Quorums机制--预防Split-Brain问题
使用ZooKeeper学生们应该看到一个参数.它是ZooKeeper超过一半的群集必须节点(Majority)可用的.外来人才在整个集群中可用.在大多数情况下,这种说法是正确的. 谈论这篇文章背后的原 ...
- 打包静默安装参数(nsis,msi,InstallShield,InnoSetup)
原文:打包静默安装参数(nsis,msi,InstallShield,InnoSetup)[转] 有时我们在安装程序的时候,希望是静默安装的,不显示下一步下一步,这编访问来教大家如何来操作,现在常用的 ...