windows服务简介
Microsoft Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。
这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。这种服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上工作的其他用户,需要长时间运行功能时使用。还可以在不同于登录用户的特定用户帐户或默认计算机帐户的安全上下文中运行服务。
编写windows服务
Windows服务程序有着固定的模式,它一般由四个部分组成:main(), ServiceMain(), ServiceHandle(), MyWork()
main() 仅负责创建服务分派表并启动控制分派机制
典型代码如下:
int main(void) { SERVICE_TABLE_ENTRYA ServTable[2]; // 创建服务分派表。 ServTable[0].lpServiceName = "Test"; // 服务名称。类似于 Win32 应用程序的窗口名称。每个服务代表一项功能。 ServTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; //服务入口函数。 ServTable[1].lpServiceName = NULL; // 每一个服务分派表代表一个服务,分派表的最后一项必须是服务名和服务主函数域的 NULL 指针。 ServTable[1].lpServiceProc = NULL; // 我们称之为“哨兵”(所有值都为NULL),表示该服务表末尾。 StartServiceCtrlDispatcher(ServTable); // 启动控制分派机制。 return 0; }
SERVICE_TABLE_ENTRYA 结构体:
typedef struct _SERVICE_TABLE_ENTRYA { LPSTR lpServiceName; // 服务名称。 LPSERVICE_MAIN_FUNCTIONA lpServiceProc; // 服务入口函数。 } SERVICE_TABLE_ENTRYA, *LPSERVICE_TABLE_ENTRYA;
StartServiceCtrlDispatcher()
功能:连接程序主线程到服务控制管理程序
返回值:非零表示成功,零表示失败。
BOOL StartServiceCtrlDispatcher( CONST SERVICE_TABLE_ENTRYA *lpServiceStartTable // SERVICE_TABLE_ENTRYA 结构体变量。 );
服务控制管理器(SCM:Services Control Manager)是一个管理系统所有服务的进程
当 SCM 启动某个服务时,它等待某个进程的主线程来调用 StartServiceCtrlDispatcher 函数,将分派表传递给 StartServiceCtrlDispatcher。
这将把调用进程的主线程转换为控制分派器。该分派器启动一个新线程,该线程运行分派表中每个服务的 ServiceMain 函数分派器还监视程序中所有服务的执行情况。
然后分派器将控制请求从 SCM 传给服务。分派表中所有的服务执行完之后,或者发生错误时。StartServiceCtrlDispatcher 调用返回。然后主进程终止。
SCM 开始启动一个服务程序时,总是等待这个服务程序去调用 StartServiceCtrlDispatcher()。
而当服务开始运行时,main() 将会调用 ServiceMain(), 直到 ServiceMain() 执行完毕或发生错误而退出,StartServiceCtrlDispatcher() 返回,主线程将会终止。
ServiceMain() 服务入口函数
它的作用就是:将你需要执行的任务放到该函数中循环执行即可。这就是服务程序的工作函数。
在ServiceMain执行你的任务前,需要给SERVICE_TABLE_ENTRY 分派表结构体进行赋值。
典型代码如下:
// SERVICE_STATUS ServiceStatus; //这段代码应声明为全局变量,因多处使用。 // SERVICE_STATUS_HANDLE hStatus; //这段代码应声明为全局变量,因多处使用。 void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv) { // 初始化状态设置。 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; // 即服务目前状态为 正在初始化。 ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP |SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN; // 这个通知 SCM 服务接收哪个域。本例包含 停止,暂停和继续,关机等命令。 ServiceStatus.dwWin32ExitCode = 0; // 这个域在终止服务并报告细节时很有用。下面这四个值一般不用关心,通常设置为 0。 ServiceStatus.dwCheckPoint = 0; // 用来报告它当前的事件进展情况的。 ServiceStatus.dwServiceSpecificExitCode = 0; // 这个域在终止服务并报告细节时也很有用。 ServiceStatus.dwWaitHint = 0; // 根据初始化过程的长短而定。 // 注册控制函数。 hStatus = RegisterServiceCtrlHandler("ServiceName", // 注册服务控制程序,注册成功后将会返回一个服务状态句柄。 (LPHANDLER_FUNCTION)ServiceHandler); // ServiceHandle 是服务控制程序。类似与 Windows 应用程序的窗口过程。 if (!hStatus) { printf("Register Service Error!\n"); system("pause"); return; } SetServiceStatus(hStatus, &ServiceStatus); // 设置服务状态。通过调用 SetServiceStatus 函数,向 SCM 报告服务的状态。 if (GetLastError != NO_ERROR) // 返回调用线程最近的错误代码值,检查是否出错。 { // 如果出错,将其重设为停止状态。 ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(hStatus, &ServiceStatus); printf("Start Error!\n"); system("pause"); return; } // 没有错误就继续运行。 ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(hStatus, &ServiceStatus); // 创建线程执行特定功能 HANDLE hThread = CreateThread(NULL, 0, MyWork, NULL, 0, NULL); // MyWOrk 是特定功能的函数,如后门程序。 if(hThread = NULL) return; }
SERVICE_STATUS 结构体:
typedef struct _SERVICE_STATUS { DWORD dwServiceType; // 服务类型。 DWORD dwCurrentState; // 服务的当前状态。 DWORD dwControlsAccepted; // 服务在其处理函数中接受和处理的控制代码。 DWORD dwWin32ExitCode; // 服务用于报告启动或停止时发生错误的错误代码。 DWORD dwServiceSpecificExitCode; // 服务在启动或停止时发生错误时返回的错误代码。 DWORD dwCheckPoint; // 服务在长时间启动、停止、暂停或继续操作期间定期递增以报告其进度的检查点值。 DWORD dwWaitHint; // 将要进行 开始、停止、暂停或继续服务 操作所需的估计时间 (以毫秒为单位)。 } SERVICE_STATUS, *LPSERVICE_STATUS;
dwServiceType 的值:(可组合)
值 | 含义 |
SERVICE_FILE_SYSTEM_DRIVER | 该服务是一个文件系统驱动程序 |
SERVICE_KERNEL_DRIVER | 该服务是一个设备驱动程序 |
SERVICE_WIN32_OWN_PROCESS | 服务在自己的进程中运行(通常使用这个) |
SERVICE_USER_OWN_PROCESS | 该服务在登录用户帐户下在其自己的进程中运行 |
dwCurrentState 的值:
值 | 含义 |
SERVICE_CONTINUE_PENDING | 服务处于从暂停状态恢复的过程中 |
SERVICE_PAUSE_PENDING | 服务正在暂停过程中,但还有没完全进入暂停状态 |
SERVICE_PAUSED | 服务已经暂停了 |
SERVICE_RUNNING | 服务正在运行了 |
SERVICE_START_PENDING | 服务在启动过程中,但还没有准备好对请求进行响应 |
SERVICE_STOP_PENDING | 服务正在停止过程中,但还没有完全进入停止状态 |
SERVICE_STOPPED | 服务已经停止了 |
dwControlsAccepted 的值: (可组合)
值 | 含义 |
---|---|
SERVICE_ACCEPT_NETBINDCHANGE | 该服务是一个网络组件,并且能够在服务在服务不重启的情况下,改变其所网络接收的绑定,接收SERVICE_CONTROL_NETBINDADD、SERVICE_CONTROL_NETBINDREMOVE、SERVICE_CONTROL_NETBINDENABLE、SERVICE_CONTROL_NETBINDDISABLE 的通知 |
SERVICE_ACCEPT_PARAMCHANGE | 服务在不重启的情况下能够重新读取其配置参数,接收 SERVICE_CONTROL_PARAMCHANGE 通知 |
SERVICE_ACCEPT_PAUSE_CONTINUE | 服务支持暂停和重启,服务能够接收到 SERVICE_CONTROL_PAUSE 和SERVICE_CONTROL_CONTINUE的通知 |
SERVICE_ACCEPT_PRESHUTDOWN | 系统在关闭前,能够收到系统的 SERVICE_CONTROL_PRESHUTDOWN 通知,用来处理一些关闭前的清理,xp之前不支持此控制码 |
SERVICE_ACCEPT_SHUTDOWN | 能够接收系统退出时的 SERVICE_CONTROL_SHUTDOWN 的通知,以便处理一些回收 |
SERVICE_ACCEPT_STOP | 能够接收 SERVICE_CONTROL_STOP 的通知来处理一些回收任务 |
SetServiceStatus()
功能:更新服务控制管理器调用服务的状态信息。
返回值:非零表示成功,零表示失败。
函数原型:
BOOL SetServiceStatus( SERVICE_STATUS_HANDLE hServiceStatus, //服务状态信息结构的句柄, 由 RegisterServiceCtrlHandler() 返回。 LPSERVICE_STATUS lpServiceStatus // 指向 SERVICE_STATUS 结构的指针包含呼叫服务的最新状态信息。 );
RegisterServiceCtrlHandler()
功能:注册一个函数以处理服务控制请求。
返回值:如果函数成功, 则返回值为服务状态句柄。如果函数失败, 返回值为零。
函数原型:
SERVICE_STATUS_HANDLE RegisterServiceCtrlHandler( LPCSTR lpServiceName, //调用线程运行的服务的名称, 即在 CreateService() 中指定的服务控制程序的服务名称。 LPHANDLER_FUNCTION lpHandlerProc // 指向要注册的处理程序的函数。 );
CreateThread()
功能:该函数在 主线程 的基础上创建一个新线程。线程 终止运行后,线程对象仍然在系统中,必须通过 CloseHandle() 来关闭该线程对象。
返回值:如果函数成功, 则返回值是新线程的句柄。如果函数失败, 返回值为 NULL。
函数原型:
HANDLE CreateThread( LPSECURITY_ATTRIBUTES lpThreadAttributes, SIZE_T dwStackSize, LPTHREAD_START_ROUTINE lpStartAddress, LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId );
参数:
lpThreadAttributes
指向 SECURITY_ATTRIBUTES 结构的指针, 它确定返回的句柄是否可以由子进程继承。
如果 lpThreadAttributes 为 NULL, 则无法继承句柄。
dwStackSize
堆栈的初始大小 (以字节为单位)。系统将此值舍入到最近的页面。
如果此参数为零, 则新线程将使用可执行文件的默认大小。
lpStartAddress
指向要由线程执行的应用程序定义的函数。此指针表示线程的起始地址。
lpParameter
指向要传递给线程的变量的指针。
dwCreationFlags
控制线程创建的标志。通常情况下为 0。
lpThreadId
指向接收线程标识符的变量的指针。如果此参数为 NULL, 则不返回线程标识符。
返回值:如果函数成功, 则返回值是新线程的句柄。如果函数失败, 返回值为 NULL。
ServiceHandle() 服务控制函数
典型代码如下:
void WINAPI ServiceHandler(DWORD fdwControl) { switch (fdwControl) { case SERVICE_CONTROL_PAUSE: ServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: ServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(hStatus, &ServiceStatus); return; default: break; } SetServiceStatus(hStatus, &ServiceStatus); // 重设服务状态。 return; }
OpenSCManager()
功能:建立了一个到服务控制管理器的连接,并打开指定的数据库。
返回值:如果函数成功,返回值是一个指定的服务控制管理器数据库的句柄。如果函数失败,返回值为NULL 。
函数原型:
SC_HANDLE OpenSCManager( LPCSTR lpMachineName, // 指向零终止字符串,指定目标计算机的名称。 通常为 NULL。 LPCSTR lpDatabaseName, // 指向零终止字符串,指定将要打开的服务控制管理数据库的名称。通常为 NULL。 DWORD dwDesiredAccess // 指定服务访问控制管理器的权限。通常为 SC_MANAGER_ALL_ACCESS。 );
参数:
lpMachineName
指向零终止字符串,指定目标计算机的名称。
如果该指针为NULL ,或者它指向一个空字符串,那么该函数连接到本地计算机上的服务控制管理器。
lpDatabaseName
指向零终止字符串,指定将要打开的服务控制管理数据库的名称。
此字符串应被置为 SERVICES_ACTIVE_DATABASE。
如果该指针为NULL ,则打开默认的 SERVICES_ACTIVE_DATABASE 数据库。
dwDesiredAccess
指定服务访问控制管理器的权限。
在授予要求的权限前,系统会检查调用进程的权限令牌,该令牌针对与服务控制管理器相关的安全描述符的权限控制列表。
此外,该函数的调用将隐式地指定 SC_MANAGER_CONNECT 的访问权限。
此外,下列服务控制管理器对象的访问类型可以被指定:
SC_MANAGER_ALL_ACCESS 除了所有此表中列出的访问类型,还包括 STANDARD_RIGHTS_REQUIRED。
SC_MANAGER_CONNECT 可以连接到服务控制管理器。
SC_MANAGER_CREATE_SERVICE 使要求的 CreateService 函数创建一个服务对象,并将其添加到数据库中。
SC_MANAGER_ENUMERATE_SERVICE 使要求的 EnumServicesStatus 功能清单的服务,这是在数据库中。
SC_MANAGER_LOCK 使要求的 LockServiceDatabase 功能获得锁定数据库。
SC_MANAGER_QUERY_LOCK_STATUS 使要求的 QueryServiceLockStatus 检索功能锁定状态信息的数据库。
OpenService()
功能:打开一个服务对象。
返回值:如果函数成功, 则返回值是服务的句柄。如果函数失败,返回值为NULL 。
函数原型:
SC_HANDLE OpenService( SC_HANDLE hSCManager, // 使用 OpenSCManager() 打开后返回的对象句柄。 LPCSTR lpServiceName, // 需要打开的服务的名称,其中不能出现斜杆。 DWORD dwDesiredAccess // 打开权限。通常为 SC_MANAGER_ALL_ACCESS。 );
参数:
lpServiceName
这是在创建服务对象时由 CreateService 函数的 lpServiceName 参数指定的名称,
而不是用户界面应用程序显示的用于标识服务的服务显示名称。
dwDesiredAccess
权限同上。
在授予请求的访问权限之前, 系统将根据与服务对象关联的安全描述符的自由访问控制列表检查调用进程的访问令牌。
返回值:如果函数成功, 则返回值是服务的句柄。如果函数失败,返回值为NULL 。
CreateService()
功能:创建一个服务对象,并将其添加到指定的服务控制管理器数据库的函数。
返回值:如果函数成功, 则返回值是服务的句柄。如果函数失败, 返回值为 NULL。
函数原型:
SC_HANDLE CreateService( SC_HANDLE hSCManager, // 服务控制管理器数据库的句柄。 LPCSTR lpServiceName, // 要安装的服务的名称。 LPCSTR lpDisplayName, // 用户界面程序用来标识服务的显示名称。 DWORD dwDesiredAccess, // 对服务的访问权限。通常为 SC_MANAGER_ALL_ACCESS。 DWORD dwServiceType, // 服务类型。 通常为 SERVICE_WIN32_OWN_PROCESS。 DWORD dwStartType, // "服务启动" 选项。通常为 SERVICE_AUTO_START。 DWORD dwErrorControl, // 错误的严重性和所采取的操作。 LPCSTR lpBinaryPathName, // 服务二进制文件的完全限定路径。 LPCSTR lpLoadOrderGroup, // 通常不关心,设置为 NULL。 LPDWORD lpdwTagId, // 通常不关心,设置为 NULL。 LPCSTR lpDependencies, // 通常不关心,设置为 NULL。 LPCSTR lpServiceStartName, // 通常不关心,设置为 NULL。 LPCSTR lpPassword // 通常不关心,设置为 NULL。 );
参数:
hSCManager
服务控制管理器数据库的句柄。此句柄由 OpenSCManager 函数返回,
并且必须具有 SC_MANAGER_CREATE_SERVICE 访问权限。
lpServiceName
要安装的服务的名称。最大字符串长度为256个字符。
服务控制管理器数据库保留字符的大小写, 但服务名称比较始终不区分大小写。正斜杠 (/) 和反斜线 () 不是有效的服务名称字符。
lpDisplayName
用户界面程序用来标识服务的显示名称。此字符串的最大长度为256个字符。
该名称在服务控制管理器中保留为 case。显示名称比较始终不区分大小写。
dwDesiredAccess
对服务的访问。在授予请求的访问权限之前, 系统将检查调用进程的访问令牌。值同 OpenSCManager() 的该参数。
dwServiceType
服务类型
值 | 含义 |
SERVICE_FILE_SYSTEM_DRIVER | 文件系统驱动程序服务。 |
SERVICE_KERNEL_DRIVER | 驱动程序服务。 |
SERVICE_WIN32_OWN_PROCESS | 在其自己的进程中运行的服务。(常用的值) |
SERVICE_USER_OWN_PROCESS | 该服务在登录用户帐户下在其自己的进程中运行。 |
dwStartType
“服务启动” 选项
值 | 含义 |
SERVICE_AUTO_START | 在系统启动期间, 服务控制管理器自动启动服务。(常用的值) |
SERVICE_BOOT_START | 由系统加载器启动的设备驱动程序。此值仅对驱动程序服务有效。 |
SERVICE_DEMAND_START | 当进程调用 StartService 函数时, 由服务控制管理器启动的服务。 |
SERVICE_DISABLED | 无法启动的服务。尝试启动服务会导致错误代码 ERROR_SERVICE_DISABLED。 |
SERVICE_SYSTEM_START | 由 IoInitSystem 函数启动的设备驱动程序。此值仅对驱动程序服务有效。 |
dwErrorControl
错误的严重性和所采取的操作
值 | 含义 |
SERVICE_ERROR_CRITICAL | 如果可能, 启动程序会在事件日志中记录错误。如果正在启动最后一次已知良好的配置, 则启动操作将失败。否则, 系统将以最后一次正确的配置重新启动。 |
SERVICE_ERROR_IGNORE | 启动程序忽略错误并继续启动操作。 |
SERVICE_ERROR_NORMAL | 启动程序在事件日志中记录错误, 但继续启动操作。 |
SERVICE_ERROR_SEVERE | 启动程序在事件日志中记录错误。如果正在启动最后一次已知良好的配置, 则启动操作将继续进行。否则, 系统将以上次已知良好的配置重新启动。 |
lpBinaryPathName
服务二进制文件的完全限定路径。如果路径包含空格, 则必须引用它以使其正确解释。
该路径还可以包含自动启动服务的参数。例如, “d:\myshare\myservice.exe arg1 arg2″。这些参数被传递到服务入口点。
如果在另一台计算机上指定路径, 则该共享必须由本地计算机的计算机帐户访问, 因为这是远程调用中使用的安全上下文。
但是, 此要求允许远程计算机中的任何潜在漏洞影响本地计算机。因此, 最好使用本地文件。
StartService()
功能:启动服务。
返回值:非零表示成功,零表示失败。
QueryServiceStatus()
功能:检索指定服务的当前状态。
返回值:非零表示成功,零表示失败。
函数原型:
BOOL QueryServiceStatus( SC_HANDLE hService, // 此句柄由 OpenService 或 CreateService 函数返回, 并且必须具有 SERVICE_START 访问权限。 LPSERVICE_STATUS lpServiceStatus // 指向接收状态信息的 SERVICE_STATUS 结构的指针。 );
ControlService()
功能:向服务发送控制代码。
返回值:非零表示成功,零表示失败。
函数原型:
BOOL ControlService( SC_HANDLE hService, // 此句柄由 OpenService 或 CreateService 函数返回, 并且必须具有 SERVICE_START 访问权限。 DWORD dwControl, // 控制代码。 LPSERVICE_STATUS lpServiceStatus // 指向接收最新服务状态信息的 SERVICE_STATUS 结构的指针。 );
参数
dwControl
控制代码 | 含义 |
SERVICE_CONTROL_CONTINUE | 通知暂停的服务应恢复。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
SERVICE_CONTROL_INTERROGATE | 通知服务应将其当前状态信息报告给服务控制管理器。hService 句柄必须具有 SERVICE_INTERROGATE 访问权限。 |
SERVICE_CONTROL_NETBINDADD | 通知网络服务有一个用于绑定的新组件。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
SERVICE_CONTROL_NETBINDDISABLE | 通知网络服务其中一个绑定已被禁用。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
SERVICE_CONTROL_NETBINDENABLE | 通知网络服务已启用已禁用的绑定。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
SERVICE_CONTROL_NETBINDREMOVE | 通知网络服务已删除绑定的组件。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
SERVICE_CONTROL_PARAMCHANGE | 通知服务其启动参数已更改。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
SERVICE_CONTROL_PAUSE | 通知服务应暂停。hService 句柄必须具有 SERVICE_PAUSE_CONTINUE 访问权限。 |
SERVICE_CONTROL_STOP | 通知服务应停止。hService 句柄必须具有 SERVICE_STOP 访问权限。 |
DeleteService()
功能:将指定的服务标记为从服务控制管理器数据库中删除。
返回值:非零表示成功,零表示失败。
函数原型:
BOOL DeleteService( SC_HANDLE hService // 此句柄由 OpenService 或 CreateService 函数返回, 并且必须具有 "删除" 访问权限。 );
CloseServiceHandle()
功能:关闭服务控制管理器或服务对象的句柄。
返回值:非零表示成功,零表示失败。
函数原型:
BOOL CloseServiceHandle( SC_HANDLE hSCObject // 要关闭的服务控件管理器对象或服务对象的句柄。 );
参数
hSCObject
要关闭的服务控件管理器对象或服务对象的句柄。
服务控制管理器对象的句柄由 OpenSCManager 函数返回, 并且服务对象的句柄由 OpenService 或 CreateService 函数返回。
代码
#include<stdio.h> #include<Windows.h> #include<winsock.h> #pragma comment(lib, "Advapi32") #pragma comment(lib,"ws2_32") #define MYPORT 1234 #define BACKLOG 10 SERVICE_STATUS ServiceStatus; SERVICE_STATUS_HANDLE hStatus; SC_HANDLE SCManager; SC_HANDLE SCService; void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv); void WINAPI ServiceHandler(DWORD fdwControl); void InstallService(); void StartService0(); void StopService(); void UnInstallService(); void MyWork(); // 自定义特定功能的函数。本打算用线程调用完成的,简单起见就这样吧。 //DWORD WINAPI MyWork(LPVOID lpParam); 该函数涉及到线程,先放这里。 int main(void) { SERVICE_TABLE_ENTRY ServTable[2]; ServTable[0].lpServiceName = (LPSTR)"Test"; ServTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain; ServTable[1].lpServiceName = NULL; ServTable[1].lpServiceProc = NULL; StartServiceCtrlDispatcher(ServTable); InstallService(); StartService0(); return 0; } void WINAPI ServiceMain(DWORD dwArgc, LPSTR *lpszArgv) { // 初始化状态设置。 ServiceStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; ServiceStatus.dwCurrentState = SERVICE_START_PENDING; ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN; ServiceStatus.dwWin32ExitCode = 0; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwServiceSpecificExitCode = 0; ServiceStatus.dwWaitHint = 0; // 注册控制函数。 hStatus = RegisterServiceCtrlHandler("BackDoor", (LPHANDLER_FUNCTION)ServiceHandler); if (!hStatus) { printf("Register Service Error!\n"); system("pause"); return; } SetServiceStatus(hStatus, &ServiceStatus); // 如果出错,将其重设为停止状态。 if (GetLastError() != NO_ERROR) { ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(hStatus, &ServiceStatus); printf("Start Error!\n"); system("pause"); return; } // 没有错误就继续运行。 ServiceStatus.dwCurrentState = SERVICE_RUNNING; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(hStatus, &ServiceStatus); // 从这里开始可以放入你想服务为你做的事情。 /* HANDLE hThread = CreateThread(NULL, 0, MyWork, NULL, 0, NULL); if (hThread = NULL) return; */ //功能函数 MyWork(); return; } void WINAPI ServiceHandler(DWORD fdwControl) { switch (fdwControl) { case SERVICE_CONTROL_PAUSE: ServiceStatus.dwCurrentState = SERVICE_PAUSED; break; case SERVICE_CONTROL_CONTINUE: ServiceStatus.dwCurrentState = SERVICE_RUNNING; break; case SERVICE_CONTROL_STOP: case SERVICE_CONTROL_SHUTDOWN: ServiceStatus.dwCurrentState = SERVICE_STOPPED; ServiceStatus.dwCheckPoint = 0; ServiceStatus.dwWaitHint = 0; SetServiceStatus(hStatus, &ServiceStatus); StopService(); UnInstallService(); return; default: break; } SetServiceStatus(hStatus, &ServiceStatus);// 重设服务状态。 return; } //注册服务 void InstallService() { char PathName[MAX_PATH]; char SysName[MAX_PATH]; GetModuleFileName(NULL, PathName, MAX_PATH); GetSystemDirectory(SysName, MAX_PATH); wsprintf(SysName, "%s\\Test.exe", SysName); if (!MoveFile(PathName, SysName)) { printf(" Move File Error!\n"); system("pause"); return; } SCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);//建立了一个到服务控制管理器的连接,并打开指定的数据库 if (SCManager == NULL) { printf("OpenSCManager Error!\n"); system("pause"); return; } SCService = CreateService(//创建一个服务对象,并将其添加到指定的服务控制管理器数据库的函数 SCManager, "BackDoor", "Service32", SC_MANAGER_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_IGNORE, SysName, NULL, NULL, NULL, NULL, NULL); if (SCService == NULL) { printf("CreateService Error!\n"); CloseServiceHandle(SCManager); system("pause"); return; } printf("Create Service Succeed!\n"); CloseServiceHandle(SCService); CloseServiceHandle(SCManager); return; } //开启服务 void StartService0() { SCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (SCManager == NULL) { printf("OpenSCManager Error!\n"); system("pause"); return; } SCService = OpenService(SCManager, "BackDoor", SC_MANAGER_ALL_ACCESS);//打开一个服务对象。 if(SCService == NULL) { printf("OpenService Error!\n"); CloseServiceHandle(SCManager); system("pause"); return; } if (StartService(SCService, NULL, NULL))//启动服务 { while (QueryServiceStatus(SCService,&ServiceStatus)) { if (ServiceStatus.dwCurrentState == SERVICE_RUNNING) break; else Sleep(100); } printf("Service Start Succeed!\n"); } CloseServiceHandle(SCService); CloseServiceHandle(SCManager); return; } //停止服务 void StopService() { SCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);//建立了一个到服务控制管理器的连接,并打开指定的数据库 if (SCManager == NULL) { printf("OpenSCManager Error!\n"); system("pause"); return; } SCService = OpenService(SCManager, "BackDoor", SC_MANAGER_ALL_ACCESS);//打开服务 if (SCService == NULL) { printf("Open Service Error!\n"); CloseServiceHandle(SCManager); system("pause"); return; } if (ControlService(SCService, SERVICE_CONTROL_STOP, &ServiceStatus))//向服务发送控制代码 { while (QueryServiceStatus(SCService, &ServiceStatus))//检索指定服务的当前状态 { if (ServiceStatus.dwCurrentState == SERVICE_STOPPED) break; else Sleep(100); } printf("Service Stop Succeed!\n"); } CloseServiceHandle(SCService); CloseServiceHandle(SCManager); return; } //卸载服务 void UnInstallService() { SCManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS); if (SCManager == NULL) { printf("OpenSCManager Error!\n"); system("pause"); return; } SCService = OpenService(SCManager, "BackDoor", SC_MANAGER_ALL_ACCESS); if (SCService == NULL) { printf("Open Service Error!\n"); CloseServiceHandle(SCManager); system("pause"); return; } if (DeleteService(SCService))//删除服务 printf("Uninstall Service Succeed!\n"); else printf("Unistall Service Error!\n"); CloseServiceHandle(SCService); CloseServiceHandle(SCManager); return; } //功能函数 void MyWork() { SOCKET sockfd, new_fd; struct sockaddr_in my_addr; struct sockaddr_in their_addr; int sin_size = sizeof(struct sockaddr_in); WSADATA ws; if (WSAStartup(MAKEWORD(2, 2), &ws) != 0) { printf("WSAStart up Error!\n"); WSACleanup(); system("pause"); exit(0); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { printf("Socket Error!\n"); system("pause"); exit(0); } my_addr.sin_family = AF_INET; my_addr.sin_port = htons(MYPORT); my_addr.sin_addr.S_un.S_addr = INADDR_ANY; if (bind(sockfd, (struct sockaddr*)&my_addr, sizeof(struct sockaddr)) == -1) { printf("Bind Error!\n"); closesocket(sockfd); system("pause"); exit(0); } if (listen(sockfd, BACKLOG) == SOCKET_ERROR) { printf("Listen Error!\n"); closesocket(sockfd); system("pause"); exit(0); } if ((new_fd = accept(sockfd, (struct sockaddr *)&their_addr, &sin_size)) == INVALID_SOCKET) { printf("Accept Error!\n"); closesocket(sockfd); exit(0); } closesocket(sockfd); closesocket(new_fd); WSACleanup(); return; } /* DWORD WINAPI MyWork(LPVOID lpParam) { return 0; } */
非常感谢M-Anonymous 大部分从如下链接转载
https://www.cnblogs.com/M-Anonymous/p/9380772.html
https://www.cnblogs.com/M-Anonymous/p/9393088.html
强烈推荐 https://www.cnblogs.com/M-Anonymous 这是一位优秀的学者,再次感谢