建立SvcHost.exe呼叫的服務原理與實踐(2)
// SvcHostDLL.cpp : Demo for a service dll used by svchost.exe to host it.
//
// for detail comment see articles.
// by bingle_at_email.com.cn
// www.BingleSite.net
//
/* save following as a .def file to export function, only ServiceMain is needed.
other used to install & uninstall service.
or use /EXPORT: link option to export them.
EXPORTS
ServiceMain
InstallService
UninstallService
RundllUninstallA
RundllInstallA
*/
/*
To compile & link:
cl /MD /GX /LD svchostdll.cpp /link
advapi32.lib /DLL /base:0x71000000 /export:ServiceMain
/EXPORT:RundllUninstallA /EXPORT:RundllInstallA
/EXPORT:InstallService /EXPORT:UninstallService
*/
//
// Articles:
// 1. HOWTO Create a service dll used by svchost.exe by bingle, at: http://www.BingleSite.net/article/svchost-dll-service.html
// 2. Inside Win32 Services, Part 2 by: Mark Russinovich, at: http://www.winnetmag.com/Articles/Index.cfm?ArticleID=8943&pg=3
// 3. Platform SDK: Tools - Rundll32, at: http://msdn.microsoft.com/library/en-us/tools/tools/rundll32.asp
#include <stdio.h>
#include <time.h>
#include <assert.h>
#include <windows.h>
#define DEFAULT_SERVICE "IPRIP"
#define MY_EXECUTE_NAME "SvcHostDLL.exe"
//main service process function void __stdcall ServiceMain( int argc, wchar_t* argv[] );
//report service stat to the service control manager int TellSCM( DWORD dwState, DWORD dwExitCode, DWORD dwProgress );
//service control handler, call back by service control manager void __stdcall ServiceHandler( DWORD dwCommand );
//RealService just create a process int RealService(char *cmd, int bInteract);
//Install this dll as a Service host by svchost.exe, service name is given by caller int InstallService(char *name);
//unInstall a Service, be CARE FOR call this to delete a service int UninstallService(char *name);
//Install this dll as a Service host by svchost.exe, used by RUNDLL32.EXE to call void CALLBACK RundllInstallA(HWND hwnd, HINSTANCE hinst, char *param, int nCmdShow);
//unInstall a Service used by RUNDLL32.EXE to call, be CARE FOR call this to delete a service void CALLBACK RundllUninstallA(HWND hwnd, HINSTANCE hinst, char *param, int nCmdShow);
//output the debug infor into log file(or stderr if a console program call me) & DbgPrint void OutputString( char *lpFmt, ... );
//dll module handle used to get dll path in InstallService HANDLE hDll = NULL;
//Service HANDLE & STATUS used to get service state SERVICE_STATUS_HANDLE hSrv;
DWORD dwCurrState;
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hDll = hModule;
#ifdef _DEBUG
AllocConsole();
OutputString("SvcHostDLL: DllMain called DLL_PROCESS_ATTACH");
break;
case DLL_THREAD_ATTACH:
OutputString("SvcHostDLL: DllMain called DLL_THREAD_ATTACH");
case DLL_THREAD_DETACH:
OutputString("SvcHostDLL: DllMain called DLL_THREAD_DETACH");
case DLL_PROCESS_DETACH:
TellSCM( SERVICE_STOP_PENDING, 0, 0 );
Sleep(1500);
TellSCM( SERVICE_STOPPED, 0, 0 );
OutputString("SvcHostDLL: DllMain called DLL_PROCESS_DETACH");
#endif
break;
}
return TRUE;
}
void __stdcall ServiceMain( int argc, wchar_t* argv[] )
{
// DebugBreak();
char svcname[256];
strncpy(svcname, (char*)argv[0], sizeof svcname); //it's should be unicode, but if it's ansi we do it well
wcstombs(svcname, argv[0], sizeof svcname);
OutputString("SvcHostDLL: ServiceMain(%d, %s) called", argc, svcname);
hSrv = RegisterServiceCtrlHandler( svcname, (LPHANDLER_FUNCTION)ServiceHandler );
if( hSrv == NULL )
{
OutputString("SvcHostDLL: RegisterServiceCtrlHandler %S failed", argv[0]);
return;
}else FreeConsole();
TellSCM( SERVICE_START_PENDING, 0, 1 );
TellSCM( SERVICE_RUNNING, 0, 0 );
// call Real Service function noew
if(argc > 1)
strncpy(svcname, (char*)argv[1], sizeof svcname),
wcstombs(svcname, argv[1], sizeof svcname);
RealService(argc > 1 ? svcname : MY_EXECUTE_NAME, argc > 2 ? 1 : 0);
do{
Sleep(10);//not quit until receive stop command, otherwise the service will stop
}while(dwCurrState != SERVICE_STOP_PENDING && dwCurrState != SERVICE_STOPPED);
OutputString("SvcHostDLL: ServiceMain done");
return;
}
int TellSCM( DWORD dwState, DWORD dwExitCode, DWORD dwProgress )
{
SERVICE_STATUS srvStatus;
srvStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS;
srvStatus.dwCurrentState = dwCurrState = dwState;
srvStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE | SERVICE_ACCEPT_SHUTDOWN;
srvStatus.dwWin32ExitCode = dwExitCode;
srvStatus.dwServiceSpecificExitCode = 0;
srvStatus.dwCheckPoint = dwProgress;
srvStatus.dwWaitHint = 3000;
return SetServiceStatus( hSrv, &srvStatus );
}
void __stdcall ServiceHandler( DWORD dwCommand )
{
// not really necessary because the service stops quickly
switch( dwCommand )
{
case SERVICE_CONTROL_STOP:
TellSCM( SERVICE_STOP_PENDING, 0, 1 );
OutputString("SvcHostDLL: ServiceHandler called SERVICE_CONTROL_STOP");
Sleep(10);
TellSCM( SERVICE_STOPPED, 0, 0 );
break;
case SERVICE_CONTROL_PAUSE:
TellSCM( SERVICE_PAUSE_PENDING, 0, 1 );
OutputString("SvcHostDLL: ServiceHandler called SERVICE_CONTROL_PAUSE");
TellSCM( SERVICE_PAUSED, 0, 0 );
break;
case SERVICE_CONTROL_CONTINUE:
TellSCM( SERVICE_CONTINUE_PENDING, 0, 1 );
OutputString("SvcHostDLL: ServiceHandler called SERVICE_CONTROL_CONTINUE");
TellSCM( SERVICE_RUNNING, 0, 0 );
break;
case SERVICE_CONTROL_INTERROGATE:
OutputString("SvcHostDLL: ServiceHandler called SERVICE_CONTROL_INTERROGATE");
TellSCM( dwCurrState, 0, 0 );
break;
case SERVICE_CONTROL_SHUTDOWN:
OutputString("SvcHostDLL: ServiceHandler called SERVICE_CONTROL_SHUTDOWN");
TellSCM( SERVICE_STOPPED, 0, 0 );
break;
}
}
//RealService just create a process
int RealService(char *cmd, int bInteract)
{
OutputString("SvcHostDLL: RealService called '%s' %s", cmd, bInteract ? "Interact" : "");
STARTUPINFO si = {0};
PROCESS_INFORMATION pi;
si.cb = sizeof si;
if(bInteract) si.lpDesktop = "WinSta0\\Default";
if(!CreateProcess(NULL, cmd, NULL, NULL, false, 0, NULL, NULL, &si, &pi))
OutputString("SvcHostDLL: CreateProcess(%s) error:%d", cmd, GetLastError());
else OutputString("SvcHostDLL: CreateProcess(%s) to %d", cmd, pi.dwProcessId);
return 0;
}
int InstallService(char *name)
{
// Open a handle to the SC Manager database.
int rc = 0;
HKEY hkRoot = HKEY_LOCAL_MACHINE, hkParam = 0;
SC_HANDLE hscm = NULL, schService = NULL;
try{
char buff[500];
char *svcname = DEFAULT_SERVICE;
if(name && name[0]) svcname = name;
//query svchost setting
char *ptr, *pSvchost = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Svchost";
rc = RegOpenKeyEx(hkRoot, pSvchost, 0, KEY_QUERY_VALUE, &hkRoot);
if(ERROR_SUCCESS != rc)
{
OutputString("RegOpenKeyEx(%s) KEY_QUERY_VALUE error %d.", pSvchost, rc);
throw "";
}
DWORD type, size = sizeof buff;
rc = RegQueryValueEx(hkRoot, "netsvcs", 0, &type, (unsigned char*)buff, &size);
RegCloseKey(hkRoot);
SetLastError(rc);
if(ERROR_SUCCESS != rc)
throw "RegQueryValueEx(Svchost\\netsvcs)";
for(ptr = buff; *ptr; ptr = strchr(ptr, 0)+1)
if(stricmp(ptr, svcname) == 0) break;
if(*ptr == 0)
{
OutputString("you specify service name not in Svchost\\netsvcs, must be one of following:");
for(ptr = buff; *ptr; ptr = strchr(ptr, 0)+1)
OutputString(" - %s", ptr);
throw "";
}
//install service
hscm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hscm == NULL)
throw "OpenSCManager()";
char *bin = "%SystemRoot%\\System32\\svchost.exe -k netsvcs";
schService = CreateService(
hscm,// SCManager database
svcname, // name of service
NULL, // service name to display
SERVICE_ALL_ACCESS,// desired access
SERVICE_WIN32_SHARE_PROCESS, // service type
SERVICE_AUTO_START, // start type
SERVICE_ERROR_NORMAL, // error control type
bin,// service's binary
NULL, // no load ordering group
NULL, // no tag identifier
NULL, // no dependencies
NULL, // LocalSystem account
NULL); // no password
if (schService == NULL)
{
OutputString("CreateService(%s) error %d", svcname, rc = GetLastError());
throw "";
}
OutputString("CreateService(%s) SUCCESS. Config it", svcname);
CloseServiceHandle(schService);
CloseServiceHandle(hscm);
//config service
hkRoot = HKEY_LOCAL_MACHINE;
strncpy(buff, "SYSTEM\\CurrentControlSet\\Services\\", sizeof buff);
strncat(buff, svcname, 100);
rc = RegOpenKeyEx(hkRoot, buff, 0, KEY_ALL_ACCESS, &hkRoot);
if(ERROR_SUCCESS != rc)
{
OutputString("RegOpenKeyEx(%s) KEY_SET_VALUE error %d.", svcname, rc);
throw "";
}
rc = RegCreateKey(hkRoot, "Parameters", &hkParam);
SetLastError(rc);
if(ERROR_SUCCESS != rc)
throw "RegCreateKey(Parameters)";
if(!GetModuleFileName(HMODULE(hDll), buff, sizeof buff))
throw "GetModuleFileName() get dll path";
rc = RegSetValueEx(hkParam, "ServiceDll", 0, REG_EXPAND_SZ, (unsigned char*)buff, strlen(buff)+1);
SetLastError(rc);
if(ERROR_SUCCESS != rc)
throw "RegSetValueEx(ServiceDll)";
OutputString("Config service %s ok.", svcname);
}catch(char *str)
{
if(str && str[0])
{
rc = GetLastError();
OutputString("%s error %d", str, rc);
}
}
RegCloseKey(hkRoot);
RegCloseKey(hkParam);
CloseServiceHandle(schService);
CloseServiceHandle(hscm);
return rc;
}
/*
used to install by rundll32.exe
Platform SDK: Tools - Rundll32
The Run DLL utility (Rundll32.exe) included in Windows enables you to call functions exported from a 32-bit DLL. These functions must have the following syntax:
*/
void CALLBACK RundllInstallA(
HWND hwnd,// handle to owner window
HINSTANCE hinst, // instance handle for the DLL
char *param,// string the DLL will parse
int nCmdShow // show state
)
{
InstallService(param);
}
int UninstallService(char *name)
{
int rc = 0;
SC_HANDLE schService;
SC_HANDLE hscm;
__try{
hscm = OpenSCManager(NULL, NULL, SC_MANAGER_ALL_ACCESS);
if (hscm == NULL)
{
OutputString("OpenSCManager() error %d", rc = GetLastError() );
return rc;
}
char *svcname = DEFAULT_SERVICE;
if(name && name[0]) svcname = name;
schService = OpenService(hscm, svcname, DELETE);
if (schService == NULL)
{
OutputString("OpenService(%s) error %d", svcname, rc = GetLastError() );
return rc;
}
if (!DeleteService(schService) )
{
OutputString("OpenService(%s) error %d", svcname, rc = GetLastError() );
return rc;
}
OutputString("DeleteService(%s) SUCCESS.", svcname);
}__except(1)
{
OutputString("Exception Catched 0x%X", GetExceptionCode());
}
CloseServiceHandle(schService);
CloseServiceHandle(hscm);
return rc;
}
/*
used to uninstall by rundll32.exe
Platform SDK: Tools - Rundll32
The Run DLL utility (Rundll32.exe) included in Windows enables you to call functions exported from a 32-bit DLL. These functions must have the following syntax:
*/
void CALLBACK RundllUninstallA(
HWND hwnd,// handle to owner window
HINSTANCE hinst, // instance handle for the DLL
char *param,// string the DLL will parse
int nCmdShow // show state
)
{
UninstallService(param);
}
//output the debug infor into log file & DbgPrint
void OutputString( char *lpFmt, ... )
{
char buff[1024];
va_list arglist;
va_start( arglist, lpFmt );
_vsnprintf( buff, sizeof buff, lpFmt, arglist );
va_end( arglist );
DWORD len;
HANDLE herr = GetStdHandle(STD_OUTPUT_HANDLE);
if(herr != INVALID_HANDLE_VALUE)
{
WriteFile(herr, buff, strlen(buff), &len, NULL);
WriteFile(herr, "\r\n", 2, &len, NULL);
}else
{
FILE *fp = fopen("SvcHost.DLL.log", "a");
if(fp)
{
char date[20], time[20];
fprintf(fp, "%s %s - %s\n", _strdate(date), _strtime(time), buff);
if(!stderr) fclose(fp);
}
}
OutputDebugString(buff);
}
相關文章
- 建立SvcHost.exe呼叫的服務原理與實踐(1)
- Istio實踐(2)-流量控制及服務間呼叫
- GRPC 服務呼叫實踐(一)RPC
- Node 呼叫 dubbo 服務的探索及實踐
- Redis核心原理與實踐--事務實踐與原始碼分析Redis原始碼
- 微服務快取原理與最佳實踐微服務快取
- 微服務~Eureka實現的服務註冊與發現及服務之間的呼叫微服務
- 資訊保安原理與實踐(第2版)
- OpenFeign 服務註冊和呼叫原理
- ITIL 服務檯:ITSM幫助員工建立實踐
- RocketMQ的原理與實踐MQ
- 微服務實踐k8s&dapr開發部署實驗(1)服務呼叫微服務K8S
- 服務註冊與發現的原理和實現
- 服務API版本控制設計與實踐API
- 使用dubbo+zookeeper釋出服務與呼叫服務
- eureka實現服務之間的呼叫
- Mysql事務原理與最佳化最佳實踐MySql
- 微服務5:服務註冊與發現(實踐篇)微服務
- angr原理與實踐(一)——原理
- springcloud(三):服務提供與呼叫SpringGCCloud
- OpenFeign 服務呼叫與負載負載
- Webpack原理與實踐Web
- Flutter原理與美團的實踐Flutter
- VS2013建立和呼叫Web服務Web
- 微服務實踐手冊-服務的拆分策略微服務
- Laravel 服務容器實現原理Laravel
- Docker容器的原理與實踐 (下)Docker
- MelGan原理與實踐篇
- Vue CLI 原理與實踐Vue
- Apollo GraphQL 服務端實踐服務端
- Nacos服務註冊與發現的原理
- 分散式事務與Seate框架(2)——Seata實踐分散式框架
- 分散式資料庫事務故障恢復的原理與實踐分散式資料庫
- YARP實現Dapr服務呼叫的反向代理
- 微服務呼叫鏈基本原理與使用微服務
- grpc實戰——服務端流式呼叫RPC服務端
- 一文搞懂服務註冊發現的原理與實現
- java版b2b2c社交電商spring cloud分散式微服務-服務提供與呼叫JavaSpringCloud分散式微服務