summary one
windows services 的操作核心包括:
1. 注册服务 createService
2. 启动服务 startService
3. 停止服务 ControlService(...,SERVICE_CONTROL_STOP,....)
4. 注销服务 deleteService
只有注册了服务,系统中才能够查看到服务。注册后的服务,无论是否停止、运行、暂停,都会在services中显示。也就是说,关闭服务,需要注销服务。
平时用到的services.msc查看到的都是
SERVICE_WIN32
类型的服务,看不到SERVICE_DRIVER
驱动型的服务。枚举服务不能显示全部服务,必须在win32服务和驱动服务中做出单一选择。
ControlService函数不包括所有的控制,比如没有
宏SERVICE_CONTROL_START
用来启动服务对服务的操作(枚举,创建,停止,启动)都必须先获得SC控制管理器的句柄,删除服务操作是唯一例外。
注意的基本点
shown in WinNT.h
win32型服务宏定义
#define SERVICE_WIN32 (SERVICE_WIN32_OWN_PROCESS | \
SERVICE_WIN32_SHARE_PROCESS)
驱动型服务宏定义
#define SERVICE_DRIVER (SERVICE_KERNEL_DRIVER | \
SERVICE_FILE_SYSTEM_DRIVER | \
SERVICE_RECOGNIZER_DRIVER)
枚举服务时用到的数据结构 shown in WinSvc.h
//
// Service Status Structures
//
typedef struct _SERVICE_STATUS {
DWORD dwServiceType; ****
DWORD dwCurrentState; ****
DWORD dwControlsAccepted;
DWORD dwWin32ExitCode;
DWORD dwServiceSpecificExitCode;
DWORD dwCheckPoint;
DWORD dwWaitHint;
} SERVICE_STATUS, *LPSERVICE_STATUS;
//
// Service Status Enumeration Structure
//
// ENUM_SERVICE_STATUS
typedef struct _ENUM_SERVICE_STATUSW {
LPWSTR lpServiceName; ***
LPWSTR lpDisplayName; ***
SERVICE_STATUS ServiceStatus; ***
} ENUM_SERVICE_STATUSW, *LPENUM_SERVICE_STATUSW;
#ifdef UNICODE
typedef ENUM_SERVICE_STATUSW ENUM_SERVICE_STATUS;
常见错误(通过GetLastError()获得) shown in WinError.h
//
// MessageId: ERROR_INSUFFICIENT_BUFFER
//
// MessageText:
//
// The data area passed to a system call is too small.
//
#define ERROR_INSUFFICIENT_BUFFER 122L // dderror
//
// MessageId: ERROR_SERVICE_EXISTS
//
// MessageText:
//
// The specified service already exists.
//
#define ERROR_SERVICE_EXISTS 1073L
demo
VS2008sp1 ON XPx86 SP3
Windows Console Application
Debug Beta
// EnumService.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <windows.h>
/*
* type: SERVICE_WIN32 xor SERVICE_DRIVER ONLY ONE.
*/
VOID EnumService(DWORD type)
{
SC_HANDLE hscm = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (hscm == NULL)
{
printf("OpenSC Manager error! \n");
exit(1);
}
//DWORD dwBufSize =68;
DWORD dwBufSize =sizeof(ENUM_SERVICE_STATUS)*512;
DWORD dwByteNeeded,dwServiceReturned,lpResumeHandle= NULL;
// ENUM_SERVICE_STATUS SerStatus[6] ={0};
ENUM_SERVICE_STATUS SerStatus[512] ={0};
BOOL bRet = EnumServicesStatus(hscm,type,SERVICE_STATE_ALL,SerStatus,\
dwBufSize,&dwByteNeeded,&dwServiceReturned,&lpResumeHandle);
if (FALSE == bRet)
{
printf("EnumService error!\n");
printf("Find Serices count:%d\t",dwServiceReturned);
printf("Need Buffer_length: %d\n",dwByteNeeded/sizeof(ENUM_SERVICE_STATUS));
}
//ERROR_INSUFFICIENT_BUFFER
for (DWORD i = 0 ; i <dwServiceReturned ; i++)
{
if (wcscmp(SerStatus[i].lpServiceName,L"helloworld"))
{
continue;
}
printf("%i ",i);
printf("%S ",SerStatus[i].lpServiceName);
printf("%S",SerStatus[i].lpDisplayName);
switch (SerStatus[i].ServiceStatus.dwCurrentState)
{
case SERVICE_PAUSED:
printf(" paused!\n");
break;
case SERVICE_STOPPED:
printf(" stopped!\n");
break;
case SERVICE_RUNNING:
printf(" running!\n");
break;
default:
printf("Status: %08x",SerStatus[i].ServiceStatus.dwCurrentState);
}
}
CloseServiceHandle(hscm);
}
BOOL StopService(LPWCH stop_name)
{
SERVICE_STATUS ServiceStatus;
SC_HANDLE hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
printf("Open SCManager Error!");
exit(1);
}
SC_HANDLE hSCService = OpenService(hSCM,stop_name,SERVICE_ALL_ACCESS);
BOOL bRet = ControlService(hSCService,SERVICE_CONTROL_STOP,&ServiceStatus);
CloseServiceHandle(hSCService);
CloseServiceHandle(hSCM);
if (bRet ==TRUE)
{
return TRUE;
}
return FALSE;
}
BOOL myStartService(LPWCH start_name)
{
SERVICE_STATUS ServiceStatus;
SC_HANDLE hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
printf("Open SCManager Error!");
exit(1);
}
SC_HANDLE hSCService = OpenService(hSCM,start_name,SERVICE_ALL_ACCESS);
BOOL bRet = StartService(hSCService,NULL,NULL);
CloseServiceHandle(hSCM);
CloseServiceHandle(hSCService);
if (bRet == TRUE)
{
return TRUE;
}
return FALSE;
}
SC_HANDLE RegisterService()
{
// FROM MSDN
// SC_HANDLE WINAPI CreateService(
// _In_ SC_HANDLE hSCManager, //SHOULD OpenSCManager already.
// _In_ LPCTSTR lpServiceName,
// _In_opt_ LPCTSTR lpDisplayName,
// _In_ DWORD dwDesiredAccess,
// _In_ DWORD dwServiceType, //kernel? or win32?
// _In_ DWORD dwStartType, // how to start
// _In_ DWORD dwErrorControl,
// _In_opt_ LPCTSTR lpBinaryPathName, ****//可作为恶意代码检测点,即服务文件的位置
// _In_opt_ LPCTSTR lpLoadOrderGroup,
// _Out_opt_ LPDWORD lpdwTagId,
// _In_opt_ LPCTSTR lpDependencies,
// _In_opt_ LPCTSTR lpServiceStartName,
// _In_opt_ LPCTSTR lpPassword
// );
SERVICE_STATUS ServiceStatus;
SC_HANDLE hSCM = OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);
if (hSCM == NULL)
{
printf("Open SCManager Error!");
exit(1);
}
LPCTSTR lpServiceName = L"helloworld";
LPCTSTR lpDisplayName = L"bingo";
//DWORD dwDesiredAccess = SC_MANAGER_ALL_ACCESS ;
DWORD dwDesiredAccess = SERVICE_ALL_ACCESS ;
DWORD dwServiceType = SERVICE_KERNEL_DRIVER;
DWORD dwStartType = SERVICE_DEMAND_START;
DWORD dwErrorControl =SERVICE_ERROR_NORMAL;
LPCTSTR lpBinaryPathName = L"C:\\drivers\\objchk_wxp_x86\\i386\\helloworld.sys";
LPCTSTR lpLoadOrderGroup = NULL;
LPDWORD lpdwTagId =NULL;
LPCTSTR lpDependencies = NULL;
LPCTSTR lpServiceStartName =NULL;
LPCTSTR lpPassword = NULL;
SC_HANDLE bRet = CreateService(hSCM,lpServiceName,lpDisplayName,dwDesiredAccess,\
dwServiceType,dwStartType,\
dwErrorControl,lpBinaryPathName,lpLoadOrderGroup,lpdwTagId,\
lpDependencies,lpServiceStartName,lpPassword);
CloseServiceHandle(hSCM);
if (bRet!=NULL)
{
return bRet;
}
printf("%d",GetLastError());
return NULL;
}
BOOL unRegisterService(SC_HANDLE handle)
{
int Bret= DeleteService(handle);
printf("result:%d\n",Bret);
return TRUE;
}
int _tmain(int argc, _TCHAR* argv[])
{
//EnumService(SERVICE_KERNEL_DRIVER);
LPWCH stop_name=L"helloworld";
//StopService(stop_name);
//EnumService(SERVICE_KERNEL_DRIVER);
//myStartService(stop_name);
//EnumService(SERVICE_KERNEL_DRIVER);
//RegisterService();
printf("EnumServices:\n");
EnumService(SERVICE_KERNEL_DRIVER);
printf("after createsevice:\n");
SC_HANDLE create_handle=RegisterService();
EnumService(SERVICE_KERNEL_DRIVER);
myStartService(stop_name);
printf("after startservice:\n");
EnumService(SERVICE_KERNEL_DRIVER);
StopService(stop_name);
printf("after stopservice:\n");
EnumService(SERVICE_KERNEL_DRIVER);
printf("after deleteservice:\n");
unRegisterService(create_handle);
CloseServiceHandle(create_handle); //if delete,what happend?
EnumService(SERVICE_KERNEL_DRIVER);
return 0;
}
输出
C:\VC6\MyProjects\EnumService\Debug>EnumService.exe
EnumServices: **未注册
after createsevice: **注册,还未启动
172 helloworld bingo stopped!
after startservice: **启动
172 helloworld bingo running!
after stopservice: **停止
172 helloworld bingo stopped!
after deleteservice: **注销
result:1 **NONULL表示成功注销,此时SCManager已经无法得到该服务
summary two
枚举服务:
1.OpenSCManager
,获得服务管理器句柄,2.EnumServiceStatus
注册服务:1.OpenSCManager,2.CreateService
。注册服务是最麻烦的,如同CreateProcess
一般,因为要注册的消息参数非常多。
启动服务:1.OpenSCManager,2,OpenService(service_name)
,获得服务句柄。3,Startservice
(该服务必须已注册)
停止服务:1.OpenSCManager,2.OpenService(service_name),3ControlService.
(同样要求已注册且已启动)
注销服务:必须有该服务句柄,然后deleteService
可以看到,基本上都需要与服务管理器交互获得服务管理器句柄,并且很多情况下需要通过服务名获得服务句柄,然后再执行操作。
CreateService
根据参数不同而确定服务是否已经启动,因此不能说创建服务
,则服务已经启动。
记住要关闭句柄,否则会出现很多异常。比如最后注销服务的时候,如果不关闭句柄,根据MSDN提示,则该服务还没有从SCM中移除。已测试。
在枚举服务的时候有很有意思的事情出现:
//DWORD dwBufSize =68; //68= sizeof(ENUM_SERVICE_STATUS)+sizeof(L'the first service_name')*2
DWORD dwBufSize =sizeof(ENUM_SERVICE_STATUS)*512;
DWORD dwByteNeeded,dwServiceReturned,lpResumeHandle= NULL;
// ENUM_SERVICE_STATUS SerStatus[6] ={0}; //will show only one service if dwBufSize = 68
//与第一条服务字符串名长度有关,请自行调整
ENUM_SERVICE_STATUS SerStatus[512] ={0};
上述代码中dwBufSize
定义了缓冲区长度,这个缓冲区用来存放Service_name和Display_name
,因此需要非常大的缓冲区,如果较小,则接收失败。在官方文档中有提及到,为了确定长度,官方给了dwByteNeeded
,用于返回若全部服务返回时,还需要将dwBufSize
扩充的大小 ,dwServiceReturned
记录了返回的服务个数。从内存调试中可以得知,缓冲区同样从SerStatus
的地址开始,大小为dwBufSize
。枚举到的服务名从&SerStatus+dwBufSize
处往低地址处填充。因此可以通过增大SerStatus
的大小,同时将dwBufSize
改写成数组大小*sizeof(enum_service_status)(使用这个结构体,有利于查找buf位置)
来提供更大的缓冲区。假如真的系统有512个服务,那么SerStatus
的数组一定要远远大于512个,因为其尾部都会被缓冲区给填充。至于多大,感觉自己算的还是不够精细。假如太小,很容易出异常,今天还以为是自己找到0day了,结果半天发现微软已经记录了此异常.T_T.
其他
1.微软已经提供了SC命令
来查看服务信息,比services.msc
好的是,这里可以看到的不止是service_win32
类型,而且更加详细。
C:\VC6\MyProjects\EnumService\Debug>sc qc "helloworld"
[SC] GetServiceConfig SUCCESS
SERVICE_NAME: helloworld
TYPE : 1 KERNEL_DRIVER
START_TYPE : 3 DEMAND_START
ERROR_CONTROL : 1 NORMAL
BINARY_PATH_NAME : \??\C:\drivers\objchk_wxp_x86\i386\helloworld.sys
LOAD_ORDER_GROUP :
TAG : 0
DISPLAY_NAME : helloworld
DEPENDENCIES :
SERVICE_START_NAME :
//这个参数很重要,查了下表示以谁的身份启动的此服务(the name of the account under which the service should run.)
2.前几天在看rootkit
,用到了OSR的Driver Loader
。效果如图所示。
今天做完这个实验后,发现其实做的就是我们之前做的这些。
希望在恶意代码分析上可以用到今天的这些知识,下次打算把dll
用服务方式打开,加上boot
启动类型,实现高级注入。
–update2 5.13/2015
CreateService函数创建一个服务对象并将其安装在SCM数据库中,同时在注册表以下位置中创建同名键值:[HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services]
此项会随系统自动启动。就说嘛,create了一次之后忘了没有delete,那么下次系统启动后SCM中还有存根。原来是这么一回事。博客中之前不知道,这两个函数同时会对注册表进行操作,切记,切记。
–update5.14/2015
- SCM数据库存在于注册表中。枚举的时候访问的是对应的注册表中的项。存放在注册表中的这些服务,开机后就会创建(注意是创建,而不是启动)。
OSR DRIVER LOADER
中的Register Service
做的其实就是CreateService
,这时候就会往注册表中写入启动项。OSR DRIVER LOADER
中的Unregister Service
做的其实就是deleteService
,这时候就会从注册表中删除此项。
拿AutoRun.exe
做测试,会发现当注册服务之后,会多出此项。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
下存放了很多服务,这些就是SCM数据库中的数据项。
双击进入之后会看到ssdtHook服务
的信息,这些信息其实就是当时CreateService
中填写的参数。
项名称: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SSDTHook
类别名: <无类别>
最近写入时间: 2015-5-14 - 12:32
值 0
名称: Type
类型: REG_DWORD
数据: 0x1
值 1
名称: Start
类型: REG_DWORD
数据: 0x3
值 2
名称: ErrorControl
类型: REG_DWORD
数据: 0x1
值 3
名称: ImagePath
类型: REG_EXPAND_SZ
数据: \??\C:\VC6\MyProjects\SSDTHook\SSDTHook\Debug\SSDTHook.sys
值 4
名称: DisplayName
类型: REG_SZ
数据: SSDTHook
项名称: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\SSDTHook\Security
类别名: <无类别>
最近写入时间: 2015-5-14 - 12:32
值 0
名称: Security
类型: REG_BINARY
数据:
00000000 01 00 14 80 90 00 00 00 - 9c 00 00 00 14 00 00 00 ................
00000010 30 00 00 00 02 00 1c 00 - 01 00 00 00 02 80 14 00 0...............
00000020 ff 01 0f 00 01 01 00 00 - 00 00 00 01 00 00 00 00 ÿ...............
00000030 02 00 60 00 04 00 00 00 - 00 00 14 00 fd 01 02 00 ..`.........ý...
00000040 01 01 00 00 00 00 00 05 - 12 00 00 00 00 00 18 00 ................
00000050 ff 01 0f 00 01 02 00 00 - 00 00 00 05 20 00 00 00 ÿ........... ...
00000060 20 02 00 00 00 00 14 00 - 8d 01 02 00 01 01 00 00 ...............
00000070 00 00 00 05 0b 00 00 00 - 00 00 18 00 fd 01 02 00 ............ý...
00000080 01 02 00 00 00 00 00 05 - 20 00 00 00 23 02 00 00 ........ ...#...
00000090 01 01 00 00 00 00 00 05 - 12 00 00 00 01 01 00 00 ................
000000a0 00 00 00 05 12 00 00 00 - ........
在已经用osr driver loader
注册了之后,autorun
中就会有此项。用autorun
删除了此项之后,点击osr_driver_loader
中的start service
就会报错。提示“指定的服务并未以已安装的服务存在”
。 说明删除做的正是deleteService
。删除之后,会发现autorun
和register
中都已经没有了此项存在。这时候就不会开机创建此服务了。