• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            tqsheng

            go.....
            隨筆 - 366, 文章 - 18, 評論 - 101, 引用 - 0
            數據加載中……

            創建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


            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 2005-11-30 18:18 tqsheng 閱讀(625) 評論(0)  編輯 收藏 引用

            精品无码久久久久国产| 国产精品美女久久福利网站| 国产美女久久精品香蕉69| 精品久久久噜噜噜久久久| 2020久久精品国产免费| 久久se精品一区二区影院| 99久久精品免费看国产一区二区三区 | 日韩十八禁一区二区久久| 国产精品久久久香蕉| 国产精品久久毛片完整版| 久久精品桃花综合| 91精品无码久久久久久五月天| 久久综合日本熟妇| 国产精品美女久久久| 久久人人爽人人爽人人片av麻烦| 久久美女人爽女人爽| 亚洲精品国产美女久久久| 精品视频久久久久| 久久香蕉国产线看观看乱码| 无码八A片人妻少妇久久| 精品综合久久久久久88小说| 午夜精品久久久久久久| 久久人人爽人人人人爽AV| 久久亚洲国产精品123区| 99久久国产综合精品五月天喷水| 亚洲香蕉网久久综合影视| 色天使久久综合网天天| 久久亚洲2019中文字幕| 久久se精品一区精品二区国产| 久久精品国产一区| 91视频国产91久久久| 狠狠色丁香婷婷久久综合不卡| 久久久免费精品re6| 久久超乳爆乳中文字幕| 久久人人爽人人爽人人AV| 色诱久久久久综合网ywww | 久久久久黑人强伦姧人妻| 久久99国产精品一区二区| WWW婷婷AV久久久影片| 久久国产精品久久| 久久99精品久久久久久不卡 |