上一篇简要介绍了如何制作一个可被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

制作可被svchost调用的服务(下)相关推荐

  1. 实现在GET请求下调用WCF服务时传递对象(复合类型)参数

    WCF实现RESETFUL架构很容易,说白了,就是使WCF能够响应HTTP请求并返回所需的资源,如果有人不知道如何实现WCF支持HTTP请求的,可参见我之前的文章<实现jquery.ajax及原 ...

  2. Silverlight同步(Synchro“.NET研究”nous)调用WCF服务

    Silverlight的RIA应用中访问远端的WebService或WCF服务,都是通过异步线程模式调用的.在某些情况下我们的调用是需要同步进行,虽然Silverlight没有内置同步线程模式调用远端 ...

  3. svchost.exe启动服务原理

    svchost.exe本身只是作为服务宿主,并不实现任何服务功能,需要svchost.exe启动的服务以动态链接库形式实现,在安装这些服务时,把服务的可执行程序指向svchost.exe,启动这些服务 ...

  4. svchost.exe启动服务原理(如何查看系统服务究竟启动了哪个文件)

    引言: 本来是不想研究这些东西的,但是米老大指示要求禁用网上邻居,顺便研究一下. 其实禁用网上邻居,可以简单的从注册表禁用,不过这样太苍白无力了,既然做,就做强悍点,直接从服务入手,彻底kill网上邻 ...

  5. 【随记】动态调用web服务

    通常我们在程序中需要调用WebService时,都是通过"添加Web引用",让VS.NET环境来为我们生成服务代理,然后调用对应的Web服务.这样是使工作简单了,但是却和提供Web ...

  6. 大系统化小之后,微信如何解决大规模微服务下的难题?

    "大系统小做",微服务与腾讯的理念有一些相同的地方.本文整理自许家滔在2016年ArchSummit全球架构师峰会的演讲,分享了微信在微服务架构的实践中遇到的问题与解决方案. 背 ...

  7. 实现jquery.ajax及原生的XMLHttpRequest调用WCF服务的方法

    废话不多说,直接讲解实现步骤 一.首先我们需定义支持WEB HTTP方法调用的WCF服务契约及实现服务契约类(重点关注各attribute),代码如下: //IAddService.cs namesp ...

  8. WCF 入门之旅(4): 怎样用客户端调用WCF服务

    WCF 入门之旅(4): 怎样用客户端调用WCF服务 前面的demo已经能够跑起来,现在开始考虑用客户端来测试所写的应用了,首先用个普通的应用程序来调用所写的wcf服务吧.其实最后运行wcf服务后的页 ...

  9. 绑定服务调用本地服务中的方法

    如果想调用服务中的方法, 通过startService()是做不到的, 这时需要用bindService来解决. 下面的demo是在Activity中调用Service中的自定义方法---method ...

  10. linux c调用wcf服务,Silverlight+WCF实现跨域调用

    在这篇文章中,WCF扮演服务器,向外提供LoginVaild服务:Silverlight扮演客户端,调用WCF提供的LoginVaild服务.思路有了,下面进行代码实现. 数据库脚本实现 新建T_Us ...

最新文章

  1. 联想笔记本Ideapad(flex 2)进入BIOS设置U盘启动的详细步骤
  2. 用DataBindings属性绑定控件的值
  3. 自定义MyBatis
  4. matlab中如何添加注释
  5. html表白_HTML 表白网页
  6. 设计模式(四)--代理模式
  7. rabbitmq的相关知识
  8. 华为网络设备上的常用安全技术(一)
  9. 《Java程序设计》学期总结
  10. 用友云开发者中心助你上云系列之在线调试
  11. 虚拟机linux如何扩大内存吗,如何扩大Vmware虚拟机中Ubuntu系统磁盘空间的方法
  12. Python操作文件,报FileNotFoundError: [Error 2] No such file or directory错误
  13. java配置文件强制更新_对Java配置文件Properties的读取、写入与更新操作
  14. 基于Spring Security的认证授权_应用详解_会话管理_Spring Security OAuth2.0认证授权---springcloud工作笔记129
  15. DevExpress v18.1新版亮点——WPF篇(一)
  16. Odoo12功能模块文档整理
  17. 计算机用几个字节储存,一个文字在计算机中用两个字节来储存。()
  18. 全国计算机二级flash,教你如何在Flash当中制作插按钮动画
  19. DANDELION 病毒
  20. 【网络运维与安全岗位】月薪2.5w,您还不知道的前景!

热门文章

  1. 毕设过程中使用WPS的自定义生成目录中混入图片等非相关元素
  2. [转载]深入理解vue中的slot与slot-scope
  3. 从传课网论公司是否要卖给资方控股
  4. OpenLayers 5 使用turf.js渲染克里金插值计算的等值面
  5. 用Python绘制折线图(下)
  6. MapReduce计算PMI
  7. 《ROS2机器人建模URDF》8.2RVIZ2可视化移动机器人模型
  8. 怎样查看计算机注册表上的游戏,win7 32位旗舰版电脑中如何通过注册表修复游戏登陆问题...
  9. linux 7查看网络流量,CentOS7 监控网络流量
  10. 小程序容器对政务服务平台建设的帮助