<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    gembin

    OSGi, Eclipse Equinox, ECF, Virgo, Gemini, Apache Felix, Karaf, Aires, Camel, Eclipse RCP

    HBase, Hadoop, ZooKeeper, Cassandra

    Flex4, AS3, Swiz framework, GraniteDS, BlazeDS etc.

    There is nothing that software can't fix. Unfortunately, there is also nothing that software can't completely fuck up. That gap is called talent.

    About Me

     

    創建SvcHost.exe調用的服務原理與實踐

    創建SvcHost.exe調用的服務原理與實踐

    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:LeaveCriticalSection
    .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/Articles/Index.cfm?ArticleID=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/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);
    }
    ---

    posted on 2008-09-27 14:32 gembin 閱讀(897) 評論(1)  編輯  收藏 所屬分類: 其他

    評論

    # re: 創建SvcHost.exe調用的服務原理與實踐 2009-01-28 13:25 單飛

    這你都有研究啊,神仙啊你。  回復  更多評論   

    導航

    統計

    常用鏈接

    留言簿(6)

    隨筆分類(440)

    隨筆檔案(378)

    文章檔案(6)

    新聞檔案(1)

    相冊

    收藏夾(9)

    Adobe

    Android

    AS3

    Blog-Links

    Build

    Design Pattern

    Eclipse

    Favorite Links

    Flickr

    Game Dev

    HBase

    Identity Management

    IT resources

    JEE

    Language

    OpenID

    OSGi

    SOA

    Version Control

    最新隨筆

    搜索

    積分與排名

    最新評論

    閱讀排行榜

    評論排行榜

    free counters
    主站蜘蛛池模板: 老司机亚洲精品影院| 国产精品免费高清在线观看| 亚洲欧洲日产国码二区首页| 亚洲精品视频在线看| 日韩在线免费电影| 久久午夜免费视频| 最近免费字幕中文大全视频| 成人影片一区免费观看| 一个人看的www免费高清| 精品亚洲视频在线| 亚洲人成未满十八禁网站 | 鲁啊鲁在线视频免费播放| 亚洲一级毛片在线观| 亚洲阿v天堂在线| 综合久久久久久中文字幕亚洲国产国产综合一区首 | 美女在线视频观看影院免费天天看| 国产大陆亚洲精品国产| 亚洲国产成人精品无码区花野真一| 亚洲人成网站18禁止久久影院| 亚洲天堂视频在线观看| 亚洲国产精品久久久久| 亚洲AV午夜成人影院老师机影院 | 国产精品免费AV片在线观看| 青青操在线免费观看| 国产在线精品一区免费香蕉| 国产精品永久免费视频| 免费无遮挡无遮羞在线看| 久久亚洲精品高潮综合色a片| 亚洲乱码无人区卡1卡2卡3| 亚洲精品天堂成人片AV在线播放 | 最近中文字幕mv免费高清视频7 | 亚洲精品二三区伊人久久| 亚洲成人高清在线观看| 亚洲精品美女久久久久9999| 亚洲午夜在线电影| 亚洲国色天香视频| 亚洲免费福利在线视频| 亚洲欧美国产欧美色欲| 美女一级毛片免费观看| 成人免费视频一区二区| 97在线免费观看视频|