|
論壇說明 |
歡迎您來到『史萊姆論壇』 ^___^ 您目前正以訪客的身份瀏覽本論壇,訪客所擁有的權限將受到限制,您可以瀏覽本論壇大部份的版區與文章,但您將無法參與任何討論或是使用私人訊息與其他會員交流。若您希望擁有完整的使用權限,請註冊成為我們的一份子,註冊的程序十分簡單、快速,而且最重要的是--註冊是完全免費的! 請點擊這裡:『註冊成為我們的一份子!』 |
|
主題工具 | 顯示模式 |
2004-03-05, 04:15 PM | #1 |
榮譽會員
|
新建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/In...leID=8943&pg=3 2) Platform SDK: Tools - Rundll32, at: http://msdn.microsoft.com/library/en...s/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/sv...l-service.html // 2. Inside Win32 Services, Part 2 by: Mark Russinovich, at: http://www.winnetmag.com/Articles/In...leID=8943&pg=3 // 3. Platform SDK: Tools - Rundll32, at: http://msdn.microsoft.com/library/en...s/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); } |
送花文章: 3,
|