window服务调试(一):winodw服务运行原理

window服务调试(一):winodw服务运行原理

windows服务运行主要由三部分构成:安装windows服务 启动windows服务 卸载windows服务

一、安装window服务

安装window服务的原理是获取到SCM(服务控制管理器)的句柄,然后将服务名和该服务的可执行路径写入SCM中以注册一个服务,用到的Windows API有 OpenSCManager、CreateService

示例代码:

VOID SvcInstall()
{
	SC_HANDLE schSCManager;
	SC_HANDLE schService;
	TCHAR szPath[MAX_PATH];

	if (!GetModuleFileName(NULL, szPath, MAX_PATH))
	{
		printf("Cannot install service (%d)\n", GetLastError());
		return;
	}

	// Get a handle to the SCM database. 

	schSCManager = OpenSCManager(
		NULL,                    // local computer
		NULL,                    // ServicesActive database 
		SC_MANAGER_ALL_ACCESS);  // full access rights 

	if (NULL == schSCManager)
	{
		printf("OpenSCManager failed (%d)\n", GetLastError());
		return;
	}

	// Create the service

	schService = CreateService(
		schSCManager,              // SCM database 
		SVCNAME,                   // name of service 
		SVCNAME,                   // service name to display 
		SERVICE_ALL_ACCESS,        // desired access 
		SERVICE_WIN32_OWN_PROCESS, // service type 
		SERVICE_DEMAND_START,      // start type 
		SERVICE_ERROR_NORMAL,      // error control type 
		szPath,                    // path to service's binary 
		NULL,                      // no load ordering group 
		NULL,                      // no tag identifier 
		NULL,                      // no dependencies 
		NULL,                      // LocalSystem account 
		NULL);                     // no password 

	if (schService == NULL)
	{
		printf("CreateService failed (%d)\n", GetLastError());
		CloseServiceHandle(schSCManager);
		return;
	}
	else printf("Service installed successfully\n");

	CloseServiceHandle(schService);
	CloseServiceHandle(schSCManager);
}

启动window服务

winodw服务并不是服务程序启动的,而是由SCM启动的,如下图所示( 按win+R 输入services.msc即可打开服务)当你启动这个服务时,SCM就会按照之前安装服务给出的路径去启动服务程序

image

这个时候

1.你需要告诉SCM主要的服务函数在哪里,然后SCM就会调用这个函数(StartServiceCtrlDispatcher)
2.用一个回调函数处理当SCM停止服务、暂停服务、恢复服务要做哪些操作(RegisterServiceCtrlHandler)
3.最后在主要的服务函数中告诉SCM启动成功(setSvcStatus或ReportSvcStatus)
示例代码

void __cdecl _tmain(int argc, TCHAR *argv[])
{
	// If command-line parameter is "install", install the service. 
	// Otherwise, the service is probably being started by the SCM.

	if (lstrcmpi(argv[1], TEXT("install")) == 0)
	{
		SvcInstall();
		return;
	}

	// TO_DO: Add any additional services for the process to this table.
	SERVICE_TABLE_ENTRY DispatchTable[] =
	{
		{ SVCNAME, (LPSERVICE_MAIN_FUNCTION)SvcMain },
		{ NULL, NULL }
	};

	DWORD dw_RetCode = -1;

	// This call returns when the service has stopped. 
	// The process should simply terminate when the call returns.

	if (!StartServiceCtrlDispatcher(DispatchTable))
	{
		dw_RetCode = GetLastError();
		MessageBoxEx(NULL, _T("start SvrName service fail!"), NULL, 0, 0);
		SvcReportEvent(TEXT("StartServiceCtrlDispatcher"));
	}
}
VOID WINAPI SvcMain(DWORD dwArgc, LPTSTR *lpszArgv)
{
	// Register the handler function for the service

	gSvcStatusHandle = RegisterServiceCtrlHandler(
		SVCNAME,
		SvcCtrlHandler);

	if (!gSvcStatusHandle)
	{
		SvcReportEvent(TEXT("RegisterServiceCtrlHandler"));
		return;
	}

	// These SERVICE_STATUS members remain as set here

	gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
	gSvcStatus.dwServiceSpecificExitCode = 0;
	gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE;


	WriteToLog("in SvrMain(), start Service success!");

	// Report initial status to the SCM

	ReportSvcStatus(SERVICE_START_PENDING, NO_ERROR, 3000);

	// Perform service-specific initialization and work.

	SvcInit(dwArgc, lpszArgv);
}

卸载window服务

卸载Window服务是最简单的,利用OpenSCManager和OpenService获取服务句柄,再用DeleteService删除服务即可

代码实例(由于是逆向还原的代码,可读性有些差,多包涵)

void uninsatllService() {
	SERVICE_STATUS ServiceStatus = {0,};
	SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (!scm) {

		_tprintf(L"UninstallService() : OpenSCManager failed (%d)", GetLastError());
		return;
	}
	SC_HANDLE sevice = OpenService(scm, ServiceName, DELETE | SERVICE_INTERROGATE);

	if (sevice == 0) {

		DWORD error = GetLastError();

		if (error != 0x424) {
			_tprintf(L"UninstallService() : OpenSCManager failed (%d)", error);
			CloseServiceHandle(scm);
			return;
		}
		goto _EXIT;	
	}
	ControlService(sevice, SERVICE_CONTROL_INTERROGATE, &ServiceStatus);
	if (ServiceStatus.dwCurrentState != 1) {
		_tprintf(L"  -> Service is running! Stop the servi");
	}
	else {
		if (DeleteService(sevice) == 0) {
			_tprintf(L"UninstallService() : DeleteService fail");
		}else
			_tprintf(L"Service uninstalled successfully\n");
	}
	CloseServiceHandle(sevice);
		_EXIT:
	CloseServiceHandle(scm);
	return;
}

完整源码:

#include <Windows.h>
#include<stdio.h>
#include<tchar.h>
#define ServiceName TEXT("SvcTest")
void WINAPI SvcMain(
	DWORD dwNumServicesArgs,
	LPSTR *lpServiceArgVectors
);
VOID WINAPI sub_401380(DWORD dwFlag);
void installService(TCHAR * fileName);
void uninsatllService();
struct _SERVICE_STATUS ServiceStatus = {0x10,0,0xFF,0,0,0,0};

SERVICE_STATUS_HANDLE hServiceStatus = {0,};


int _tmain(int argc, TCHAR*argv[]) {
	TCHAR  fileName[0x105] = {0,};

	BOOL flag = FALSE;
	LPSERVICE_MAIN_FUNCTIONW LpserviceMainFunctionw = (LPSERVICE_MAIN_FUNCTIONW)SvcMain;
	SERVICE_TABLE_ENTRY steTable[] = {
		{ServiceName,LpserviceMainFunctionw},
		{NULL,NULL}
	};

	if (argc == 1) {

		flag = StartServiceCtrlDispatcher(steTable);
		if (flag) {
			_tprintf(L"StartServiceCtrlDispatcher() failed!!! [%d]", GetLastError());
		}
	}
	else if (argc == 2) {
			if (!GetModuleFileName(NULL, fileName, 0x105)) {

				printf("GetModuleFileName() failed! [%d]\n", GetLastError());
				return 0;
			}

			if (!_tcsicmp(argv[1], L"install")) {
				installService(fileName);
				return 0;
			}
			 

			if (!_tcsicmp(argv[1], L"uninstall")) {
				uninsatllService();
				
				return 0;
			}
			
			_tprintf(L"Wrong parameters!!!\n");
		}

	_tprintf(L"\nUSAGE : %s <install | uninstall>\n",argv[0]);
	
	return 0;
}

void WINAPI SvcMain(
	DWORD dwNumServicesArgs,
	LPSTR *lpServiceArgVectors
) {
	LPHANDLER_FUNCTION handle_funtion = (LPHANDLER_FUNCTION)sub_401380;
	hServiceStatus = RegisterServiceCtrlHandler(ServiceName, handle_funtion);
	if (hServiceStatus == NULL) {
		OutputDebugString(L"RegisterServiceCtrlHandler() failed!!!");
		return;
	}
	ServiceStatus.dwCurrentState = SERVICE_RUNNING;
	SetServiceStatus(hServiceStatus, &ServiceStatus);
	do {
		
		OutputDebugString(L"[SvcTest] service is running...");
		Sleep(0x0BB8);
	} while (TRUE);
	
}


void uninsatllService() {
	SERVICE_STATUS ServiceStatus = {0,};
	SC_HANDLE scm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
	if (!scm) {

		_tprintf(L"UninstallService() : OpenSCManager failed (%d)", GetLastError());
		return;
	}
	SC_HANDLE sevice = OpenService(scm, ServiceName, DELETE | SERVICE_INTERROGATE);

	if (sevice == 0) {

		DWORD error = GetLastError();

		if (error != 0x424) {
			_tprintf(L"UninstallService() : OpenSCManager failed (%d)", error);
			CloseServiceHandle(scm);
			return;
		}
		goto _EXIT;	
	}
	ControlService(sevice, SERVICE_CONTROL_INTERROGATE, &ServiceStatus);
	if (ServiceStatus.dwCurrentState != 1) {
		_tprintf(L"  -> Service is running! Stop the servi");
	}
	else {
		if (DeleteService(sevice) == 0) {
			_tprintf(L"UninstallService() : DeleteService fail");
		}else
			_tprintf(L"Service uninstalled successfully\n");
	}
	CloseServiceHandle(sevice);
		_EXIT:
	CloseServiceHandle(scm);
	return;
}void installService(TCHAR * fileName) {
	SC_HANDLE scm = OpenSCManager(NULL, NULL, 0xF003F);
	if (scm == 0) {
		_tprintf(L"InstallService() : OpenSCManager failed (%d)", GetLastError());
		return;
	}

	SC_HANDLE service = CreateServiceW(scm, ServiceName, ServiceName, 0x0F01FF, 0x10, 3, 1, fileName, NULL, NULL, NULL, NULL, NULL);
	if (service == 0) {
		DWORD error = GetLastError();
		_tprintf(L"InstallService() : CreateService failed (%d)", GetLastError());
		if (error == 0x431) {
			_tprintf(L"-> The specified service already exists.");
			CloseServiceHandle(scm);
			return;
		}
		else
			goto _END;
	
	}
	_tprintf(L"InstallService() : Service installed successfully");
	CloseServiceHandle(service);
_END:
	CloseServiceHandle(scm);
}
VOID WINAPI sub_401380(DWORD dwFlag) {
	if (dwFlag - 1 == 0) {
		ServiceStatus.dwCurrentState = 3;
		SetServiceStatus(hServiceStatus, &ServiceStatus);
		ServiceStatus.dwCurrentState = 1;
		SetServiceStatus(hServiceStatus, &ServiceStatus);
		OutputDebugString(L"[SvcTest] service is stopped...");
	}
	return;
}
posted @ 2021-08-22 15:32  乘舟凉  阅读(360)  评论(0编辑  收藏  举报