制作可被svchost调用的服务(下)

6 篇文章 0 订阅

上一篇简要介绍了如何制作一个可被svchost调用的服务,本篇介绍如何使得这个服务可以被svchost识别并调用。

svchost会到注册表的HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost项中搜索其子项,每一个子项都是一个svchost服务组,svchost项有很多键值,每个键对应一个服务组,其值是该服务组下所有的服务

所以,首先要决定我们自己的服务放在哪个服务组里,这里假设是netsvcs组。在netsvcs键值最后添加自编服务的名称即可。

随后svchost会根据服务名到注册表的HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services项下找到服务名同名的子项,子项中的一些键定义了这个服务的详情:

“description”键是服务的详细描述;“displayName”是服务的友好显示名称;ErrorControl是错误控制级别,1表示忽略错误,就是告诉操作系统尽管出错了,但还是继续加载其他服务;ImagePath指定了svchost的运行路径以及自编服务所在的服务组,一般为“%SystemRoot%\System32\svchost.exe -k {serv_grp_name}”;ObjectName指定了对象名,对于Win32服务来说,就是系统服务帐号名,比如LocalSystem;start指定了启动类型,3表示手工启动,2表示自动启动,1表示I/O驱动程序方式启动,0表示引导时随内核启动,4表示禁用;type指定了服务类型,1表示内核设备驱动程序,2表示文件系统驱动程序,0x10表示Win32服务,0x20表示该服务可以与其他服务共享进程。上图中的target是后面介绍的程序将会用到的自定义键,用于指定服务被组合到哪个服务组中。

服务名子项下还有一个名为Parameters的子项,这个子项有一个名为ServiceDLL的键,其取值为服务DLL的绝对路径。

综上所述,只要按照上述规则,在注册表中写好相应的信息,重启系统之后,就可以由svchost调用自制服务了。下面的程序可以将自编的可被svchost调用的服务装载到注册表中,亦可从注册表中清除。代码如下:

issapp.h

/*
 * issapp.h
 *
 *  Created on: 2021年5月16日
 *      Author: kingfox
 */

#ifndef ISSAPP_H_
#define ISSAPP_H_

#include <string>

struct ServiceConfig
{
   std::string servName;
   std::string descr;
   std::string dispName;
   uint32_t errorControl;
   std::string imagePath;
   std::string target;
   std::string objectName;
   uint32_t startMode;
   uint32_t type;
   std::string servDLL;

   static const char *servNameKeyName;
   static const char *descrKeyName;
   static const char *dispNameKeyName;
   static const char *errorControlKeyName;
   static const char *imagePathKeyName;
   static const char *targetKeyName;
   static const char *objectNameKeyName;
   static const char *startModeKeyName;
   static const char *typeKeyName;
   static const char *servDLLKeyName;
};

enum class ISSErrorCode
{
   EC_SUCCESS = 0,
   EC_INVALID_FILE = -1,
   EC_INVALID_FORMAT = -2,
   EC_INVALID_SERVICE = -3,
   EC_ALREADY_INSTALLED = -4
};

class InstallServiceApplication
{
public:
   InstallServiceApplication();
   virtual ~InstallServiceApplication();

protected:
   virtual int run(void *params) override;

   void displayUsage();
   long loadServiceConfig(const std::string& filename, ServiceConfig& serviceConfig);
   long installService(const ServiceConfig& serviceConfig);
   long uninstallService(const std::string& servName);
   bool queryService(const std::string& servName);

private:
   static const char __commentChar;
   static const char *__keyValueDelim;
   static const std::string __rootKeyPath;
   static const std::string __svchostPath;
   static const std::string __targetService;

   char configBuffer[65536];
};

#endif /* ISSAPP_H_ */

issapp.cpp:

/*
 * issapp.cpp
 *
 *  Created on: 2021年5月16日
 *      Author: kingfox
 *
 *  Purpose: install a service DLL into svchost, or uninstall a svchost service.
 *  usage:
 *       to install a svchost service: iss install serv_descr_file
 *       to uninstall a svchost service: iss uninstall service_name
 *       to query whether a svchost service is installed: iss query service_name
 */
#include <string>
#include <fstream>
#include <iostream>
#include <vector>
#include <windows.h>
#include "issapp.h"

using namespace std;

const char *ServiceConfig::servNameKeyName = "serviceName";
const char *ServiceConfig::descrKeyName = "Description";
const char *ServiceConfig::dispNameKeyName = "DisplayName";
const char *ServiceConfig::errorControlKeyName = "ErrorControl";
const char *ServiceConfig::imagePathKeyName = "ImagePath";
const char *ServiceConfig::targetKeyName = "target";
const char *ServiceConfig::objectNameKeyName = "ObjectName";
const char *ServiceConfig::startModeKeyName = "Start";
const char *ServiceConfig::typeKeyName = "Type";
const char *ServiceConfig::servDLLKeyName = "ServiceDll";

const char InstallServiceApplication::__commentChar = '#';
const char *InstallServiceApplication::__keyValueDelim = "=";
const string InstallServiceApplication::__rootKeyPath = {"SYSTEM\\CurrentControlSet\\services\\"};
const string InstallServiceApplication::__svchostPath = {"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost\\"};
const string InstallServiceApplication::__targetService = {"netsvcs"};

InstallServiceApplication issApp;

InstallServiceApplication::InstallServiceApplication()
{
}

InstallServiceApplication::~InstallServiceApplication()
{
}

int InstallServiceApplication::run(void *params)
{
   MainArgs *args = reinterpret_cast<MainArgs *>(params);
   long errorCode = NO_ERROR;
   if (args->argc == 1)
   {
      displayUsage();
   }
   else if ((string(args->argv[1]) == "install") && (args->argc == 3))
   {
      ServiceConfig serviceConfig;
      errorCode = loadServiceConfig(args->argv[2], serviceConfig);
      if (errorCode != NO_ERROR)
      {
         cerr << "load config from " << args->argv[2] << " error: " << errorCode << endl;
         return errorCode;
      }
      if (queryService(serviceConfig.servName))
      {
         cout << "svchost service " << serviceConfig.servName << " installed. please uninstall it first." << endl;
         errorCode = (long)ISSErrorCode::EC_ALREADY_INSTALLED;
      }
      else
      {
         errorCode = installService(serviceConfig);
         if (errorCode == NO_ERROR)
         {
            cout << "install service success." << endl;
         }
         else
         {
            cerr << "write registry error: " << errorCode << endl;
         }
      }
   }
   else if ((string(args->argv[1]) == "uninstall") && (args->argc == 3))
   {
      if (!queryService(args->argv[2]))
      {
         cout << "svchost service " << args->argv[2] << " not installed" << endl;
         errorCode = (long)ISSErrorCode::EC_ALREADY_INSTALLED;
      }
      else
      {
         errorCode = uninstallService(args->argv[2]);
         if (errorCode == NO_ERROR)
         {
            cout << "uninstall service success." << endl;
         }
         else
         {
            cerr << "uninstall service failure: " << errorCode << endl;
         }
      }
   }
   else if ((string(args->argv[1]) == "query") && (args->argc == 3))
   {
      bool installed = queryService(args->argv[2]);
      if (installed)
      {
         cout << "svchost service " << args->argv[2] << " installed." << endl;
      }
      else
      {
         cout << "svchost service " << args->argv[2] << " not installed." << endl;
      }
   }
   else
   {
      cerr << "bad arguments." << endl;
      displayUsage();
   }
   return errorCode;
}

void InstallServiceApplication::displayUsage()
{
   cout << "to install a svchost service: iss install serv_descr_file" << endl;
   cout << "to uninstall a svchost service: iss uninstall service_name" << endl;
   cout << "to query whether a svchost service is installed: iss query service_name" << endl;
   cout << "\tNOTE: after install a svchost service, you should restart to make it usable." << endl;
}

long InstallServiceApplication::loadServiceConfig(const string &filename, ServiceConfig &serviceConfig)
{
   long errorCode = (long)ISSErrorCode::EC_SUCCESS;
   string text;
   ifstream ifs(filename);
   if (!ifs)
   {
      errorCode = (long)ISSErrorCode::EC_INVALID_FILE;
   }
   else
   {
      while(!ifs.eof())
      {
         getline(ifs, text);
         StringUtility::trim(text);
         if ((text.length() > 0) && (text.at(0) != __commentChar))
         {
            vector<string> keyAndValue;
            int count = StringUtility::split(text, keyAndValue, __keyValueDelim);
            if (count != 2)
            {
               errorCode = (long)ISSErrorCode::EC_INVALID_FORMAT;
               break;
            }
            if (keyAndValue[0] == ServiceConfig::servNameKeyName)
            {
               serviceConfig.servName.assign(keyAndValue[1]);
            }
            else if (keyAndValue[0] == ServiceConfig::descrKeyName)
            {
               serviceConfig.descr.assign(keyAndValue[1]);
            }
            else if (keyAndValue[0] == ServiceConfig::dispNameKeyName)
            {
               serviceConfig.dispName.assign(keyAndValue[1]);
            }
            else if (keyAndValue[0] == ServiceConfig::errorControlKeyName)
            {
               serviceConfig.errorControl = stoi(keyAndValue[1]);
            }
            else if (keyAndValue[0] == ServiceConfig::imagePathKeyName)
            {
               serviceConfig.imagePath.assign(keyAndValue[1]);
            }
            else if (keyAndValue[0] == ServiceConfig::targetKeyName)
            {
               serviceConfig.target.assign(keyAndValue[1]);
            }
            else if (keyAndValue[0] == ServiceConfig::objectNameKeyName)
            {
               serviceConfig.objectName.assign(keyAndValue[1]);
            }
            else if (keyAndValue[0] == ServiceConfig::startModeKeyName)
            {
               serviceConfig.startMode = stoi(keyAndValue[1]);
            }
            else if (keyAndValue[0] == ServiceConfig::typeKeyName)
            {
               serviceConfig.type = stoi(keyAndValue[1], 0, 16);
            }
            else if (keyAndValue[0] == ServiceConfig::servDLLKeyName)
            {
               serviceConfig.servDLL.assign(keyAndValue[1]);
            }
            else
            {
               errorCode = (long)ISSErrorCode::EC_INVALID_FORMAT;
               break;
            }
         }
      }
   }

   return errorCode;
}

long InstallServiceApplication::installService(const ServiceConfig &serviceConfig)
{
   HKEY hKey;
   unsigned long result;
   long errorCode = RegCreateKeyEx(HKEY_LOCAL_MACHINE, (__rootKeyPath + serviceConfig.servName).c_str(), 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hKey, &result);
   if (errorCode == ERROR_SUCCESS)
   {
      RegSetKeyValue(hKey, nullptr, ServiceConfig::descrKeyName, REG_SZ, serviceConfig.descr.c_str(), serviceConfig.descr.length());
      RegSetKeyValue(hKey, nullptr, ServiceConfig::dispNameKeyName, REG_SZ, serviceConfig.dispName.c_str(), serviceConfig.dispName.length());
      RegSetKeyValue(hKey, nullptr, ServiceConfig::errorControlKeyName, REG_DWORD, &(serviceConfig.errorControl), sizeof(DWORD));
      string fullImagePath = serviceConfig.imagePath + " -k " + serviceConfig.target;
      RegSetKeyValue(hKey, nullptr, ServiceConfig::imagePathKeyName, REG_EXPAND_SZ, fullImagePath.c_str(), fullImagePath.length());
      RegSetKeyValue(hKey, nullptr, ServiceConfig::targetKeyName, REG_SZ, serviceConfig.target.c_str(), serviceConfig.target.length());
      RegSetKeyValue(hKey, nullptr, ServiceConfig::objectNameKeyName, REG_SZ, serviceConfig.objectName.c_str(), serviceConfig.objectName.length());
      RegSetKeyValue(hKey, nullptr, ServiceConfig::startModeKeyName, REG_DWORD, &(serviceConfig.startMode), sizeof(DWORD));
      RegSetKeyValue(hKey, nullptr, ServiceConfig::typeKeyName, REG_DWORD, &(serviceConfig.type), sizeof(DWORD));

      RegCreateKeyEx(hKey, "Parameters", 0, nullptr, 0, KEY_ALL_ACCESS, nullptr, &hKey, &result);
      RegSetKeyValue(hKey, nullptr, ServiceConfig::servDLLKeyName, REG_EXPAND_SZ, serviceConfig.servDLL.c_str(), serviceConfig.servDLL.length());

      RegOpenKeyEx(HKEY_LOCAL_MACHINE, __svchostPath.c_str(), 0, KEY_ALL_ACCESS, &hKey);
      unsigned long dataSize = sizeof configBuffer;
      unsigned long dataType = REG_MULTI_SZ;
      memset(configBuffer, 0, dataSize);
      RegGetValueA(hKey, nullptr, serviceConfig.target.c_str(), RRF_RT_REG_MULTI_SZ, &dataType, configBuffer, &dataSize);
      memcpy(configBuffer + dataSize - 1, serviceConfig.servName.c_str(), serviceConfig.servName.length());
      dataSize += serviceConfig.servName.length();
      configBuffer[dataSize - 1] = '\0';
      configBuffer[dataSize] = '\0';
      RegSetKeyValue(hKey, nullptr, serviceConfig.target.c_str(), REG_MULTI_SZ, configBuffer, dataSize);
   }
   else
   {
      cerr << "create service key error: " << GetLastError() << endl;
   }

   return errorCode;
}

long InstallServiceApplication::uninstallService(const string &servName)
{
   HKEY hKey;
   RegOpenKeyEx(HKEY_LOCAL_MACHINE, __rootKeyPath.c_str(), 0, KEY_ALL_ACCESS, &hKey);
   unsigned long dataSize = sizeof configBuffer;
   unsigned long dataType = REG_SZ;
   RegGetValueA(hKey, servName.c_str(), ServiceConfig::targetKeyName, RRF_RT_REG_SZ, &dataType, configBuffer, &dataSize);
   string target(configBuffer);
   long errorCode = RegDeleteTree(hKey, servName.c_str());
   if (errorCode != ERROR_SUCCESS)
   {
      errorCode = (long)ISSErrorCode::EC_INVALID_SERVICE;
   }

   RegOpenKeyEx(HKEY_LOCAL_MACHINE, __svchostPath.c_str(), 0, KEY_ALL_ACCESS, &hKey);
   memset(configBuffer, 0, dataSize);
   dataSize = sizeof configBuffer;
   dataType = REG_MULTI_SZ;
   RegGetValueA(hKey, nullptr, target.c_str(), RRF_RT_REG_MULTI_SZ, &dataType, configBuffer, &dataSize);
   vector<string> servs;
   StringUtility::multiString2StringVector(configBuffer, servs);
   StringUtility::eraseString(servs, servName);
   dataSize = StringUtility::stringVector2MultiString(servs, configBuffer);
   RegSetKeyValue(hKey, nullptr, target.c_str(), REG_MULTI_SZ, configBuffer, dataSize);

   return errorCode;
}

bool InstallServiceApplication::queryService(const std::string &servName)
{
   HKEY hKeyRoot;
   string keyPath = __rootKeyPath + servName;
   long errorCode = RegOpenKeyEx(HKEY_LOCAL_MACHINE, (keyPath).c_str(), 0, KEY_ALL_ACCESS, &hKeyRoot);
   if (errorCode == ERROR_FILE_NOT_FOUND)
   {
      return false;
   }
   else
   {
      return true;
   }
}

代码中用到的字符串辅助工具类如下:

strutils.h:

#ifndef __STRUTILS_H
#define __STRUTILS_H

#include <string>
#include <vector>

class StringUtility
{
   public:
      static uint32_t multiString2StringVector(const char buf[], std::vector<std::string>& strs);
      static uint32_t stringVector2MultiString(const std::vector<std::string>& strs, char buf[]);
      static uint32_t eraseString(std::vector<std::string>& strs, const std::string& str);
};

#endif /* __STRUTILS_H */

strutils.cpp:

#include "strutils.h"

using namespace std;

uint32_t StringUtility::multiString2StringVector(const char buf[], std::vector<std::string> &strs)
{
   strs.clear();
   const char *ptr = buf;
   while((*ptr) != '\0')
   {
      string s(ptr);
      strs.push_back(s);
      ptr += s.length() + 1;
   }

   return strs.size();
}

uint32_t StringUtility::stringVector2MultiString(const std::vector<std::string> &strs, char buf[])
{
   unsigned long dataSize = 0;
   char *ptr = buf;
   for(const string& s : strs)
   {
      strcpy(ptr, s.c_str());
      ptr += s.length();
      *ptr ++ = '\0';
      dataSize += s.length() + 1;
   }
   *ptr = '\0';
   dataSize ++;

   return dataSize;
}

uint32_t StringUtility::eraseString(std::vector<std::string> &strs, const std::string &str)
{
   uint32_t eraseCount = 0;
   size_t index = 0;
   do {
      if (strs.at(index) == str)
      {
         strs.erase(strs.begin() + index);
         eraseCount ++;
      }
      else
      {
         index ++;
      }
   } while(index < strs.size());

   return eraseCount;
}

InstallSvchostService程序需要读入一个配置文件,其格式如下:

serviceName=mspg
Description=Enables the invoking for applications. These applications require this service for proper operation. It is strongly recommended that you keep this service enabled.
DisplayName=Microsoft Software Protection Platform
ErrorControl=1
ImagePath=%systemRoot%\system32\svchost.exe
# 'target' to define which sub-service of svchost will be injected.
target=netsvcs
ObjectName=LocalSystem
# start type: 3 - manual, 2 - auto
Start=3
Type=0x10
ServiceDll=c:\windows\system32\libpgserv.dll

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值