设为首页 收藏本站
查看: 592|回复: 0

[经验分享] Windows服务程序的原理及实现(服务分为WIN32服务和系统服务)

[复制链接]

尚未签到

发表于 2017-6-29 12:23:00 | 显示全部楼层 |阅读模式
  今天给大家讲下怎样做一个服务程序...本来是想详细讲的,不过写着写着累得要命..很多
  地方就没详细...不过代码我加了点注...如果还有一些不明白的自己查下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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-389332-1-1.html 上篇帖子: 背水一战 Windows 10 (23) 下篇帖子: Windows下ELK环境搭建(单机多节点集群部署)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表