I、 摘要
II、 关于WIN2K的服务
III、 服务的启动和关闭基本过程
IV、 服务的编程
V、 关于服务的安全
VI、 服务的管理
VII、 结尾
I、 摘要
WIN NT下的服务就类似*NIX下面的守护进程一样,而且现在越来越多的软件开始设计成服务的形式,从XP推出之后,通过服务来实现多用户切换等就显得很有作用了。
从安全角度来看待WIN的服务的话,也就因此有很多的话题,比如运行的权限、运行的时间等等。
本文就从一些方面来介绍并谈谈WIN服务的一些东西,受水平限制,内容不精致。
II、 关于WIN2K的服务
WIN32服务由三部分组成:服务应用程序、服务控制程序(SCP)和服务控制管理器(SCM)。
一、服务控制管理器
服务控制管理器(Service Control Manager):在系统启动的时候开始,是WIN系统的一部分,它是一个远程过程调用(RPC)服务器。这也是WIN服务系统的核心。
SCM主要负责下面的东西:
?维护安装的服务数据库
?在系统启动或者有命令的时候开始服务和驱动服务
?枚举安装的服务和驱动
?维护运行着的服务和驱动的状态
?传输控制请求去运行服务
?锁定和解锁服务数据库
SCM维护着注册表中的服务数据库,位于:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services。其下的子键就是安装的服务和驱动服务。每个子键的名称就是服务名,当安装的时候由服务安全程序的 CreateService 函数指定。
当系统安装的时候,最初的数据库就被创建。这个数据库包含系统启动时候的设备驱动。数据库中的每个服务和驱动的信息包括:
?服务类型。服务执行时候是自己的进行还是同其他服务共享进行,是否是核心驱动还是文件系统驱动。
?启动类型。服务或者驱动服务是否是在系统启动的时候自动启动还是,是否是由SCM来接受控制请求来启动。启动类型也表明服务是否被禁止。
?错误控制等级。指明如果服务或者驱动服务启动失败的错误处理。
?执行文件的全路径。
?附加依赖信息决定启动的正确顺序。对于服务,这个信息包括在服务启动之前SCM需要先启动的指定服务,服务所属加载顺序组的名称,服务在组中启动顺序的标志符。对于驱动服务,这个信息包括驱动启动前需要启动的指定驱动。
?对于服务,还有附加的帐号名称和密码。如果没有指定帐号,服务就使用LocalSystem帐号。
?对于驱动,附加驱动对象名称,用于I/0系统加载设备驱动。如果没有指明对象名,I/O系统在驱动服务名称基础上创建一个默认的名称。
二、服务控制程序
服务控制程序(SCP)则是控制服务应用程序的功能块,也是服务应用程序同服务管理器(SCM)之间的桥梁。服务控制程序可以完成这些动作:
?如果服务启动类型为SERVICE_DEMAND_START,那么服务控制程序来启动服务
?发送控制请求给运行着的服务
?查询运行着的服务的当前状态
这些动作要求打开一个服务对象的句柄。
?服务启动
要启动一个服务,服务控制程序使用StartService 函数。如果数据库被锁定,那么StartService函数会失败。如果遇到这种情况,那么服务控制程序需要等待,并重新调用StartService。可以通过QueryServiceLockStatus来查询服务数据库的状态。
当服务控制程序开始一个服务的时候,可以通过StartService函数来指定传递给服务ServiceMain 函数的参数。当创建一个新的线程去执行ServiceMain后,StartService就返回了。服务控制程序可以通过QueryServiceStatus 函数来查询被启动的服务的状态。在SERVICE_STATUS结构初始化中dwCurrentState应该是SERVICE_START_PENDING,而dwWaitHint则是一个毫秒的时间间隔,表示服务控制程序在调用QueryServiceStatus应该等待的时间。当初始化完成,服务就会改变服务的状态dwCurrentState 为SERVICE_RUNNING。
如果服务在80秒,再加上最后的等待时间内没有改变它的状态,服务控制管理器确定服务已经停止响应,会记录事件并停止服务。
如果程序在启动驱动服务,StartService会在设备驱动初始化完成后返回。
?服务控制请求
服务控制程序通过ControlService来发送一个控制请求给运行着的服务。这个函数指定控制值传递给指定服务的HandlerEx 函数。这个控制值可以是用户自定义码,也可以是下面这些基本控制码:
?停止服务:SERVICE_CONTROL_STOP
?暂停服务:SERVICE_CONTROL_PAUSE
?恢复被暂停的服务:SERVICE_CONTROL_CONTINUE
?返回服务的更新状态信息:SERVICE_CONTROL_INTERROGATE
每个服务可以指定它接收和处理的控制值。要确定哪个基本控制值被服务接收,可以使用QueryServiceStatus 函数或者指定SERVICE_CONTROL_INTERROGATE 来调用ControlService 函数。SERVICE_STATUS结构中的dwControlsAccepted返回的是是否服务能被停止、暂停和恢复。所有的服务都能接收SERVICE_CONTROL_INTERROGATE。
QueryServiceStatus函数返回指定服务的最近状态,而不会获得服务本身更新的状态。使用
SERVICE_CONTROL_INTERROGATE控制来调用ControlService函数可以确定状态是否是当前的信息。
三、服务应用程序
服务应用程序是一个服务的主体程序,它是一个或者多个服务的可执行代码。这将在服务的编程中详细解释。
III、 服务的启动和关闭的基本过程
当系统启动的时候,SCM会启动所有自动启动的服务以及这些服务依赖的服务。如果一个自动启动的服务所依赖的服务是“手动”(需要命令才启动)的服务,那么这个服务也会被自动启动。服务的加载顺序由下面这些方面来决定:
1.组的顺序
2.一个组中服务的加载顺序
3.每个服务所依赖的服务
当启动完成的时候,系统执行启动确认程序(由注册表的HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control
中的BootVerificationProgram值指定,默认情况下,这个值是没有的。)。当第一个用户登录后,系统会简单地报告启动成功。可以单独提供一个启动确认程序来检查系统问题和报告启动状态给SCM,使用 NotifyBootConfigStatus 函数。
当系统成功启动后,系统就克隆保存一份数据库备份,作为last-known-good(LKG)配置。如果当前使用的数据库导致系统启动失败,那么可以用备份来恢复。备份的数据库就保存在:
HKEY_LOCAL_MACHINE\SYSTEM\ControlSetXXX\Services 中。
其中XXX值也被保存在:
HKEY_LOCAL_MACHINE\System\Select\LastKnownGood 中。
如果自动启动的服务自动的时候得出SERVICE_ERROR_CRITICAL错误,SCM就会重新启动机器,并使用LKG的配置,如果LKG的配置已经被使用了,启动就会失败。
注册表中服务的ErrorControl值表示SCM如何处理服务错误。如果值为SERVICE_ERROR_IGNORE(0)或者没有指定,SCM只忽略错误并继续服务的启动,如果为SERIVCE_ERROR_NORMAL(1),就在事件日志中记录下错误原因。如果错误控制为SERIVCE_ERROR_SEVERE(2)或者SERIVCE_ERROR_CRITICAL(3),服务就报告启动错误。SCM记录事件日志,并调用函数ScreverToLastKnownGood,将系统注册配置切换到LKG的版本,然后调用NtShutDownSystem重新启动系统。如果系统已经使用LKG版本,就直接重新启动。
LKG版本的产生:SCM在系统启动阶段启动了所有自起服务之后,需要来决定这个LKG配置。缺省情况下,一次成功的启动包括所有服务的成功启动和一个用户的登录。如果在启动服务阶段存在服务的SERIVCE_ERROR_SEVERE(2)或者SERIVCE_ERROR_CRITICAL(3)错误,那么这就是失败的启动。如果SCM成功完成服务的启动,当有用户登录的时候,Winlogon调用NotifyBootConfigStatus函数发送消息给SCM。在成功启动所有服务,并且收到NotifyBootConfigStatus的登录信息,SCM就调用NtInitializeRegistry保存当前的启动配置信息。
第三方可以用自己的定义取代Winlogon的确认,这可以由注册表中:
KHLM\SYSTEM\CurrentControlSet\Control\BootVerificationProgam中的程序确定,可通过此加入对系统成功启动的定义。启动验证程序则通过设定HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\ReportBootOK为0禁止Winlogon对NotifyBootConfigStatus的调用。这样,SCM启动完服务后,等待这个验证程序调用NotifyBootConfigStatus函数通知登录成功,然后才保存LKG配置。
SCM的执行文件是:WINN\System32\Service.exe,以控制台模式运行,Winlogon进程在系统启动早期启动SCM。
SvcCtrlMain在紧接着屏幕变为空白时刻运行,在Winlogon加载图形化身份鉴定并显示登录界面GINA之前运行。
SvcCtrlMain首先创建一个nonsignaled初始化的名为SvcCtrlEvent_A3752DX的同步事件,在完成准备接受SCP的命令的各项步骤之后,SCM才设定此事件为signaled状态。SCP通过OpenSCManager函数来确认SCM,这个函数通过等待SvcCtrlEvent_A3752DX为signaled来防止SCP在SCM初始化完成之前接触SCM。
SvcCtrlMain然后调用ScCreateServiceDB函数,建立SCM的服务数据库。它先读取注册表中:
HKLM\system\CurrentControlSet\Control\ServicegroupOrder\list内容,列出服务组名称和它们的启动顺序,然后再搜索HKLM\SYSTEM\currentControlSet\Services的内容,为每一条主键在服务的数据库中创建一个条目。SCM本身属于自起服务和设备驱动,并且标记为引导启动和系统启动驱动的启动错误,也就是,所有标记为引导驱动