系统安全-服务编写

服务

Microsoft Windows 服务(即,以前的 NT 服务)使您能够创建在它们自己的 Windows 会话中可长时间运行的可执行应用程序。这些服务可以在计算机启动时自动启动,可以暂停和重新启动而且不显示任何用户界面。这种服务非常适合在服务器上使用,或任何时候,为了不影响在同一台计算机上工作的其他用户,需要长时间运行功能时使用。还可以在不同于登录用户的特定用户帐户或默认计算机帐户的安全上下文中运行服务。

exe服务程序

服务程序编写主要有两种方式,exe服务和Dll服务,exe是最为简单的一种服务程序,编写过程几乎不用什么额外操作,只需要将编译生成的exe文件用工具导入服务即可。服务添加工具有很多,SRVINSTW是比较简单的一种。
系统安全-服务编写
系统安全-服务编写
这种方法除了方便可以说没有一点好处,当然是从恶意角度来说。服务进程直接显示在任务管理器中,恶意进攻时,若是计算机出现异常,有一定计算机基础的人很容易就会发现问题并解决。如果只是简单地要编写服务的话可以采用这种方法,若要实现一定隐蔽效果,则需要采用下面这种方法。
#Dll服务

svchost

svchost.exe是微软Windows操作系统中的系统文件,微软官方对它的解释是:svchost.exe 是从动态链接库 (DLL) 中运行的服务的通用主机进程名称。这个程序对系统的正常运行是非常重要,而且是不能被结束的。许多服务通过注入到该程序中启动,所以会有多个该文件的进程。如果能将Dll挂靠在系统进程下,无疑给我们的代码增加了更大的安全性和隐蔽性,故选择将dll隐藏到svhost服务组中。

Dll编写方法在之前的文章已经介绍过了,导出需要的函数即可。而Dll安装服务的代码则需要我们自行编写,具体代码如下:

#include "windows.h"
#include "strsafe.h"

#define DLL_NAME		TEXT("dllservice.dll")
#define SERVICE_NAME	TEXT("KW")
#define SERVICE_GROUP	TEXT("netsvcs")

DWORD IntallDllService(TCHAR szServiceFilePath[], TCHAR szServiceName[], TCHAR szServiceDisplayName[], TCHAR szServiceGroup[]);
DWORD AddSvchostService(TCHAR szServiceName[], TCHAR szServiceGroup[]);
DWORD StartDllService(TCHAR szServiceName[]);
DWORD UnInstallService(TCHAR szServiceName[], TCHAR szServiceGroup[]);
DWORD RemoveSvchostService(TCHAR szServiceName[], TCHAR szServiceGroup[]);

int WINAPI WinMain( __in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in_opt LPSTR lpCmdLine, __in int nShowCmd )
{
	TCHAR	szDllPath[MAX_PATH];

#define INSTALL

#ifdef INSTALL
	//服务dll路径
	::GetFullPathName(DLL_NAME, ARRAYSIZE(szDllPath), szDllPath, NULL);

	//安装服务
	IntallDllService(szDllPath, SERVICE_NAME, SERVICE_NAME, SERVICE_GROUP);

	//启动服务
	StartDllService(SERVICE_NAME);
#else
	//卸载
	UnInstallService(SERVICE_NAME, SERVICE_GROUP);
#endif
	return	0;
}

/************************************************************************/
/* 
功能:安装dll开机启动服务
参数:szServiceFilePath		- 服务dll的路径
      szServiceName			- 服务名
	  szServiceDisplayName	- 显示的服务名
	  szServiceGroup		- 将该服务添加到的服务组
返回:错误代码
原理:1.svchost开机启动时在Windows NT\CurrentVersion\SvcHost读取服务组,
        并且启动他们
	  2.对应dll在SYSTEM\CurrentControlSet\Services\服务名\Paramters中的键ServiceDll
*/
/************************************************************************/
DWORD IntallDllService(TCHAR szServiceFilePath[], 
					   TCHAR szServiceName[], 
					   TCHAR szServiceDisplayName[],
					   TCHAR szServiceGroup[])
{
	SC_HANDLE	hScm = NULL;
	SC_HANDLE	hService = NULL;
	HKEY		hRootKey = NULL;
	HKEY		hKeyService = NULL;
	HKEY		hKeyParameters = NULL;
	DWORD		dwRet = 0;
	TCHAR		szServiceImagePath[MAX_PATH];
	TCHAR		szRegPath[MAX_PATH];

	//先创建服务吧
	__try
	{
		hScm = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
		if (NULL == hScm)
		{
			__leave;
		}
		::StringCchCopy(szServiceImagePath, ARRAYSIZE(szServiceImagePath), TEXT("%SystemRoot%\\system32\\svchost.exe -k "));
		::StringCchCat(szServiceImagePath, ARRAYSIZE(szServiceImagePath), szServiceGroup);

		hService = ::CreateService(hScm,
			szServiceName,
			szServiceDisplayName,
			SERVICE_ALL_ACCESS,
			SERVICE_WIN32_OWN_PROCESS,
			SERVICE_AUTO_START,
			SERVICE_ERROR_NORMAL,
			szServiceImagePath,
			NULL,
			NULL,
			NULL,
			NULL,
			NULL
			);
		if (NULL == hService)
		{
			//已经存在,那就打开呗
			if (::GetLastError() == ERROR_SERVICE_EXISTS)
			{
				hService = ::OpenService(hScm, szServiceName, SERVICE_ALL_ACCESS);
				if (NULL == hService)
				{
					__leave;
				}
			}
			else
			{
				__leave;
			}
		}

		//在对应服务项下Parameters下添加键ServiceDll,对应dll路径
		::StringCchCopy(szRegPath, ARRAYSIZE(szRegPath), TEXT("SYSTEM\\CurrentControlSet\\Services\\"));
		::StringCchCat(szRegPath, ARRAYSIZE(szRegPath), szServiceName);

		hRootKey = HKEY_LOCAL_MACHINE;
		dwRet = ::RegOpenKeyEx(hRootKey, 
			szRegPath, 
			0, 
			KEY_CREATE_SUB_KEY|KEY_SET_VALUE, 
			&hKeyService
			);
		if (dwRet != ERROR_SUCCESS)
		{
			__leave;
		}

		::RegCreateKeyEx(hKeyService,
			TEXT("Parameters"),
			0, NULL,
			REG_OPTION_NON_VOLATILE,
			KEY_ALL_ACCESS,
			NULL,
			&hKeyParameters,
			&dwRet
			);
		
		::RegSetValueEx(hKeyParameters,
			TEXT("ServiceDll"),
			0, REG_EXPAND_SZ,
			(PBYTE)szServiceFilePath,
			::lstrlen(szServiceFilePath)
			);
		
		if (NULL != szServiceGroup)
		{
			AddSvchostService(szServiceName, szServiceGroup);
		}
	}
	__finally
	{
		dwRet = ::GetLastError();
		if (NULL != hScm)
		{
			::CloseServiceHandle(hScm);
		}
		if (NULL != hService)
		{
			::CloseServiceHandle(hService);
		}
		if (NULL != hKeyService)
		{
			::RegCloseKey(hKeyService);
		}
		if (NULL != hKeyParameters)
		{
			::RegCloseKey(hKeyParameters);
		}
	}

	return	dwRet;
}

/************************************************************************/
/* 
 功能:添加服务到svchost启动服务项
 参数:szServiceName	- 服务名
       szServiceGroup	- 服务组名称
*/
/************************************************************************/
DWORD AddSvchostService(TCHAR szServiceName[], TCHAR szServiceGroup[])
{
	PTSTR		pszItemData = NULL;
	DWORD		dwItemValueLen = 0, dwBufferLen = 0;
	DWORD		dwType;
	DWORD		dwRet = 0;
	HKEY		hKeyService = NULL;

	__try
	{
		dwRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
			TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost"), 
			0, 
			KEY_SET_VALUE|KEY_QUERY_VALUE, 
			&hKeyService
			);
		if (ERROR_SUCCESS != dwRet)
		{
			__leave;
		}

		dwItemValueLen = 0;
		::RegQueryValueEx(hKeyService, szServiceGroup, 0, &dwType, NULL, &dwItemValueLen);

		dwBufferLen = dwItemValueLen;
		dwBufferLen += (::lstrlen(szServiceName) + 1) * sizeof(TCHAR);
		pszItemData = (PTSTR)::HeapAlloc(::GetProcessHeap(), 0, dwBufferLen);
		if (NULL != pszItemData)
		{
			::RegQueryValueEx(hKeyService, 
				szServiceGroup,
				0,
				&dwType,
				(PBYTE)pszItemData,
				&dwItemValueLen
				);
			//检测是否已经有本服务
			PTSTR pServiceItem = pszItemData;
			for (;
				TEXT('\0') != *pServiceItem && ::lstrcmp(szServiceName, pServiceItem);
				pServiceItem += lstrlen(pServiceItem) + 1
				)
			{
			}
			
			if (TEXT('\0') == *pServiceItem)
			{
				::StringCchCat(pszItemData+dwItemValueLen/sizeof(TCHAR)-1, 
					(dwBufferLen+1-dwItemValueLen)/sizeof(TCHAR), 
					szServiceName
					);

				::RegSetValueEx(hKeyService,
					szServiceGroup,
					0, 
					dwType,
					(PBYTE)pszItemData,
					dwBufferLen
					);
			}
			else
			{
				::SetLastError(ERROR_SERVICE_EXISTS);
			}
		}
	}
	__finally
	{
		dwRet = ::GetLastError();
		if (NULL != hKeyService)
		{
			::RegCloseKey(hKeyService);
		}
		if (NULL != pszItemData)
		{
			::HeapFree(::GetProcessHeap(), 0, pszItemData);
		}
	}

	return	0;
}

/************************************************************************/
/* 
 功能:开启dll服务
 参数:szServiceName	- 服务名称
*/
/************************************************************************/
DWORD StartDllService(TCHAR szServiceName[])
{ 
	SC_HANDLE		hScm = NULL;
	SC_HANDLE		hService = NULL;
	SERVICE_STATUS	ServiceStatus ={0};
	DWORD			dwRet = 0;
	DWORD			dwError = 0;

	__try
	{
		//打开服务管理器
		hScm = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
		if (NULL == hScm)
		{
			__leave;
		}

		//打开服务
		hService = ::OpenService(hScm, szServiceName, SERVICE_START);
		if (NULL == hService)
		{
			__leave;
		}

		//开启服务
		dwRet = ::StartService(hService, 0, NULL);
		if (0 == dwRet)
		{
		}
		else
		{
		}
	}
	__finally
	{
		dwError = ::GetLastError();
		if (NULL != hScm)
		{
			::CloseServiceHandle(hScm);
		}
		if (NULL != hService)
		{
			::CloseServiceHandle(hService);
		}
	}

	return	dwError;
}

/************************************************************************/
/* 
 功能:删除服务
 参数:szServiceName	- 需要删除的服务名称
       szServiceGroup   - 从该服务组中删除本服务的服务组名称
 返回:错误代码
*/
/************************************************************************/
DWORD UnInstallService(TCHAR szServiceName[], TCHAR szServiceGroup[])
{
	SC_HANDLE		hScm = NULL;
	SC_HANDLE		hService = NULL;
	DWORD			dwError = 0;
	DWORD			dwServiceConfigLen = 0;
	DWORD			dwBytesNeeded = 0;
	LPQUERY_SERVICE_CONFIG	pServiceConfig = NULL;

	__try
	{
		hScm = ::OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
		if (NULL == hScm)
		{
			__leave;
		}
		hService = ::OpenService(hScm, szServiceName, SERVICE_ALL_ACCESS);
		if (NULL == hService)
		{
			__leave;
		}
		
		//停止服务
		SERVICE_STATUS	ServiceStatus;
		::ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);

		//删除
		if (!::DeleteService(hService))
		{
			__leave;
		}

		//从服务组中删除的服务
		if (NULL == szServiceGroup)
		{
			RemoveSvchostService(szServiceName, szServiceGroup);
		}
	}
	__finally
	{
		dwError = ::GetLastError();
		if (NULL != hScm)
		{
			::CloseServiceHandle(hScm);
		}
		if (NULL != hService)
		{
			::CloseServiceHandle(hService);
		}
		if (NULL != pServiceConfig)
		{
			::HeapFree(::GetProcessHeap(), 0, pServiceConfig);
		}
	}

	return	dwError;
}

/************************************************************************/
/* 
 功能:将服务从svchost启动项中移除
 参数:szServiceName	- 要移除的服务名
       szServiceGroup	- 从该服务组中移除服务
*/
/************************************************************************/
DWORD RemoveSvchostService(TCHAR szServiceName[], TCHAR szServiceGroup[])
{
	PTSTR		pszItemData = NULL;
	DWORD		dwItemValueLen = 0, dwNewItemValueLen = 0;
	DWORD		dwType;
	DWORD		dwRet = 0;
	HKEY		hKeyService = NULL;

	__try
	{
		dwRet = ::RegOpenKeyEx(HKEY_LOCAL_MACHINE, 
			TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\SvcHost"), 
			0, 
			KEY_SET_VALUE|KEY_QUERY_VALUE, 
			&hKeyService
			);
		if (ERROR_SUCCESS != dwRet)
		{
			__leave;
		}

		dwItemValueLen = 0;
		::RegQueryValueEx(hKeyService, szServiceGroup, 0, &dwType, NULL, &dwItemValueLen);

		pszItemData = (PTSTR)::HeapAlloc(::GetProcessHeap(), 0, dwItemValueLen);
		if (NULL != pszItemData)
		{
			::RegQueryValueEx(hKeyService, 
				szServiceGroup,
				0,
				&dwType,
				(PBYTE)pszItemData,
				&dwItemValueLen
				);
			//检测该服务组是否有本服务, 如果则删除
			PTSTR pServiceItem = pszItemData;
			for (;
				TEXT('\0') != *pServiceItem && ::lstrcmp(szServiceName, pServiceItem);
				pServiceItem += lstrlen(pServiceItem) + 1
				)
			{
			}
			if (TEXT('\0') != *pServiceItem)
			{
				DWORD	dwDeleteServiceItemLen;
				PTSTR	pNextServiceItem;

				dwDeleteServiceItemLen = ::lstrlen(pServiceItem) + 1;
				pNextServiceItem = pServiceItem + dwDeleteServiceItemLen;
				::memcpy(pServiceItem, pNextServiceItem, pszItemData+dwItemValueLen-pNextServiceItem);
				dwNewItemValueLen = dwItemValueLen - dwDeleteServiceItemLen;

				::RegSetValueEx(hKeyService,
					szServiceGroup,
					0, 
					dwType,
					(PBYTE)pszItemData,
					dwNewItemValueLen
					);
			}
			else 
			{
				::SetLastError(ERROR_SERVICE_NOT_FOUND);
			}
		}
	}
	__finally
	{
		dwRet = ::GetLastError();
		if (NULL != hKeyService)
		{
			::RegCloseKey(hKeyService);
		}
		if (NULL != pszItemData)
		{
			::HeapFree(::GetProcessHeap(), 0, pszItemData);
		}
	}
	return	0;
}

使用火绒查看进程调用的dll
系统安全-服务编写

总结

简单编写服务可以使用服务添加工具添加编写好exe的方法实现。
若需要一定隐蔽性,程序可以通过编写为dll再接入服务组运行的方式来避免任务管理器的查看,进行进程隐藏,达到部分隐蔽效果。但是在服务中仍然以单体形式显示,这种方法对于只会切任务管理器的初级甚至中级的电脑用户来说比较有效,虽然我也是做了这个实验才知道有利用服务隐藏进程的方法。但是只要留痕就有被发现的危险,以后可以进一步研究更为隐蔽,更难以发现的隐藏手段。

上一篇:TCHAR用法


下一篇:Windows 程序设计(三)关于字符串