0x服务简介
我们在进行一些程序分析时会发现有些程序会调用服务控制管理器,用服务的形式运行了一段代码,这就是常见的创建服务程序。
它的核心原理就是首先在SCM(Service Control Manager)下创建一个子进程,让这个子进程执行我们第三方程序提供的代码。
其中涉及的API有三个:StartService()
、StartServiceCtrlDispatcher()
、SetServiceStatus()
1)服务控制器用StartService()函数,是用SCM创建一个SCM下的子进程,并且执行这个子进程EP
2)服务进程调用StartServiceCtrlDispatcher()函数用于注册服务进程函数,使用这个函数前必须调用服务控制器API接口返回的控制句柄才能操作
3)服务进程调用SetServiceStatus()函数,虽然已经创建了服务进程,但尚未以服务形式运行。当前状态仍未SERVICE_START_PENDING。在主函数SvcMain被SCM调用后,通过SvcMain()内部的SetServiceStatus()函数调用过后,这样才能以服务进程形式运行。
0x1 强制EIP调试
对于DLL文件形式的Windows服务,服务主函数(默认为ServiceMain)为导出函数,SCM会调用运行导出函数,所以不需要另外调用StartServiceCtrlDispatcher
反汇编窗口跟随,查看是否是可执行的汇编代码
设置新EIP,这样除了EIP外,其他寄存器都保持原值不变
然后开始调试ScvMain即可。但是这种方式由于不是SCM正常启动的,所以在调用相关部分API可能发生异常。为了避免这种异常可以在调试器中强制设置EIP跳过对相关API调用。也可以设置内存访问异常忽略,如下图。但是这种设置仍然有可能崩溃,毕竟是强制跳转过来的。
0x2 正常附加调试
启动服务后,SCM会在一定时间内等待服务状态改变乘STATUS_RUNNING。若规定时间内服务状态未改变(默认30s),SCM就会引发ERROR_SERVICE_REQUEST_TIMEOUT错误,然后中止相关进程。
因为正常调试的情况下,目标服务进程是由SCM服务创建出来的子服务进程。我们需要先附加到SCM进程中,然后将要调试目标程序代码的EP处改成死循环,让SCM一直等待服务子进程执行,这时候我们再重新更改附加对象到目标服务进程中,恢复原来的EP代码,让目标服务可以正常跑下去。不这么做,一下子目标服务就可能跑完了,还没等附加,子进程服务就结束了。
以下是步骤:
1)首先安装示例程序,切换到示例程序下执行安装命令,注意这里是DebugMe1.exe中的主函数有接收install字符串处理,当接收到这个字符串后调用InstallService()
函数才能进行安装的。如果要调试的源码中没有提供这个安装方法,就需要自己写程序安装驱动或用强制EIP了。
打开服务管理查看是否安装服务成功
2)增加服务启动超时时间
启动注册表编辑器regedit.exe
,创建ServicesPipeTimeout注册表项。ServicesPipeTimeout会对所有服务都产生影响。[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Controll] ServicesPipeTimeout
新建一个DWORD值
3)覆盖写入循环
首先拿PE解析工具找到入口点在文件中的偏移。
用16进制编辑器修改此处机器码为0xEB 0xFE
4)启动服务
启动成功后,服务进程也就运行起来了(DebugMe1.exe)
使用Process Explorer查看SvcTest服务进程,服务被启动
注意:这里会弹出没有响应启动或控制请求,一定要重启这就是没重启后导致的错误
附加到对应的服务上后,该程序就是
修改回原值
接着在要调试的地方下断点就可以了,因为是SCM下子进程DebugMe1.exe创建的,所以ScvMain会被SCM调用。
然后就可以重新设置EIP为目标代码起始位置了,普通调试是在SCM下的子进程创建的,所以服务控制器会调用ScvMain中的代码。