国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開通VIP
創(chuàng)建SvcHost.exe調(diào)用的服務(wù)原理與實(shí)踐
1. 多個(gè)服務(wù)共享一個(gè)Svchost.exe進(jìn)程利與弊

       windows 系統(tǒng)服務(wù)分為獨(dú)立進(jìn)程和共享進(jìn)程兩種,在windows NT時(shí)只有服務(wù)器管理器SCM(Services.exe)有多個(gè)共享服務(wù),隨著系統(tǒng)內(nèi)置服務(wù)的增加,在windows 2000中ms又把很多服務(wù)做成共享方式,由svchost.exe啟動。windows 2000一般有2個(gè)svchost進(jìn)程,一個(gè)是RPCSS(Remote Procedure Call)服務(wù)進(jìn)程,另外一個(gè)則是由很多服務(wù)共享的一個(gè)svchost.exe。而在windows XP中,則一般有4個(gè)以上的svchost.exe服務(wù)進(jìn)程,windows 2003 server中則更多,可以看出把更多的系統(tǒng)內(nèi)置服務(wù)以共享進(jìn)程方式由svchost啟動是ms的一個(gè)趨勢。這樣做在一定程度上減少了系統(tǒng)資源的消耗,不過也帶來一定的不穩(wěn)定因素,因?yàn)槿魏我粋€(gè)共享進(jìn)程的服務(wù)因?yàn)殄e(cuò)誤退出進(jìn)程就會導(dǎo)致整個(gè)進(jìn)程中的所有服務(wù)都退出。另外就是有一點(diǎn)安全隱患,首先要介紹一下svchost.exe的實(shí)現(xiàn)機(jī)制。


2. Svchost原理

      Svchost本身只是作為服務(wù)宿主,并不實(shí)現(xiàn)任何服務(wù)功能,需要Svchost啟動的服務(wù)以動態(tài)鏈接庫形式實(shí)現(xiàn),在安裝這些服務(wù)時(shí),把服務(wù)的可執(zhí)行程序指向svchost,啟動這些服務(wù)時(shí)由svchost調(diào)用相應(yīng)服務(wù)的動態(tài)鏈接庫來啟動服務(wù)。

       那么svchost如何知道某一服務(wù)是由哪個(gè)動態(tài)鏈接庫負(fù)責(zé)呢?這不是由服務(wù)的可執(zhí)行程序路徑中的參數(shù)部分提供的,而是服務(wù)在注冊表中的參數(shù)設(shè)置的,注冊表中服務(wù)下邊有一個(gè)Parameters子鍵其中的ServiceDll表明該服務(wù)由哪個(gè)動態(tài)鏈接庫負(fù)責(zé)。并且所有這些服務(wù)動態(tài)鏈接庫都必須要導(dǎo)出一個(gè)ServiceMain()函數(shù),用來處理服務(wù)任務(wù)。

例如rpcss(Remote Procedure Call)在注冊表中的位置是  HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/RpcSs,它的參數(shù)子鍵Parameters里有這樣一項(xiàng):
"ServiceDll"=REG_EXPAND_SZ:"%SystemRoot%/system32/rpcss.dll"
當(dāng)啟動rpcss服務(wù)時(shí),svchost就會調(diào)用rpcss.dll,并且執(zhí)行其ServiceMain()函數(shù)執(zhí)行具體服務(wù)。

       既然這些服務(wù)是使用共享進(jìn)程方式由svchost啟動的,為什么系統(tǒng)中會有多個(gè)svchost進(jìn)程呢?ms把這些服務(wù)分為幾組,同組服務(wù)共享一個(gè)svchost進(jìn)程,不同組服務(wù)使用多個(gè)svchost進(jìn)程,組的區(qū)別是由服務(wù)的可執(zhí)行程序后邊的參數(shù)決定的。

例如rpcss在注冊表中 HKEY_LOCAL_MACHINE/SYSTEM/CurrentControlSet/Services/RpcSs 有這樣一項(xiàng):
"ImagePath"=REG_EXPAND_SZ:"%SystemRoot%/system32/svchost -k rpcss"
因此rpcss就屬于rpcss組,這在服務(wù)管理控制臺也可以看到。

svchost的所有組和組內(nèi)的所有服務(wù)都在注冊表的如下位置: 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..

在啟動一個(gè)svchost.exe負(fù)責(zé)的服務(wù)時(shí),服務(wù)管理器如果遇到可執(zhí)行程序內(nèi)容ImagePath已經(jīng)存在于服務(wù)管理器的映象庫中,就不在啟動第2個(gè)進(jìn)程svchost,而是直接啟動服務(wù)。這樣就實(shí)現(xiàn)了多個(gè)服務(wù)共享一個(gè)svchost進(jìn)程。


3. Svchost代碼

        現(xiàn)在我們基本清楚svchost的原理了,但是要自己寫一個(gè)DLL形式的服務(wù),由svchost來啟動,僅有上邊的信息還有些問題不是很清楚。比如我們在導(dǎo)出的ServiceMain()函數(shù)中接收的參數(shù)是ANSI還是Unicode?我們是否需要調(diào)用RegisterServiceCtrlHandler和StartServiceCtrlDispatcher來注冊服務(wù)控制及調(diào)度函數(shù)?

        這些問題要通過查看svchost代碼獲得。下邊的代碼是windows 2000+ service pack 4 的svchost反匯編片段,可以看出svchost程序還是很簡單的。

        主函數(shù)首先調(diào)用ProcCommandLine()對命令行進(jìn)行分析,獲得要啟動的服務(wù)組,然后調(diào)用SvcHostOptions()查詢該服務(wù)組的選項(xiàng)和服務(wù)組的所有服務(wù),并使用一個(gè)數(shù)據(jù)結(jié)構(gòu) svcTable 來保存這些服務(wù)及其服務(wù)的DLL,然后調(diào)用PrepareSvcTable() 函數(shù)創(chuàng)建SERVICE_TABLE_ENTRY 結(jié)構(gòu),把所有處理函數(shù)SERVICE_MAIN_FUNCTION 指向自己的一個(gè)函數(shù)FuncServiceMain(),最后調(diào)用API StartServiceCtrlDispatcher() 注冊這些服務(wù)的調(diào)度函數(shù)。

; =============================== 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為該組的所有服務(wù)都注冊了svchost中的一個(gè)處理函數(shù),因此每次啟動任何一個(gè)服務(wù)時(shí),服務(wù)管理器SCM都會調(diào)用FuncServiceMain() 這個(gè)函數(shù)。這個(gè)函數(shù)使用 svcTable 查詢要啟動的服務(wù)使用的DLL,調(diào)用DLL導(dǎo)出的ServiceMain()函數(shù)來啟動服務(wù),然后返回。

; ============================== 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已經(jīng)調(diào)用了StartServiceCtrlDispatcher來服務(wù)調(diào)度函數(shù),因此我們在實(shí)現(xiàn)DLL實(shí)現(xiàn)時(shí)就不用了,這主要是因?yàn)橐粋€(gè)進(jìn)程只能調(diào)用一次StartServiceCtrlDispatcher API。但是需要用 RegisterServiceCtrlHandler 來注冊響應(yīng)控制請求的函數(shù)。最后我們的DLL接收的都是unicode字符串。

       由于這種服務(wù)啟動后由svchost加載,不增加新的進(jìn)程,只是svchost的一個(gè)DLL,而且一般進(jìn)行審計(jì)時(shí)都不會去HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Svchost 檢查服務(wù)組是否變化,就算去檢查,也不一定能發(fā)現(xiàn)異常,因此如果添加一個(gè)這樣的DLL后門,偽裝的好,是比較隱蔽的。


4. 安裝服務(wù)與設(shè)置
       要通過svchost調(diào)用來啟動的服務(wù),就一定要在HKEY_LOCAL_MACHINE/SOFTWARE/Microsoft/Windows NT/CurrentVersion/Svchost下有該服務(wù)名,這可以通過如下方式來實(shí)現(xiàn):
1) 添加一個(gè)新的服務(wù)組,在組里添加服務(wù)名
2) 在現(xiàn)有組里添加服務(wù)名
3) 直接使用現(xiàn)有服務(wù)組里的一個(gè)服務(wù)名,但本機(jī)沒有安裝的服務(wù)
4) 修改現(xiàn)有服務(wù)組里的現(xiàn)有服務(wù),把它的ServiceDll指向自己

        其中前兩種可以被正常服務(wù)使用,如使用第1種方式,啟動其服務(wù)要創(chuàng)建新的svchost進(jìn)程;第2種方式如果該組服務(wù)已經(jīng)運(yùn)行,安裝后不能立刻啟動服務(wù),因?yàn)閟vchost啟動后已經(jīng)把該組信息保存在內(nèi)存里,并調(diào)用API StartServiceCtrlDispatcher() 為該組所有服務(wù)注冊了調(diào)度處理函數(shù),新增加的服務(wù)不能再注冊調(diào)度處理函數(shù),需要重起計(jì)算機(jī)或者該組的svchost進(jìn)程。而后兩種可能被后門使用,尤其是最后一種,沒有添加服務(wù),只是改了注冊表里一項(xiàng)設(shè)置,從服務(wù)管理控制臺又看不出來,如果作為后門還是很隱蔽的。比如EventSystem服務(wù),缺省是指向es.dll,如果把ServiceDll改為EventSystem.dll就很難發(fā)現(xiàn)。

         因此服務(wù)的安裝除了調(diào)用CreateService()創(chuàng)建服務(wù)之外,還需要設(shè)置服務(wù)的ServiceDll,如果使用前2種還要設(shè)置svchost的注冊表選項(xiàng),在卸載時(shí)也最好刪除增加的部分。

具體代碼參見后邊的附例(使用的是方法3)。

注: ImagePath 和ServiceDll 是ExpandString不是普通字符串。因此如果使用.reg文件安裝時(shí)要注意。


5. DLL服務(wù)實(shí)現(xiàn)
         DLL程序的編寫比較簡單,只要實(shí)現(xiàn)一個(gè)ServiceMain()函數(shù)和一個(gè)服務(wù)控制程序,在ServiceMain()函數(shù)里用RegisterServiceCtrlHandler()注冊服務(wù)控制程序,并設(shè)置服務(wù)的運(yùn)行狀態(tài)就可以了。

          另外,因?yàn)榇朔N服務(wù)的安裝除了正常的CreateService()之外,還要進(jìn)行其他設(shè)置,因此最好實(shí)現(xiàn)安裝和卸載函數(shù)。

          為了方便安裝,實(shí)現(xiàn)的代碼提供了InstallService()函數(shù)進(jìn)行安裝,這個(gè)函數(shù)可以接收服務(wù)名作為參數(shù)(如果不提供參數(shù),就使用缺省的iprip),如果要安裝的服務(wù)不在svchost的netsvcs組里安裝就會失??;如果要安裝的服務(wù)已經(jīng)存在,安裝也會失??;安裝成功后程序會配置服務(wù)的ServiceDll為當(dāng)前Dll。提供的UninstallService()函數(shù),可以刪除任何函數(shù)而沒有進(jìn)行任何檢查。

         為了方便使用rundll32.exe進(jìn)行安裝,還提供了RundllInstallA()和RundllUninstallA()分別調(diào)用InstallService()及UninstallService()。因?yàn)閞undll32.exe使用的函數(shù)原型是:
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
);
對應(yīng)的命令行是rundll32 DllName,FunctionName [Arguments]

         DLL服務(wù)本身只是創(chuàng)建一個(gè)進(jìn)程,該程序命令行就是啟動服務(wù)時(shí)提供的第一個(gè)參數(shù),如果未指定就使用缺省的svchostdll.exe。啟動服務(wù)時(shí)如果提供第二個(gè)參數(shù),創(chuàng)建的進(jìn)程就是和桌面交互的。

具體代碼參見后邊的附例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);
}
本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊舉報(bào)
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
電腦進(jìn)程詳解
驅(qū)動程序安裝類(C#)
Windows系統(tǒng)進(jìn)程列表完全解析
IE瀏覽器打開網(wǎng)頁速度慢的解決方法_會飛的狼
經(jīng)過半小時(shí)整理,讓你快速看懂系統(tǒng)進(jìn)程
認(rèn)識Windows XP的系統(tǒng)進(jìn)程 - ucsai的日志 - 網(wǎng)易博客
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服