创建SvcHost.exe调用的服务原理与实践

HDI盲埋孔设计规范:高速PCB信号完整性落地指南 盲埋孔是高密度互连(HDI)PCB实现高速信号完整性的关键技术,其本质是通过控制过孔stub长度、优化回流路径和提升布线密度,解决GHz级信号在传统通孔结构下出现的谐振、串扰与EMI超标问题。其设计核心在于叠层物理约束、电气参数建模与工艺能力协同,涉及stub长度计算、反焊盘尺寸推导、孔壁粗糙度Rz控制等关键指标。广泛应用于DDR4、PCIe Gen4、USB3.2等高速接口的PCB设计中,尤其在车载ADAS、5G基站及FPGA载板等对SI/PI要求严苛的场景中成为刚性门槛。 阅读详情
1. 多个服务共享一个Svchost.exe进程利与弊

windows 系统服务分为独立进程和共享进程两种,在windows NT时只有服务器管理器SCM(Services.exe)有多个共享服务,随着系统内置服务的增加,在windows 2000中ms又把很多服务做成共享方式,由svchost.exe启动。windows 2000一般有2个svchost进程,一个是RPCSS(Remote Procedure Call)服务进程,另外一个则是由很多服务共享的一个svchost.exe。而在windows XP中,则一般有4个以上的svchost.exe服务进程,windows 2003 server中则更多,可以看出把更多的系统内置服务以共享进程方式由svchost启动是ms的一个趋势。这样做在一定程度上减少了系统资源的消耗,不过也带来一定的不稳定因素,因为任何一个共享进程的服务因为错误退出进程就会导致整个进程中的所有服务都退出。另外就是有一点安全隐患,首先要介绍一下svchost.exe的实现机制。


2. Svchost原理

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

那么svchost如何知道某一服务是由哪个动态链接库负责呢?这不是由服务的可执行程序路径中的参数部分提供的,而是服务在注册表中的参数设置的,注册表中服务下边有一个Parameters子键其中的ServiceDll表明该服务由哪个动态链接库负责。并且所有这些服务动态链接库都必须要导出一个ServiceMain()函数,用来处理服务任务。

例如rpcss(Remote Procedure Call)在注册表中的位置是  HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/RpcSs,它的参数子键Parameters里有这样一项:
"ServiceDll"=REG_EXPAND_SZ:"%SystemRoot%/system32/rpcss.dll"
当启动rpcss服务时,svchost就会调用rpcss.dll,并且执行其ServiceMain()函数执行具体服务。

既然这些服务是使用共享进程方式由svchost启动的,为什么系统中会有多个svchost进程呢?ms把这些服务分为几组,同组服务共享一个svchost进程,不同组服务使用多个svchost进程,组的区别是由服务的可执行程序后边的参数决定的。

例如rpcss在注册表中 HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/RpcSs 有这样一项:
"ImagePath"=REG_EXPAND_SZ:"%SystemRoot%/system32/svchost -k rpcss"
因此rpcss就属于rpcss组,这在服务管理控制台也可以看到。

svchost的所有组和组内的所有服务都在注册表的如下位置: HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Svchost,例如windows 2000共有4组rpcss、netsvcs、wugroup、BITSgroup,其中最多的就是netsvcs=REG_MULTI_SZ:EventSystem.Ias.Iprip.Irmon.Netman.Nwsapagent.Rasauto.Rasman.Remoteaccess.SENS.Sharedaccess.Tapisrv.Ntmssvc.wzcsvc..

在启动一个svchost.exe负责的服务时,服务管理器如果遇到可执行程序内容ImagePath已经存在于服务管理器的映象库中,就不在启动第2个进程svchost,而是直接启动服务。这样就实现了多个服务共享一个svchost进程。


3. Svchost代码

现在我们基本清楚svchost的原理了,但是要自己写一个DLL形式的服务,由svchost来启动,仅有上边的信息还有些问题不是很清楚。比如我们在导出的ServiceMain()函数中接收的参数是ANSI还是Unicode?我们是否需要调用RegisterServiceCtrlHandler和StartServiceCtrlDispatcher来注册服务控制及调度函数?

这些问题要通过查看svchost代码获得。下边的代码是windows 2000+ service pack 4 的svchost反汇编片段,可以看出svchost程序还是很简单的。

主函数首先调用ProcCommandLine()对命令行进行分析,获得要启动的服务组,然后调用SvcHostOptions()查询该服务组的选项和服务组的所有服务,并使用一个数据结构 svcTable 来保存这些服务及其服务的DLL,然后调用PrepareSvcTable() 函数创建SERVICE_TABLE_ENTRY 结构,把所有处理函数SERVICE_MAIN_FUNCTION 指向自己的一个函数FuncServiceMain(),最后调用API StartServiceCtrlDispatcher() 注册这些服务的调度函数。

; =============================== Main Funcion ===========================================
.text:010010B8                 public start
.text:010010B8 start           proc near
.text:010010B8                 push    esi
.text:010010B9                 push    edi
.text:010010BA                 push    offset sub_1001EBA ; lpTopLevelExceptionFilter
.text:010010BF                 xor     edi, edi
.text:010010C1                 call    ds:SetUnhandledExceptionFilter
.text:010010C7                 push    1               ; uMode
.text:010010C9                 call    ds:SetErrorMode
.text:010010CF                 call    ds:GetProcessHeap
.text:010010D5                 push    eax
.text:010010D6                 call    sub_1001142
.text:010010DB                 mov     eax, offset dword_1003018
.text:010010E0                 push    offset unk_1003000 ; lpCriticalSection
.text:010010E5                 mov     dword_100301C, eax
.text:010010EA                 mov     dword_1003018, eax
.text:010010EF                 call    ds:InitializeCriticalSection
.text:010010F5                 call    ds:GetCommandLineW
.text:010010FB                 push    eax             ; lpString
.text:010010FC                 call    ProcCommandLine
.text:01001101                 mov     esi, eax
.text:01001103                 test    esi, esi
.text:01001105                 jz      short lab_doservice
.text:01001107                 push    esi
.text:01001108                 call    SvcHostOptions
.text:0100110D                 call    PrepareSvcTable
.text:01001112                 mov     edi, eax        ; SERVICE_TABLE_ENTRY returned
.text:01001114                 test    edi, edi
.text:01001116                 jz      short loc_1001128
.text:01001118                 mov     eax, [esi+10h]
.text:0100111B                 test    eax, eax
.text:0100111D                 jz      short loc_1001128
.text:0100111F                 push    dword ptr [esi+14h] ; dwCapabilities
.text:01001122                 push    eax             ; int
.text:01001123                 call    InitializeSecurity
.text:01001128
.text:01001128 loc_1001128:                            ; CODE XREF: start+5Ej
.text:01001128                                         ; start+65j
.text:01001128                 push    esi             ; lpMem
.text:01001129                 call    HeapFreeMem
.text:0100112E
.text:0100112E lab_doservice:                          ; CODE XREF: start+4Dj
.text:0100112E                 test    edi, edi
.text:01001130                 jz      ExitProgram
.text:01001136                 push    edi             ; lpServiceStartTable
.text:01001137                 call    ds:StartServiceCtrlDispatcherW
.text:0100113D                 jmp     ExitProgram
.text:0100113D start           endp
; =============================== Main Funcion end ===========================================


由于svchost为该组的所有服务都注册了svchost中的一个处理函数,因此每次启动任何一个服务时,服务管理器SCM都会调用FuncServiceMain() 这个函数。这个函数使用 svcTable 查询要启动的服务使用的DLL,调用DLL导出的ServiceMain()函数来启动服务,然后返回。

; ============================== FuncServiceMain() ===========================================
.text:01001504 FuncServiceMain proc near               ; DATA XREF: PrepareSvcTable+44o
.text:01001504
.text:01001504 arg_0           = dword ptr  8
.text:01001504 arg_4           = dword ptr  0Ch
.text:01001504
.text:01001504                 push    ecx
.text:01001505                 mov     eax, [esp+arg_4]
.text:01001509                 push    ebx
.text:0100150A                 push    ebp
.text:0100150B                 push    esi
.text:0100150C                 mov     ebx, offset unk_1003000
.text:01001511                 push    edi
.text:01001512                 mov     edi, [eax]
.text:01001514                 push    ebx
.text:01001515                 xor     ebp, ebp
.text:01001517                 call    ds:EnterCriticalSection
.text:0100151D                 xor     esi, esi
.text:0100151F                 cmp     dwGroupSize, esi
.text:01001525                 jbe     short loc_1001566
.text:01001527                 and     [esp+10h], esi
.text:0100152B
.text:0100152B loc_100152B:                            ; CODE XREF: FuncServiceMain+4Aj
.text:0100152B                 mov     eax, svcTable
.text:01001530                 mov     ecx, [esp+10h]
.text:01001534                 push    dword ptr [eax+ecx]
.text:01001537                 push    edi
.text:01001538                 call    ds:lstrcmpiW
.text:0100153E                 test    eax, eax
.text:01001540                 jz      short StartThis
.text:01001542                 add     dword ptr [esp+10h], 0Ch
.text:01001547                 inc     esi
.text:01001548                 cmp     esi, dwGroupSize
.text:0100154E                 jb      short loc_100152B
.text:01001550                 jmp     short loc_1001566
.text:01001552 ; =================================================
.text:01001552
.text:01001552 StartThis:                              ; CODE XREF: FuncServiceMain+3Cj
.text:01001552                 mov     ecx, svcTable
.text:01001558                 lea     eax, [esi+esi*2]
.text:0100155B                 lea     eax, [ecx+eax*4]
.text:0100155E                 push    eax
.text:0100155F                 call    GetDLLServiceMain
.text:01001564                 mov     ebp, eax        ; dll ServiceMain Function address
.text:01001566
.text:01001566 loc_1001566:                            ; CODE XREF: FuncServiceMain+21j
.text:01001566                                         ; FuncServiceMain+4Cj
.text:01001566                 push    ebx
.text:01001567                 call    ds eaveCriticalSection
.text:0100156D                 test    ebp, ebp
.text:0100156F                 jz      short loc_100157B
.text:01001571                 push    [esp+10h+arg_4]
.text:01001575                 push    [esp+14h+arg_0]
.text:01001579                 call    ebp
.text:0100157B
.text:0100157B loc_100157B:                            ; CODE XREF: FuncServiceMain+6Bj
.text:0100157B                 pop     edi
.text:0100157C                 pop     esi
.text:0100157D                 pop     ebp
.text:0100157E                 pop     ebx
.text:0100157F                 pop     ecx
.text:01001580                 retn    8
.text:01001580 FuncServiceMain endp ; sp = -8
; ============================== FuncServiceMain() end ========================================


由于svchost已经调用了StartServiceCtrlDispatcher来服务调度函数,因此我们在实现DLL实现时就不用了,这主要是因为一个进程只能调用一次StartServiceCtrlDispatcher API。但是需要用 RegisterServiceCtrlHandler 来注册响应控制请求的函数。最后我们的DLL接收的都是unicode字符串。

由于这种服务启动后由svchost加载,不增加新的进程,只是svchost的一个DLL,而且一般进行审计时都不会去HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Svchost 检查服务组是否变化,就算去检查,也不一定能发现异常,因此如果添加一个这样的DLL后门,伪装的好,是比较隐蔽的。


4. 安装服务与设置
要通过svchost调用来启动的服务,就一定要在HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Svchost下有该服务名,这可以通过如下方式来实现:
1) 添加一个新的服务组,在组里添加服务名
2) 在现有组里添加服务名
3) 直接使用现有服务组里的一个服务名,但本机没有安装的服务
4) 修改现有服务组里的现有服务,把它的ServiceDll指向自己

其中前两种可以被正常服务使用,如使用第1种方式,启动其服务要创建新的svchost进程;第2种方式如果该组服务已经运行,安装后不能立刻启动服务,因为svchost启动后已经把该组信息保存在内存里,并调用API StartServiceCtrlDispatcher() 为该组所有服务注册了调度处理函数,新增加的服务不能再注册调度处理函数,需要重起计算机或者该组的svchost进程。而后两种可能被后门使用,尤其是最后一种,没有添加服务,只是改了注册表里一项设置,从服务管理控制台又看不出来,如果作为后门还是很隐蔽的。比如EventSystem服务,缺省是指向es.dll,如果把ServiceDll改为EventSystem.dll就很难发现。

因此服务的安装除了调用CreateService()创建服务之外,还需要设置服务的ServiceDll,如果使用前2种还要设置svchost的注册表选项,在卸载时也最好删除增加的部分。

具体代码参见后边的附例(使用的是方法3)。

注: ImagePath 和ServiceDll 是ExpandString不是普通字符串。因此如果使用.reg文件安装时要注意。


5. DLL服务实现
DLL程序的编写比较简单,只要实现一个ServiceMain()函数和一个服务控制程序,在ServiceMain()函数里用RegisterServiceCtrlHandler()注册服务控制程序,并设置服务的运行状态就可以了。

另外,因为此种服务的安装除了正常的CreateService()之外,还要进行其他设置,因此最好实现安装和卸载函数。

为了方便安装,实现的代码提供了InstallService()函数进行安装,这个函数可以接收服务名作为参数(如果不提供参数,就使用缺省的iprip),如果要安装的服务不在svchost的netsvcs组里安装就会失败;如果要安装的服务已经存在,安装也会失败;安装成功后程序会配置服务的ServiceDll为当前Dll。提供的UninstallService()函数,可以删除任何函数而没有进行任何检查。

为了方便使用rundll32.exe进行安装,还提供了RundllInstallA()和RundllUninstallA()分别调用InstallService()及UninstallService()。因为rundll32.exe使用的函数原型是:
void CALLBACK FunctionName(
  HWND hwnd,        // handle to owner window
  HINSTANCE hinst,  // instance handle for the DLL
  LPTSTR lpCmdLine, // string the DLL will parse
  int nCmdShow      // show state
);
对应的命令行是rundll32 DllName,FunctionName [Arguments]

DLL服务本身只是创建一个进程,该程序命令行就是启动服务时提供的第一个参数,如果未指定就使用缺省的svchostdll.exe。启动服务时如果提供第二个参数,创建的进程就是和桌面交互的。

具体代码参见后边的附例8,源代码和DLL文件请到 http://www.binglesite.net下载。

//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, ... );


6. 代码使用
C:/>tlist -s
   0 System Process
   8 System
240 services.exe    Svcs:  Browser,Dhcp,dmserver,Dnscache,Eventlog,lanmanserver,lanmanworkstation, LmHosts,PlugPlay,ProtectedStorage,TrkWks,Wmi
504 svchost.exe     Svcs:  RpcSs
1360 svchost.exe     Svcs:  EventSystem,Netman,RasMan,SENS,TapiSrv

C:/>rundll32 svchostdll.dll,RundllInstall abcd
SvcHostDLL: DllMain called DLL_PROCESS_ATTACH
you specify service name not in Svchost/netsvcs, must be one of following:
- EventSystem
- Ias
- Iprip
- Irmon
- Netman
- Nwsapagent
- Rasauto
- Rasman
- Remoteaccess
- SENS
- Sharedaccess
- Tapisrv
- Ntmssvc
- wzcsvc

C:/>rundll32 svchostdll.dll,RundllInstall IPRIP
SvcHostDLL: DllMain called DLL_PROCESS_ATTACH
CreateService(IPRIP) SUCCESS. Config it
Config service IPRIP ok.

C:/>sc start iprip "cmd /k whoami" 1
NT AUTHORITY/SYSTEM

SvcHostDLL: ServiceMain(3, IPRIP) called
SvcHostDLL: RealService called 'cmd /k whoami' Interact
SvcHostDLL: CreateProcess(cmd /k whoami) to 640

C:/>tlist -s
   0 System Process
   8 System
240 services.exe    Svcs:  Browser,Dhcp,dmserver,Dnscache,Eventlog,lanmanserver,lanmanworkstation, LmHosts,PlugPlay,ProtectedStorage,TrkWks,Wmi
504 svchost.exe     Svcs:  RpcSs
640 cmd.exe         Title: C:/WINNT/System32/cmd.exe
1360 svchost.exe     Svcs:  EventSystem,Netman,RasMan,SENS,TapiSrv,IPRIP

C:/>net stop iprip
The IPRIP service was stopped successfully.

C:/>rundll32 svchostdll.dll,RundllUninstall iprip
DeleteService(IPRIP) SUCCESS.


7. 参考

Platform SDK: Tools - Rundll32
1) Inside Win32 Services, Part 2 by: Mark Russinovich, at: http://www.winnetmag.com/Article ... cleID=8943&pg=3
2) Platform SDK: Tools - Rundll32, at: http://msdn.microsoft.com/library/en-us/tools/tools/rundll32.asp

            2003/8


8. 代码
// 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/Article ... cleID=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, " arameters", &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);
} 
初识colmap COLMAP是一款开源的计算机视觉软件,主要用于从一系列二维图像中进行三维重建。它全称为“COLLISION-MAPping”,是一个高度集成的Structure-from-Motion (SfM) 和 Multi-View Stereo (MVS) 管道工具,由斯坦福大学开发和维护。COLMAP的主要功能包括特征检测与匹配、增量式SfM、多视图立体匹配以及优化。它能够从无序或有序的二维照片集合中恢复出三维场景的几何结构(点云)以及每张图像对应的相机姿态。 阅读详情

相关推荐

水文地质人必备:用Origin Pro 2023手把手教你搞定Piper三线图(附数据模板)

本文详细介绍了如何使用Origin Pro 2023绘制专业级Piper三线图,适用于水文地质数据分析。从数据准备、百分比计算到图表参数设置,提供全流程指导,并附赠数据模板和样式预设文件,帮助用户快速掌握这一水文地球化学分析的核心工具。

weixin_30568591的博客 533

Svchost.exe进程详解及Svchost.exe病毒清除方法

这几天在宿舍上网的时候其他的舍友反映网络特别的卡。不知道是什么原因。然后我就发现自己的电脑有一个程序,自己走流量而且每秒能达100kb以上对于宿舍8个人共用的一个4M的网线来说已经算是占了好大一部分网速了。在金山流量监控上发现这个程序叫Svchost.exe。 这是一个什么程序呢。然后我就尝试禁用。但我发现win7的任务管理器的进程中是找不到这个进程的。然后我通过上网了解了这个进程。 s

韩义--廊坊师范学院信息技术提高班第九期 4万+

Pi0 项目复现及项目问题解决方案(全网抢先发布~)

Pi0 项目复现及项目问题解决方案(全网抢先发布~)

m0_68167062的博客 2262

实战还原--从大黄蜂样本到域控管理员技术解析

0 前言实战案例还原《BumbleBee Roasts Its Way To Domain Admin》一文详细的描述了一次渗透案例,但其文章组织架构建立在ATT&CK框架上,而不是按照时间线逻辑来组织,因此对于渗透人员了解学习其前后过程有些困难,特此梳理一番,按照时间线还原实战。《BumbleBee Roasts Its Way To Domain Admin》原文链接1 第一天(Da...

渗透测试研究中心 778

【Unity游戏开发】SDK接入与集成——小白入门篇

一、简介   通常一款游戏开发到后期,一般都会涉及到第三方SDK的接入与集成,对于不熟悉SDK接入的同学来说,接SDK每次都是云里雾里,而熟悉SDK接入的同学又觉得不断地重复做接入SDK工作这样没有成就感,太尼玛无聊了(Android渠道一弄就十几个,直接吐血)。其实通常情况下接入SDK都是很简单的一个过程,本系列博客就让马三和大家从小白开始,从零基础开始学习如何接入SDK以及一些常见的SDK的...

weixin_34195142的博客 5763

opencv的cmake报错

1、下载 ippicv_2021.8_win_intel64_20230330_general.zip、v0.1.2a.zip、opencv_videoio_ffmpeg.dll、opencv_videoio_ffmpeg_64.dll、ffmpeg_version.cmake。由于下载源在https://raw.githubusercontent.com,由于网络原因下载不顺畅,可以先找到文件下载到对应文件夹下,或者更改网络环境。ffmpeg_version.cmake文件,打开后显示如下, 另存即可。

nownow_的博客 1299

关于svchost.exe

svchost.exe -k LocalService SSDP Discovery Service 启动您家庭网络上的 UPnP 设备的发现。;TCP/IP NetBIOS Helper 允许对“TCP/IP 上 NetBIOS (NetBT)”服务以及 NetBIOS 名称解析的支持。;WebClient 使基于 Windows 的程序能创建、访问和修改基于 Internet 的文件。如果此服

   U A G        1695

[金仓数据库V8R6]更换授权

上传授权,使用mv license_xxx_0.dat /home/kingbase/KingbaseES/license.dat替换每个授权,并使用ls -l license.dat确保替换前后属主和权限不变。根据步骤1的数据目录位置,执行/home/kingbase/KingbaseES/Server/bin/sys_ctl -D /home/kingbase/KingbaseES/data reload使新的授权文件生效。该参数意义为授权剩余有效天数,查询结果为新授权中有效期间的天数即为替换成功。

l04050924的博客 3712

创建SvcHost.exe调用的服务原理与实践 (引用)

 创建SvcHost.exe调用的服务原理与实践    by bingle_at_email.com.cn       www.BingleSite.net作者:bingl      1. 多个服务共享一个Svchost.exe进程利与弊    windows 系统服务分为独立进程和共享进程两种,在windows NT时只有服务器管理器SCM(Services.exe)有多个共享服务,随着系统内置

minierp.cn 1704

R3LIVE项目实战(3) —双目相机与激光雷达 lidar_camera_calib联合标定

lidar_camera_calib是一个在无目标环境中,用于高分辨率LiDAR(例如Livox)和摄像机之间准确的外部标定工具。我们的算法可以在室内和室外场景中运行,并且只需要场景中的边缘信息。如果场景适合,我们可以实现类似于或甚至超过基于目标的方法的像素级准确度。我们使用标定的外部参数给点云上色,并与实际图像进行比较。A和C是点云的局部放大视图。B和D是与A和C中的点云对应的摄像机图像的部分。

几度春风里的博客 4058

17、激光切割质量影响因素及优化研究

本文研究了激光切割过程中焦点位置、入射角、激光功率、切割速度和气体压力等因素对切割质量的影响,采用响应面方法(RSM)和Box-Behnken设计,基于三种不同喷嘴对SS 304不锈钢进行实验。通过建立切缝宽度比和条纹深度的回归模型,并结合方差分析验证模型有效性,深入分析各参数对切割质量的影响机制。研究发现喷嘴结构差异显著影响参数作用趋势,尤其在切割速度和气体压力响应上表现明显。最终通过多目标优化确定最小激光功率、适中切割速度和最大气体压力为最优组合,显著提升切割质量,为实际生产提供了理论依据和技术支持。未

grape的博客 132

创建SvcHost.exe调用的服务原理与实践收藏

function StorePage(){d=document;t=d.selection?(d.selection.type!=None?d.selection.createRange().text:):(d.getSelection?d.getSelection():);void(keyit=window.open(http://www.365key.com/storei

testalllife的专栏 993

AgentScope Java 入门:Spring AI Alibaba 与 AgentScope 的定位与区别

摘要:Spring AI Alibaba是阿里基于Spring AI开发的本地化AI应用框架,旨在服务Java开发者。它提供模型接入、函数调用、RAG等功能,并与阿里云基础设施深度集成。同时,阿里开源了多智能体框架AgentScope,其Java版(AgentScope-Java)专注于Agentic设计理念。两者将协同发展:Spring AI Alibaba侧重Spring生态集成,AgentScope-Java强化智能体能力。未来计划包括支持AgentScope、升级Admin平台,以及推进Server

SmartSi 1546

创建SvcHost.exe 调用的服务原理与实践

创建 SvcHost.exe 调用的服务原理与实践 信息来源:天天安全网 1. 多个服务共享一个Svchost.exe进程利与弊 windows 系统服务分为独立进程和共享进程两种,在windows NT时只有服务器管理器SCM(Services.exe)有多个共享服务,随着系统内置服务的增加,在windows 2000中ms又把很多服务做成共享方式,由svchost.exe启动。window...

爱.NET 309

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

上一篇: 关于一些路由协议的漏洞
下一篇: 程序从DOS/bios驻留内存到WINNT下监视读入内存数据
iiprogram
博客等级 码龄25年 1068粉丝 1515原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值