服务程序调试(第41课)

windows服务是由三个组件构成的:服务应用,服务控制程序SCP,以及服务控制管理器SCM,当SCM启动一个服务进程时,该进程必须立即调用StartServiceCtrlDispatcher函数。StartServiceCtrlDispatcher函数接受一个入口点列表,每个入口点对应于该进程中的一个服务。

 

一、服务简介

windows服务是由三个组件构成的:服务应用,服务控制程序SCP,以及服务控制管理器SCM,当SCM启动一个服务进程时,该进程必须立即调用StartServiceCtrlDispatcher函数。StartServiceCtrlDispatcher函数接受一个入口点列表,每个入口点对应于该进程中的一个服务。每个入口点是由它所对应的服务的名称来标识的。StartServiceCtrlDispatcher创建了一个命名管道来跟SCM进行通信,在建立了该通信管道以后,它等待SCM通过该管道发送过来的命令。每次SCM启动一个属于该进程的服务时,它发送一个“服务启动”命令。StartServiceCtrlDispatcher函数对于所接收到的每个启动命令,创建一个线程(服务线程),由该线程调用所启动服务的入口点函数,并实现该服务的命令循环。StartServiceCtrlDispatcher一直在等待来自SCM的命令,只有当该进程的所有服务都停止时,它才会将控制返回至该进程的main函数,以便服务进程在退出以前做一些资源清理工作。

 

当SCM要启动一个服务时,它就调用ScStartService,当ScStartService启动一个windows服务时,它首先读取该服务的注册表键中ImagePath值,以确定该服务进程的映像文件名。然后,它检查该服务的Type值,如果此值是SERVICE_WINDOWS_SHARE_PROCESS(0x20)那么,SCM保证该服务运行所在的进程(如果已经启动了的话),其登录的账户一定与服务的指定启动账户相同。

 

SCM在一个称为映像数据库的内部数据库中,检查是否有针对该服务的ImagePath值的条目,以便验证该服务的进程尚未在其他账户下被启动起来。如果在映像数据库中没有找到该ImagePath值的条目,则SCM创建一个这样的条目。当SCM创建一个新的条目时,它还将该账户的登录账户名,以及该服务的ImagePath值中的数据也存储起来。如果SCM在映像数据库中找到了一个与该服务的ImagePath数据相匹配的条目,那么,必须保证当前正在启动的服务的用户账户信息与数据库条目中存储的信息是相同的。一个进程只能以一个账户的身份来登录,所以,当一个服务指定的账户名与同一个进程中已经启动起来的其他服务的账户名不相同时,SCM会报告一个错误。

 

SCM调用ScLogonAndStartImage来登录一个服务,并启动该服务的进程。SCM通过调用lsass函数LogonUserEx来登录那些并非运行在系统账户下的服务。

 

当SCM配置一个服务的登录信息时,SCM利用LsaStorePrivateData函数来指示lsass将一个登录口令保存到Secrets子键下。在登陆成功后,LogonUserEx给调用者返回一个句柄,指向一个访问令牌。Windows使用 访问令牌来代表一个用户的安全环境,以后SCM将该访问令牌与实现此服务的进程关联起来。

 

下一个步骤是,如果该服务的进程尚未被启动(例如,为了另一个服务),则SclogonAndStartImage为该服务激发一个进程。SCM通过windows函数CreateProdcessAsUser来启动此进程,并且将该进程的状态设置为挂起状态。接下来SCM创建一个命名管道,以后通过该管道与服务进程进行通信,分配给管道的名称为\Pipe\Net\NtControlPipeX,其中X是一个数字,每次SCM创建一个管道,该数字就会递增。然后,SCM通过ResumeThread函数来恢复服务进程的执行,并且等待该服务连接到它的SCM管道上。如果注册表值HKLM\SYSTEM\CurrentControlSet\Control\ServicesPipeTimeout存在的话,则它决定了SCM等待又给服务调用StartServiceCtrlDispatcher并连接过来的时间长度,如果在这么长时间里没有等到,则SCM就会放弃,终止该进程,并得出结论:该服务未能启动。如果ServicesPipeTimeout不存在,则SCM使用默认的30秒作为超时间隔值。SCM对于它所有的服务通信都是用同样的超时间隔值。

 

当一个服务通过它的管道连接到SCM时,SCM向该服务发送一个启动命令。如果该服务未能在有效时间内响应启动命令,SCM就会放弃,转移到启动下一个服务。当一个服务没有对启动请求做出响应时,SCM不会像一个服务在指定时间内没有调用StartServiceCtrlDispatcher的情形一样终止进程,相反会在系统的时间日志中记录一个错误,指明该服务未能及时启动起来。

 

如果SCM调用ScStartService启动的服务有一个Type注册表值为SERVICE_KERNEL_DRIVER或SERVICE_FILE_SYSTEM_DRIVER,那么该服务是一个设备驱动程序,所以ScStartService调用ScLoadDeviceDriver来加载该驱动程序。ScLoadDeviceDriver首先使SCM进程具有加载驱动程序的安全特权,然后调用内核服务NtLoadDriver,将该驱动程序的注册表键中的ImagePath值的数据传递过去。与windows服务不同的是,驱动程序不需要指定ImagePath值;如果该值不存在的话,SCM通过将驱动程序的名称附加在字符串%SystemRoot%\System32\Drivers\的后面就可以构造一个映像文件路径。

 

ScAutostartServices继续循环处理同一个组的服务,直到所有这些服务要么被启动起来,要么产生相依性错误。这种循环处理方式是SCM根据一个组中的服务的DependOnService相依性来自动对他们进行顺序处理的。SCM在较早的循环中启动那些被其他服务依赖的服务,跳过那些依赖于其他服务的服务,而在后续的循环中再启动这些服务。

 

SCM在处理了自动启动的服务以后,调用ScInitDelayStart,该函数将一个延迟的工作项目加入队列中,该工作项目与一个专门的辅助线程相关联,它负责处理所有由于被标记为“延迟的自动启动”而被ScAutoStartServices忽略掉的服务。此辅助线程将在一段时间的延迟之后执行,默认的延迟是120秒,但那时可以通过在HTML\SYSTEM\CurrentControlSet\Control中创建一个AutoStartDelay值,可以覆盖这一默认值。

 

当SCM完成了启动所有这些自动启动的服务和驱动程序,以及设置了延迟的自动启动的工作项目时,发信号通过\BaseNameObjects\SC_AutostartComplete事件完成。这一事件被windows setup程序用于在安装过程中衡量启动过程。

 

有些恶意样本会通过创建系统服务来执行自身的恶意功能,通过这种方法可以实现开机启动,也可以达到隐藏自身的目的,对于安全人员来说,调试服务程序也比较麻烦,这里介绍两种调试的方法。

 

二、服务启动后附加

通过任务管理器找到要调试的服务程序,查看目标进程的pid,然后再启动windbg,选择file->Attach to a Process;

file->Attach to a Process

 

在显示的进程列表中找到目标程序,然后点击OK即可开始调试。(关于此工具的详细使用方法,请参考动态调试工具篇介绍)。windbg

 

三、服务启动时附加

在服务启动的时候就使用windbg进行附加,使用这种方法需要进行简单的配置。

 

1、使用管理员启动windbg目录下的exe,在“Image File”标签页中填写Image名字(不需要写全路径)。如下图所示,服务名称是010editorAS,可执行路径为C:\Users\xxxxx\AppData\Roaming\010editorAS.exe。010editorAS

 

按照上图的例子,在Image框中填写010editorAS.exe,在下面的Debugger框中填写windbg的全路径。windbg

 

2、设置服务的属性,允许服务以交互形式启动。

允许服务以交互形式启动

 

3、设置结束后,就可以启动服务了,系统会显示交互式服务检测,点击查看消息后,便会中断在windbg中。windbg

 

但是这种方法有个问题,就是只能断下来30秒,过了这个时间就无法进行调试了。上文中提到了这个问题,查找网上的资料说,在注册表HKLM\SYSTEM\CurrentControlSet\Control下新建一个值ServicesPipeTimeout,这个值表示超时时间,但是经过实践发现并没有什么效果。

 

另外一种方法是在服务的入口加int3断点,这样就能在超时间隔内使程序执行完StartServiceCtrlDispatcher函数,不至于使服务管理器因为长时间收不到来自服务的消息而终止服务的运行。

头像
  • ¥ 1999.0元
  • 市场价:2999.0元
  • ¥ 58元
  • 市场价:58元
  • ¥ 298.0元
  • 市场价:498.0元
  • ¥ 59.8元
  • 市场价:99.8元

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: