Windows服务程序的原理及实现(服务分为WIN32服务和系统服务)

今天给大家讲下怎样做一个服务程序…本来是想详细讲的,不过写着写着累得要命..很多

地方就没详细…不过代码我加了点注…如果还有一些不明白的自己查下MSDN……便宜

环境,,VC++6.0…代码有俩段,一段是服务程序的..另一段是安装服务程序的…这个程序

的功能是开机发出滴滴声….安装成功后自己点启动…下次开机就自动起动了….

load.exe的实现是比较简单,本来想弄个汇编版本…不过真的累…就算了..这里一个服

务的基本框架就完成了…剩下的只是添加你自己的功能代码…

怎样安装::我在C盘建一个名为sysnap的文件夹..里面放着俩个EXE..一个是sv.exe 另一

个是svload.exe 然后cmd到这个文件夹,输入svload.exe则服务安装成功…开机后就有一

个服务进程sv.exe…这样我们就有了一个名为sysnap的服务..在注册表里可以找到相关

信息….当然你可以把服务名改为你自己的….svload.exe的代码很简单..我没有注

释,,,,如果需要我回帖再注..我现在累

一个服务的基本框架

1感性认识什么是服务

2用INF文件安装服务

3关于服务的一些基本理论知识

4一个服务的创建流程和基本组成

5详说各个基本函数

6所用到的一些数据结构和API说明

7开始我们的第一个服务,完整代码

8运行我们的服务,完整代码

1感性认识什么是服务

在运行框输入SERVICES.MSC..看到没,,这些都是windows的服务..里面有一些是windows自己的,有一些是第三方服务,,比如我们的杀毒软件大部分都有一个服务

那服务有什么用呢,..让我们先看一下服务的定义吧

服务:是一种应用程序类型,它在后台运行。

可见如果我们把程序做成服务后也可以照样运行起来…如果是设置成手动的,那开机后我们的服务程序就自动运行起来…所以很多木马都搞成服务启动,,这比在注册表里什么RUN

要隐蔽多了

系统有俩种服务.一种叫win32服务,他运行在用户态,对应的映像文件是.EXE或.DLL..我们这里讲的就是win32服务

另外一种叫系统服务,它运行在内核态,对应的映像文件是.SYS也就是驱动程序..其实这俩个概念现在也没必要细分了吧..区别除了运行态不同外,另外还有一个区别,就是在注册表中除了在HKEY_LOCAL_MACHINE/SYSTE/CurrentControlSet/Services下都有一个服务名外,系统服务还多了一个设备硬健HKEY_LOCAL_MACHINESystem/CurrentControlSet/Enum子键,因为是驱动程序嘛,在删除一些内核木马时.这个建默认是无法删除的,因为需要SYSTEM权限..不过右键->权限->添加->高级就可以搞定

2用INF文件安装服务

现在我们就用.INF文件来把我们的EXE程序变成服务..随开机的运行而运行,这个EXE文件我是用我前几天在吧里发的哪个小程序,依然是输出电脑的用户名…在C盘建一个文件夹,命名为SYSNAP..把我们的程序sysnap.exe放进去

打开笔记本,那下面代码写进去,保存为sysnap.inf

[Version]

Signature=”$WINDOWS NT$”

[DefaultInstall.Services]

AddService=sysnap,,My_AddService_Name

[My_AddService_Name]

DisplayName=sysnap

Description=显示电脑用户名

ServiceType=0x10

StartType=2

ErrorControl=0

ServiceBinary=C:/SYSNAP/sysnap.exe

说明一下

1、ServiceType服务类型:0x10为独立进程服务,0x20为共享进程服务(比如svchost)

2、StartType启动类型:0 系统引导时加载,1 OS初始化时加载,2 由SCM(服务控制管理器)自动启动,3 手动启动,4 禁用(注意,0和1只能用于驱动程序)

3、ErrorControl错误控制:0 忽略,1 继续并警告,2 切换到LastKnownGood的设置,3蓝屏

4、ServiceBinary服务程序位置

好了..在CMD下运行命令

 rundll32.exe setupapi,InstallHinfSection DefaultInstall 128 c:/SYSNAP/sysnap.inf 

这样就安装了一个名为sysnap的服务,是不是很简单呢..当然后.INF文件安装服务有时候是不太好,,,下面我们就通过编成来实现,,,也是主要的目的..先讲一下理论吧

3关于服务的一些基本理论知识

WIN32服务由三部分组成:服务应用程序、服务控制程序SCP,和服务控制管理器SCM。

服务应用程序:就是接下来我们要实现的程序,他是一个EXE文件..也可以是.DLL,这里我们是sysnap.exe

服务控制程序:控制服务应用程序的功能块,也是服务应用程序同服务管理器(SCM)之间的桥梁

服务控制管理器:负责加载和初始化AUTO_ATRT的服务程序,SCM维护着注册表中的服务数据库,位于:HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services。其下的子键就是安装的服务和驱动服务。每个子键的名称就是服务名,当安装的时候由服务安全程序的CreateService 函数指定

还有就不写了..可以参考<<inside windows 2000>>他们讲的已经足够好了…,不够里面涉及的东西很多.建议看下后面的程序…不懂的再去参考他们比较好..因为这个程序不要求你全要理解他们

4一个服务的创建流程一个服务的创建流程和基本组成

A编写我们的main)函数,该函数必须在30秒内调用StartServiceCtrlDispatcher 函数..这样我们的EXE文件就在SCM里注册了

B编写我们的ServiceMain),ServiceMain)要立即调用RegisterServiceCtrlHandler 注册服务控制处理函数,然后用RegisterServiceCtrlHandler返回的句柄向SCM发送状态信息,接着开始完成实际的服务任务和工作线程,一旦线程开始,ServiceMain)就等待一个事件的发生,知道服务停止,ServiceMain)才返回

C编写我们的控制处理器ServiceCtrlHandler,接受来自SCM的请求并作出反应,其实请求一般是下面几个值也可以自己定义)

停止服务:SERVICE_CONTROL_STOP 

暂停服务:SERVICE_CONTROL_PAUSE 

恢复被暂停的服务:SERVICE_CONTROL_CONTINUE 

返回服务的更新状态信息:SERVICE_CONTROL_INTERROGATE

D编写这个服务要实现的功能函数,也就是我们这个服务要完成什么功能,这里依然是输出电脑用户名

可见,一个完整的服务包括:

main):他告诉SCM 关于ServiceMain)的一些信息

ServiceMain):开始ServiceThread),告诉SCM关于控制处理器的一些信息

ServiceCtrlHandler:接受来自SCM的请求并做出响应

InitThread):由ServiceMain)打开,执行我们的任务,,就是建立一个线程来运行我们的任务

5详说各个基本函数

A main)

SCM是一个管理系统所有服务的进程,当SCM启动某个服务时,它等待某个进程的主线程来调用StartServiceCtrlDispatcher),这样把调用进程的住线程转换为控制分配器,控制分配器启动一个新线程,新线程运行分配表里每个服务的ServiceMain)

B ServiceMain)

是服务的入口点.它运行在一个单独的线程中,主要是为服务注册控制处理器,它指示控制分配器调用ServiceCtrlHandler)来处理SCM的请求,注册完成后将返回一个句柄

通过调用SetServiceStatus,用这个句柄和SERVICE_STATUS向SCM报告服务状态,,,因为这样的动作经常发生,,,所以我们把这个过程写成一个函数ReportStatusToSCMgr)

RegisterServiceCtrlHandlerstrServiceName, LPHANDLER_FUNCTION)ServiceCtrlHandler);

接着调用ReportStatusToSCMgr)向SCM报告服务状态 ReportStatusToSCMgr);

创建一个事件,在函数的最后将调用该事件来保持函数的运行知道SCM发出停止请求才返回 CreateEvent);

创建一个线程来运行我们的服务函数 sysnap);

最后ServiceThread)完成后返回ServiceMain),ServiceMain)调用 WaitForSingleObject)

C ServiceCtrlHandler)

检查SCM发送了什么请求并且做出反应…当用户关闭系统,所有的控制处理要调用SetServiceStatus设置SERVICE_ACCEPT_SHUTDOWN控制码去接收SERVICE_CONTROL_SHUTDOWN控制码,如果服务需要时间去清除,它可以发送 STOP_PENDING状态消息,连同一个等待时间,这样,服务控制器在报告系统服务关闭之前才知道应该待多长时间,无论如何,都有一个服务控制器需要等待的时间,防止服务停留在shutdown状态。要改变这个时间限制,可以修改HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Control中的WaitToKillServiceTimeout值。 

switchnControlCode)

{

case SERVICE_CONTROL_SHUTDOWN:

case SERVICE_CONTROL_STOP:

nServiceCurrentStatus=SERVICE_STOP_PENDING;

success=ReportStatusToSCMgrSERVICE_STOP_PENDING,NO_ERROR,0,1,3000);

KillService);

return;

default:

break;

}

6所用到的一些数据结构和API说明

本来想写,,算了.自己查MSDN///累….下面代码我会加点注射

下面就直接代码吧…可以自己编译

sv.exe的代码

#include <stdio.h>

#include <windows.h>

#include <winsvc.h>

//定义一些全局变量和函数

void ServiceMainDWORD argc, LPTSTR *argv); 

void ServiceCtrlHandlerDWORD dwControlCode);

//SCM报告服务状态信息

BOOL ReportStatusToSCMgrDWORD dwCurrentState, DWORD dwWin32ExitCode,

 DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,

 DWORD dwWaitHint);

BOOL InitThread); //创建线程来运行我们的任务

DWORD sysnapLPDWORD param); //我们这个服务所要完成的任务

HANDLE hServiceThread; 

void KillService); 

char *strServiceName = “sysnap”; ////标识服务的内部名

SERVICE_STATUS_HANDLE nServiceStatusHandle; //存储调用RegisterServiceCtrlHandler返回的句柄

HANDLE killServiceEvent;

BOOL nServiceRunning;

DWORD nServiceCurrentStatus;

void mainint argc, char* argv[])

{

// SERVICE_TABLE_ENTRY 结构类型的数组,他包含了调用进程所提供的每个服务的入口函数和字符串名。表中的最后一个元素必须为 NULL,指明入口表结束

SERVICE_TABLE_ENTRY servicetable[]=

{

{strServiceName,LPSERVICE_MAIN_FUNCTION)ServiceMain},

{NULL,NULL}

};

BOOL success;

 // StartServiceCtrlDispatcher 函数负责把程序主线程连接到服务控制管理程序

success=StartServiceCtrlDispatcherservicetable);

if!success)

{

printf”fialed!”);

}

}

void ServiceMainDWORD argc, LPTSTR *argv)

{

BOOL success;

//把ServiceCtrlHandler注册为服务控制器,接受来自SCM的请求并做出处理,

nServiceStatusHandle=RegisterServiceCtrlHandlerstrServiceName,

LPHANDLER_FUNCTION)ServiceCtrlHandler);

//判断是否注册成功,否则返回

if!nServiceStatusHandle)

{

return;

}

//注册成功后向SCM报告服务状态信息,因为服务还没初始化完成,所以当前服务状态为SERVICE_START_PENDING

success=ReportStatusToSCMgrSERVICE_START_PENDING,NO_ERROR,0,1,3000);

if!success)

{

return;

}

//创建一个事件,在函数的最后将用该事件来保持函数的运行直到SCM发出停止请求才返回

killServiceEvent=CreateEvent0,TRUE,FALSE,0);

ifkillServiceEvent==NULL)

{

return;

}

//向SCM报告服务状态信息

success=ReportStatusToSCMgrSERVICE_START_PENDING,NO_ERROR,0,2,1000);

if!success)

{

return;

}

//InitThread)创建一个线程来运行我们的sysnap)函数

success=InitThread);

if!success)

{

return;

}

//我们的服务开始运行任务了,当前状态设置为SERVICE_RUNNING

nServiceCurrentStatus=SERVICE_RUNNING;

success=ReportStatusToSCMgrSERVICE_RUNNING,NO_ERROR,0,0,0);

if!success)

{

return;

}

//sysnap)函数运行完了之后返回ServiceMain),ServiceMain)调用WaitForSingleObject,因为服务被停止之前ServiceMain)不会结束

WaitForSingleObjectkillServiceEvent,INFINITE);

CloseHandlekillServiceEvent);

}

//向SCM报告服务状态信息,可以说是更新信息吧,它接受的参数都是SERVICE_STATUS结构成员

BOOL ReportStatusToSCMgrDWORD dwCurrentState, DWORD dwWin32ExitCode,

 DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,

 DWORD dwWaitHint)

{

BOOL success;

SERVICE_STATUS nServiceStatus; //定义一个SERVICE_STATUS类型结构nServiceStatus

nServiceStatus.dwServiceType=SERVICE_WIN32_OWN_PROCESS; //表示我们的服务是独占一个进程的服务

nServiceStatus.dwCurrentState=dwCurrentState; //当前服务状态

//

ifdwCurrentState==SERVICE_START_PENDING) 

{

nServiceStatus.dwControlsAccepted=0; //服务的初始化没有完成

}

else

{

nServiceStatus.dwControlsAccepted=SERVICE_ACCEPT_STOP //通知 SCM 服务接受哪个域。这里允许 STOP 和SHUTDOWN 请求

|SERVICE_ACCEPT_SHUTDOWN;

}

//dwServiceSpecificExitCode在你终止服务并报告退出细节时很有用。初始化服务时并不退出,因此值为 0

ifdwServiceSpecificExitCode==0)

{

nServiceStatus.dwWin32ExitCode=dwWin32ExitCode;

}

else

{

nServiceStatus.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR;

}

nServiceStatus.dwServiceSpecificExitCode=dwServiceSpecificExitCode;

//

nServiceStatus.dwCheckPoint=dwCheckPoint;

nServiceStatus.dwWaitHint=dwWaitHint;

 //设置好nServiceStatus后,向SCM报告服务状态

 success=SetServiceStatusnServiceStatusHandle,&nServiceStatus);

if!success)

{

KillService);

return success;

}

else

return success;

}

BOOL InitThread)

{

DWORD id;

hServiceThread=CreateThread0,0,

LPTHREAD_START_ROUTINE)sysnap,

0,0,&id);

ifhServiceThread==0)

{

return false;

}

else

{

nServiceRunning=true;

return true;

}

}

DWORD sysnapLPDWORD param)

{

 whilenServiceRunning)

{

Beep450,150);

Sleep4000);

}

return 0;

}

void KillService)

{

nServiceRunning=false;

SetEventkillServiceEvent);

ReportStatusToSCMgrSERVICE_STOPPED,NO_ERROR,0,0,0);

}

void ServiceCtrlHandlerDWORD dwControlCode)

{

BOOL success;

switchdwControlCode)

{

case SERVICE_CONTROL_SHUTDOWN: 

case SERVICE_CONTROL_STOP:

nServiceCurrentStatus=SERVICE_STOP_PENDING;

success=ReportStatusToSCMgrSERVICE_STOP_PENDING,NO_ERROR,0,1,3000);//先更新服务状态为SERVICDE_STOP_PENDING,再停止服务

KillService);

return;

default:

break;

}

ReportStatusToSCMgrnServiceCurrentStatus,NO_ERROR,0,0,0);

}

svload.exe的代码

#include <stdio.h>

#include <windows.h>

#include <winsvc.h>

int mainint argc, char* argv[])

{

 char* showInfo=”sysnap’s first Windows service”;      //注意宽字符的转换(L)

 char* showName=”sysnap”;

 char* sv_Path=”C://sysnap//sv.exe”;

SC_HANDLE Hsysnap;

 SC_HANDLE hSCManager;

hSCManager=OpenSCManager0,0,SC_MANAGER_CREATE_SERVICE);

if!hSCManager)

{

printf”failed”);

return 1;

}

Hsysnap=CreateServicehSCManager,TEXTshowName),

TEXTshowInfo),

SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_DEMAND_START,

SERVICE_ERROR_NORMAL,

sv_Path,

0,0,0,0,0);

if!Hsysnap)

{

CloseServiceHandlehSCManager);

printf”failed”);

return 1;

}

CloseServiceHandleHsysnap);

CloseServiceHandlehSCManager);

return 0;

}

俩个EXE文件一共334K….如果不想编译我可以把他们发到你邮葙

哈哈..谢谢给个精品..当时在写的时候认为很清晰..不过现在自己再看一遍..是比较长..我把他的整体弄上来,,,看了才不灰乱 

void main) 

调用StartServiceCtrlDispatcher),把控制交给控制分配器,控制分配器新建一个线程来运行ServiceMain..也就是真正进入服务 

void ServiceMainDWORD argc, LPTSTR *argv) 

RegisterServiceCtrlHandler注册为服务控制器,接受来自SCM的请求并做出处理 

创建一个事件,在函数的最后将用该事件来保持函数的运行直到SCM发出停止请求 才返回 

创建一个线程来运行我们的函数 

函数运行完了之后返回ServiceMain),ServiceMain)调用  

BOOL ReportStatusToSCMgr) 

 填充SERVICE_STATUS 成员..并把它做为参数传给etServiceStatus)向SCM报告服务状 态  

BOOL InitThread) 

创建运行sysnap)的线程 

DWORD sysnapLPDWORD param) 

 我们要做的工作 

void KillService) 

停止服务 

void ServiceCtrlHandlerDWORD dwControlCode) 

接受来自SCM的请求并做出反应..这里要自己实现几个函数; 
}

总之记住看的时候以main),ServiceMain)和ServiceCtrlHandler)为中心..其他函数都是比较简单的

http://blog.csdn.net/jiangxinyu/article/details/5265673

Published by

风君子

独自遨游何稽首 揭天掀地慰生平

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注