zoukankan      html  css  js  c++  java
  • 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()

    RegisterServiceCtrlHandler(strServiceName, (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值。 

    switch(nControlCode)

    {

    case SERVICE_CONTROL_SHUTDOWN:

    case SERVICE_CONTROL_STOP:

    nServiceCurrentStatus=SERVICE_STOP_PENDING;

    success=ReportStatusToSCMgr(SERVICE_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 ServiceMain(DWORD argc, LPTSTR *argv); 

    void ServiceCtrlHandler(DWORD dwControlCode);

    //SCM报告服务状态信息

    BOOL ReportStatusToSCMgr(DWORD dwCurrentState, DWORD dwWin32ExitCode,

     DWORD dwServiceSpecificExitCode, DWORD dwCheckPoint,

     DWORD dwWaitHint);

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

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

    HANDLE hServiceThread; 

    void KillService(); 

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

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

    HANDLE killServiceEvent;

    BOOL nServiceRunning;

    DWORD nServiceCurrentStatus;

    void main(int argc, char* argv[])

    {

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

    SERVICE_TABLE_ENTRY servicetable[]=

    {

    {strServiceName,(LPSERVICE_MAIN_FUNCTION)ServiceMain},

    {NULL,NULL}

    };

    BOOL success;

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

    success=StartServiceCtrlDispatcher(servicetable);

    if(!success)

    {

    printf("fialed!");

    }

    }

    void ServiceMain(DWORD argc, LPTSTR *argv)

    {

    BOOL success;

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

    nServiceStatusHandle=RegisterServiceCtrlHandler(strServiceName,

    (LPHANDLER_FUNCTION)ServiceCtrlHandler);

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

    if(!nServiceStatusHandle)

    {

    return;

    }

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

    success=ReportStatusToSCMgr(SERVICE_START_PENDING,NO_ERROR,0,1,3000);

    if(!success)

    {

    return;

    }

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

    killServiceEvent=CreateEvent(0,TRUE,FALSE,0);

    if(killServiceEvent==NULL)

    {

    return;

    }

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

    success=ReportStatusToSCMgr(SERVICE_START_PENDING,NO_ERROR,0,2,1000);

    if(!success)

    {

    return;

    }

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

    success=InitThread();

    if(!success)

    {

    return;

    }

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

    nServiceCurrentStatus=SERVICE_RUNNING;

    success=ReportStatusToSCMgr(SERVICE_RUNNING,NO_ERROR,0,0,0);

    if(!success)

    {

    return;

    }

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

    WaitForSingleObject(killServiceEvent,INFINITE);

    CloseHandle(killServiceEvent);

    }

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

    BOOL ReportStatusToSCMgr(DWORD 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; //当前服务状态

    //

    if(dwCurrentState==SERVICE_START_PENDING) 

    {

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

    }

    else

    {

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

    |SERVICE_ACCEPT_SHUTDOWN;

    }

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

    if(dwServiceSpecificExitCode==0)

    {

    nServiceStatus.dwWin32ExitCode=dwWin32ExitCode;

    }

    else

    {

    nServiceStatus.dwWin32ExitCode=ERROR_SERVICE_SPECIFIC_ERROR;

    }

    nServiceStatus.dwServiceSpecificExitCode=dwServiceSpecificExitCode;

    //

    nServiceStatus.dwCheckPoint=dwCheckPoint;

    nServiceStatus.dwWaitHint=dwWaitHint;

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

     success=SetServiceStatus(nServiceStatusHandle,&nServiceStatus);

    if(!success)

    {

    KillService();

    return success;

    }

    else

    return success;

    }

    BOOL InitThread()

    {

    DWORD id;

    hServiceThread=CreateThread(0,0,

    (LPTHREAD_START_ROUTINE)sysnap,

    0,0,&id);

    if(hServiceThread==0)

    {

    return false;

    }

    else

    {

    nServiceRunning=true;

    return true;

    }

    }

    DWORD sysnap(LPDWORD param)

    {

     while(nServiceRunning)

    {

    Beep(450,150);

    Sleep(4000);

    }

    return 0;

    }

    void KillService()

    {

    nServiceRunning=false;

    SetEvent(killServiceEvent);

    ReportStatusToSCMgr(SERVICE_STOPPED,NO_ERROR,0,0,0);

    }

    void ServiceCtrlHandler(DWORD dwControlCode)

    {

    BOOL success;

    switch(dwControlCode)

    {

    case SERVICE_CONTROL_SHUTDOWN: 

    case SERVICE_CONTROL_STOP:

    nServiceCurrentStatus=SERVICE_STOP_PENDING;

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

    KillService();

    return;

    default:

    break;

    }

    ReportStatusToSCMgr(nServiceCurrentStatus,NO_ERROR,0,0,0);

    }

    svload.exe的代码

    #include <stdio.h>

    #include <windows.h>

    #include <winsvc.h>

    int main(int 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=OpenSCManager(0,0,SC_MANAGER_CREATE_SERVICE);

    if(!hSCManager)

    {

    printf("failed");

    return 1;

    }

    Hsysnap=CreateService(hSCManager,TEXT(showName),

    TEXT(showInfo),

    SERVICE_ALL_ACCESS,SERVICE_WIN32_OWN_PROCESS,SERVICE_DEMAND_START,

    SERVICE_ERROR_NORMAL,

    sv_Path,

    0,0,0,0,0);

    if(!Hsysnap)

    {

    CloseServiceHandle(hSCManager);

    printf("failed");

    return 1;

    }

    CloseServiceHandle(Hsysnap);

    CloseServiceHandle(hSCManager);

    return 0;

    }

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

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



    void main() 

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


    void ServiceMain(DWORD argc, LPTSTR *argv) 


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


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

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


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




    BOOL ReportStatusToSCMgr() 

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



    BOOL InitThread() 

    创建运行sysnap()的线程 


    DWORD sysnap(LPDWORD param) 

     我们要做的工作 


    void KillService() 

    停止服务 


    void ServiceCtrlHandler(DWORD dwControlCode) 

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

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

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

  • 相关阅读:
    可爱的中国电信 请问我们的电脑还属于我们自己吗?
    了解客户的需求,写出的代码或许才是最优秀的............
    DELPHI DATASNAP 入门操作(3)简单的主从表的简单更新【含简单事务处理】
    用数组公式获取字符在字符串中最后出现的位置
    在ehlib的DBGridEh控件中使用过滤功能(可以不用 MemTableEh 控件 适用ehlib 5.2 ehlib 5.3)
    格式化json返回的时间
    ExtJs中使用Ajax赋值给全局变量异常解决方案
    java compiler level does not match the version of the installed java project facet (转)
    收集的资料(六)ASP.NET编程中的十大技巧
    收集的资料共享出来(五)Asp.Net 权限解决办法
  • 原文地址:https://www.cnblogs.com/findumars/p/5650644.html
Copyright © 2011-2022 走看看