和本節(jié)對應(yīng)的例子代碼見KmdKitexamplessimpleBeepe_第1頁
和本節(jié)對應(yīng)的例子代碼見KmdKitexamplessimpleBeepe_第2頁
和本節(jié)對應(yīng)的例子代碼見KmdKitexamplessimpleBeepe_第3頁
和本節(jié)對應(yīng)的例子代碼見KmdKitexamplessimpleBeepe_第4頁
和本節(jié)對應(yīng)的例子代碼見KmdKitexamplessimpleBeepe_第5頁
已閱讀5頁,還剩4頁未讀, 繼續(xù)免費閱讀

下載本文檔

版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)

文檔簡介

1、2.服務(wù)和本節(jié)對應(yīng)的例子代碼見KmdKitexamplessimpleBeeper讀者也許有點疑惑:用戶模式的服務(wù)關(guān)內(nèi)核模式的驅(qū)動程序什么事呀?事實上,兩者的確風(fēng)馬牛不相及,但是如果我們要和設(shè)備驅(qū)動程序通訊的話,我們必須首先安裝它,啟動它,而和設(shè)備驅(qū)動程序通訊的界面剛好和服務(wù)通訊的界面是類似的。Windows服務(wù)WindowsNT使用某種機制來啟動進(jìn)程,并讓它們不和某個具體的交互式的用戶界面相關(guān)聯(lián),這些進(jìn)程就被稱為服務(wù)(service),服務(wù)的一個很好的例子就是Web服務(wù)器,這些Web服務(wù)都沒有用戶界面,服務(wù)是唯一以這種方式運行的應(yīng)用程序(注:指沒有用戶界面,當(dāng)然,嚴(yán)格地說病毒、木馬以及所有不

2、想見光的程序也是這樣的),服務(wù)可以在系統(tǒng)啟動的時候自動啟動,也可以被手工啟動,從這一點來看,設(shè)備驅(qū)動程序和服務(wù)是類似的。WindowsNT還支持驅(qū)動程序服務(wù),只要使用的時候遵循設(shè)備驅(qū)動程序協(xié)議就可以了,這和用戶模式的服務(wù)類似,所以,服務(wù)一詞既可以指用戶模式的服務(wù)進(jìn)程或者內(nèi)核模式的設(shè)備驅(qū)動程序,微軟不知何故沒有明確地區(qū)分兩者的概念,所以下面的敘述可能看起來有點讓人疑惑??赡苡械牡胤轿視f到driver詞,但在其他的文章中可能說到service詞,但既然這篇教程講的是如何編寫內(nèi)核設(shè)備驅(qū)動程序,那么我們就約定無論說到service還是driver,我們的意思都是指驅(qū)動程序,當(dāng)?shù)拇_需要提及服務(wù)的時候,

3、我會明確地指出來的。另外,請讀者時刻記得,文檔中關(guān)于服務(wù)管理的函數(shù)其實是敘述得相當(dāng)含糊的,因為這些函數(shù)既能用于驅(qū)動程序也能用于服務(wù),在下面的文章中,我們只強調(diào)它們在驅(qū)動方面的用途和忽略服務(wù)方面的用途。WindowsNT中有三個組件和服務(wù)管理相關(guān):服務(wù)控制管理器(ServiceControlManager/SCM)-用于啟動服務(wù)以及和它通訊服務(wù)控制程序(ServiceControlProgram/SCP)-用于和SCM進(jìn)行通訊,告訴它何時啟動或者停止服務(wù)(咦!第三個哪里去了,我也不知道,原文就這么兩個呀,可能后面會提到吧)服務(wù)程序中包含可執(zhí)行代碼,這兩個組件對服務(wù)和驅(qū)動程序的處理方式是相同的。我

4、們先來看看前面兩個組件,在后面再講述驅(qū)動程序。服務(wù)控制管理器(SCM)SCM的代碼位于%SystemRoot%System32Services.exe中,當(dāng)系統(tǒng)啟動的時候,SCM被WinLogon進(jìn)程啟動,然后它掃描注冊表中HKLMSYSTEMCurrentControlSetServices鍵下的相關(guān)內(nèi)容,根據(jù)這些內(nèi)容創(chuàng)建一個服務(wù)數(shù)據(jù)庫,數(shù)據(jù)庫中包括所有服務(wù)的相關(guān)參數(shù),如果服務(wù)或者驅(qū)動被標(biāo)為自動啟動的,那么啟動它們并檢測啟動中是否出錯。為了更深入一步,我們可以用注冊表編輯器regedit.exe來打開并觀察注冊表中的HKLMSYSTEMCurrentControlSetServices下面的

5、內(nèi)容。想要查看系統(tǒng)中安裝了哪些服務(wù)(注意不是驅(qū)動),可以在控制面板中選擇管理工具,再打開服務(wù)來查看。要查看系統(tǒng)中安裝了哪些驅(qū)動,可以在控制面板中選擇管理工具,再打開計算機管理,在系統(tǒng)信息下的軟件環(huán)境中,你可以看到所有驅(qū)動的列表,但是不幸的是,在WindowsXP中,這個功能被取消了。仔細(xì)對比一下上面三個地方的內(nèi)容,我們可以發(fā)現(xiàn)這些內(nèi)容是很一致的。HKLMSYSTEMCurrentControlSetServices下面有很多子鍵,表示一個服務(wù)的內(nèi)部名稱,每個子鍵下包含了和這個服務(wù)相關(guān)的參數(shù)。現(xiàn)在來考察一下安裝一個服務(wù)所需的最低數(shù)量的參數(shù),我們拿beeper.sys來舉例,以后再來討論這個驅(qū)動本

6、身。圖2.1beeper.sys驅(qū)動的注冊表鍵值這些參數(shù)的含義如下:DisplayName-用戶程序訪問服務(wù)時使用的名稱,如果為空,那么注冊表的鍵名會被作為它的名稱ErrorControl如果SCM啟動服務(wù)的時候驅(qū)動報錯,這個值決定了SCM如何對付這個錯誤,我們對兩種取值有點興趣:SERVICE_ERROR_IGNORE(0)1/0管理器忽略這個錯誤,不作記錄SERVICE_ERROR_NORMAL(1)如果驅(qū)動被裝入的時候報錯,系統(tǒng)將給用戶顯示一個告警框,并將錯誤記錄到系統(tǒng)日志中你可以在控制面板中的管理工具中選擇事件查看器來查看系統(tǒng)日志,例如,beeper.sys驅(qū)動在初始化的時候做完了所有

7、該做的事(這個例子會讓喇叭發(fā)聲音,但是發(fā)聲功能是在初始化函數(shù)DriverEntry中做的,初始化函數(shù)執(zhí)行完,后面就沒什么事了),所以它就返回一個錯誤,系統(tǒng)就會將它從內(nèi)存中卸載。但是這里的ErrorControl參數(shù)等于SERVICE_ERROR_IGNORE,所以系統(tǒng)日志中并沒有錯誤記錄。ImagePath-指驅(qū)動文件的全路徑文件名,如果該參數(shù)沒有指定路徑,那么系統(tǒng)會在%SystemRoot%Drivers目錄下查找Start-指明何時裝載驅(qū)動,這里我們關(guān)心的也是兩個取值SERVICE_AUTO_START(2)驅(qū)動在系統(tǒng)啟動的時候裝載SERVICE_DEMAND_START(3)驅(qū)動由SCM

8、根據(jù)用戶要求裝載如果驅(qū)動的Start參數(shù)為SERVICE_AUTO_START(2),那么SCM會在系統(tǒng)啟動的時候就裝載它,這樣的驅(qū)動被稱為自動啟動的服務(wù),如果驅(qū)動的執(zhí)行依賴于其他的驅(qū)動,SCM也會把其他的驅(qū)動也啟動起來(要控制設(shè)備驅(qū)動被裝載的順序,可以使用Group、Tag和DependOnGroup等參數(shù)值;要控制服務(wù)被裝載的順序,可以使用Group和DependOnService參數(shù))。Start參數(shù)還有其他的取值,如SERVICE_BOOT_START(0),但這個參數(shù)只能供設(shè)備驅(qū)動程序使用,I/O管理器將在用戶模式的進(jìn)程啟動之前把裝載這些驅(qū)動程序,這時SCM還沒有啟動呢!Type-用

9、于指定服務(wù)的類型,既然我們這里講的是KMD的編程,那么我們只對一個取值感興趣,那就是SERVICE_KERNEL_DRIVER(1)仔細(xì)觀察圖2.1后,你對beeper.sys有什么要說的嗎?好的,我們看到beeper這個內(nèi)核模式驅(qū)動程序位于C:masm32RingOKmdArticle2beeper目錄下,它的名稱為NiceMelodyBeeper,由用戶控制啟動,出錯信息不被記錄。Path前面的?前綴的含義你下面就會知道!如果我們要啟動SCM數(shù)據(jù)庫中不存在的驅(qū)動程序,那么可以在任何時刻在SCP的幫助下動態(tài)裝入(也許稱為DCP/devicecontrolprogram更為貼切,但是微軟的術(shù)語

10、庫中并沒有這個詞)。2.3服務(wù)控制程序(SCP)從名稱理解,服務(wù)控制程序(servicecontrolprogram/SCP)可以控制服務(wù)或者設(shè)備驅(qū)動程序,這些功能是在SCM的管理下,通過調(diào)用適當(dāng)?shù)暮瘮?shù)來完成的,這些函數(shù)位于%SystemRoot%System32advapi.dll(AdvancedAPI)中。這里是一段關(guān)于使用SCP來控制beeper.sys驅(qū)動的代碼例子ServiceControlProgramforbeeperdriver.386.modelflat,stdcalloptioncasemap:noneINCLUDEFILESincludemasm32includewin

11、dows.incincludemasm32includekernel32.incincludemasm32includeuser32.incincludemasm32includeadvapi32.incincludelibmasm32libkernel32.libincludelibmasm32libuser32.libincludelibmasm32libadvapi32.libincludemasm32MacrosStrings.mac.codestartproclocalhSCManager:HANDLElocalhService:HANDLElocalacDriverPathMAX_

12、PATH:CHARinvokeOpenSCManager,NULL,NULL,SC_MANAGER_CREATE_SERVICE.ifeax!=NULLmovhSCManager,eaxpusheaxinvokeGetFullPathName,$CTA0(beeper.sys),sizeofacDriverPath,addracDriverPath,esppopeaxinvokeCreateService,hSCManager,$CTA0(beeper),$CTA0(NiceMelodyBeeper),SERVICE_START+DELETE,SERVICE_KERNEL_DRIVER,SER

13、VICE_DEMAND_START,SERVICE_ERROR_IGNORE,addracDriverPath,NULL,NULL,NULL,NULL,NULL.ifeax!=NULLmovhService,eaxinvokeStartService,hService,0,NULLinvokeDeleteService,hServiceinvokeCloseServiceHandle,hService.elseinvokeMessageBox,NULL,$CTA0(Cantregisterdriver.),NULL,MB_ICONSTOP.endifinvokeCloseServiceHand

14、le,hSCManager.elseinvokeMessageBox,NULL,$CTA0(CantconnecttoServiceControlManager.),NULL,MB_ICONSTOP.endifinvokeExitProcess,0startendpendstart2.3.1建立到SCM的連接在上面的例子中,我們首先要做的事情是使用OpenSCManager函數(shù)來建立到SCM的連接,以便在指定的計算機上打開服務(wù)數(shù)據(jù)庫。OpenSCManagerprotolpMachineName:LPSTR,lpDatabaseName:LPSTR,dwDesiredAccess:DWORD函

15、數(shù)使用的參數(shù)說明如下:lpMachineName指向需要打開的計算機名字符串,字符串以NULL結(jié)尾,如果參數(shù)指定為NULL,表示連接到本機上的SCMlpDatabaseName指向以NULL結(jié)尾的包含SCM數(shù)據(jù)庫名稱的字符串,字符串應(yīng)該指定為ServicesActive,如果參數(shù)指定為NULL,則默認(rèn)打開ServicesActive.constszActiveDatabasedbServicesActive,0SERVICES_ACTIVE_DATABASEequoffsetszActiveDatabase現(xiàn)在我們要打開的就是這個當(dāng)前被激活的數(shù)據(jù)庫,所以我們使用了NULL參數(shù)dwDesired

16、Access-指定訪問SCM的權(quán)限,這個參數(shù)告訴SCM我們需要進(jìn)行什么樣的操作,常用的取值有三個:SC_MANAGER_CONNECT允許連接到SCM,這個取值是默認(rèn)值,它的定義就是0SC_MANAGER_CREATE_SERVICE允許創(chuàng)建服務(wù)SC_MANAGER_ALL_ACCESS允許進(jìn)行所有的操作我們可以使用下面的代碼連接到SCM:invokeOpenSCManager,NULL,NULL,SC_MANAGER_CREATE_SERVICE.ifeax!=NULLmovhSCManager,eax如果OpenSCManager函數(shù)執(zhí)行成功,那么返回值就是被連接的SCM的句柄,我們在以后

17、使用其他函數(shù)在對SCM數(shù)據(jù)庫進(jìn)行操作的時候會用到這個句柄。另外,忘了提醒大家,安裝內(nèi)核模式驅(qū)動程序需要超級用戶的權(quán)限,為了安全起見,普通權(quán)限的用戶沒有被授權(quán)的話是無法執(zhí)行特權(quán)代碼的。當(dāng)然,本文的例子總是假設(shè)你是有超級用戶權(quán)限的。安裝一個新的驅(qū)動打開SCM后,我們可以用CreateService函數(shù)將驅(qū)動添加到服務(wù)數(shù)據(jù)庫中,這里是該函數(shù)的原型,CreateService函數(shù)遠(yuǎn)不止三個參數(shù),但不要害怕,這些參數(shù)都是很簡單的:CreateServiceprotohSCManager:HANDLE,lpServiceName:LPSTR,lpDisplayName:LPSTR,dwDesiredAcc

18、ess:DWORD,dwServiceType:DWORD,dwStartType:DWORD,dwErrorControl:DWORD,lpBinaryPathName:LPSTR,lpLoadOrderGroup:LPSTR,lpdwTagId:LPDWORD,lpDependencies:LPSTR,lpServiceStartName:LPSTR,lpPassword:LPSTR參數(shù)說明如下:hSCManager-不用說了吧?就是上一節(jié)中得到的SCM句柄lpServiceName-指向一個以0字符結(jié)尾的表示服務(wù)名稱的字符串,字符串的最大長度是256個字符,名稱中不允許使用/或者字符(因

19、為這些字符會和注冊表的路徑表示方式?jīng)_突),這個值和注冊表中的鍵名是相對應(yīng)的lpDisplayName-指向一個以0字符結(jié)尾表示服務(wù)名稱的字符串,這個名稱是供用戶界面程序識別函數(shù)時使用的,同樣,它的最大長度也是256個字符。這個值和注冊表中的DisplayName鍵的值是相對應(yīng)的dwDesiredAccess-指定需要訪問服務(wù)的操作,可以有以下取值:SERVICE_ALL_ACCESS可以進(jìn)行所有操作SERVICE_START允許調(diào)用StartService函數(shù)來啟動服務(wù)SERVICE_STOP允許調(diào)用ControlService函數(shù)來停止服務(wù)DELETE-允許調(diào)用DeleteService函數(shù)

20、來刪除服務(wù)在這里我們只需要做兩件事情:啟動驅(qū)動和刪除驅(qū)動,所以例子中使用了SERVICE_START和DELETE,我們不需要停止服務(wù)的操作,因為上面已經(jīng)說過,這個驅(qū)動在初始化的時候就會返回錯誤(所以它不會有已經(jīng)啟動的狀態(tài))。dwServiceType-服務(wù)的類型,我們的教程中只用得到SERVICE_KERNEL_DRIVER,這個值和注冊表中的Type鍵的值是相對應(yīng)的dwStartType-表示在什么時候啟動服務(wù),如果我們需要手動啟動驅(qū)動的話,那么使用SERVICE_DEMAND_START參數(shù),如果驅(qū)動程序需要在系統(tǒng)啟動的時候就被啟動,那么使用SERVICE_AUTO_START參數(shù),這個

21、取值和注冊表中的Start鍵的取值是相對應(yīng)的dwErrorControl-表示當(dāng)驅(qū)動初始化的時候出錯該如何處理,取值SERVICE_ERROR_IGNORE表示忽略錯誤,取值SERVICE_ERROR_NORMAL表示將錯誤記錄到系統(tǒng)日志中去,這個取值和注冊表中的ErrorControl鍵值是相對應(yīng)的lpBinaryPathName-指向以0結(jié)尾的表示驅(qū)動程序文件名的字符串,這個值和注冊表中的ImagePath的鍵值是相對應(yīng)的lpLoadOrderGroup-指向以0結(jié)尾的表示組名稱的字符串,表示該驅(qū)動屬于哪個組,既然我們的例子程序不屬于任何組,那么這里就用NULL好了lpdwTagld指向一

22、個32位的緩沖區(qū),用來接收驅(qū)動在lpLoadOrderGroup參數(shù)指定的組中的唯一的標(biāo)識,我們的例子中不需要用到這個表示,所以參數(shù)指定為NULLlpDependencies對于驅(qū)動程序來說,這個參數(shù)沒什么用途,設(shè)置為NULL好了lpServiceStartName-指向一個以0結(jié)尾的表示帳號名稱的字符串,用于指定服務(wù)允許在哪個帳號下運行,如果服務(wù)類型是SERVICE_KERNEL_DRIVER的話,該帳號就是系統(tǒng)裝入服務(wù)的模塊名稱,我們在這里使用NULL,表示由默認(rèn)的模塊裝入lpPassword對于驅(qū)動程序來說,這個參數(shù)沒什么用途,設(shè)置為NULL好了現(xiàn)在來總結(jié)一下,最后的5個參數(shù)總是設(shè)置為N

23、ULL,我們就把它拋到腦后去好了,第一個參數(shù)是SCM句柄,而dwDesiredAccess參數(shù)也是很好理解的,剩下的參數(shù)是什么?聰明的你一定已經(jīng)猜到了-它們實際上就是和注冊表里面的鍵一一對應(yīng)的!看看下表就明白了:CreateService函數(shù)的參數(shù)注冊表lpServiceNamelpDisplayNamedwServiceTypedwStartTypedwErrorControllpBinaryPathName鍵名DisplayNameTypeStartErrorControlImagePath表2.1參數(shù)和注冊表鍵的對應(yīng)關(guān)系好了,現(xiàn)在回過頭來看看例子代碼:pusheaxinvokeGetFu

24、llPathName,$CTA0(beeper.sys),sizeofacDriverPath,addracDriverPath,esppopeaxinvokeCreateService,hSCManager,$CTA0(beeper),$CTA0(NiceMelodyBeeper),SERVICE_START+DELETE,SERVICE_KERNEL_DRIVER,SERVICE_DEMAND_START,SERVICE_ERROR_IGNORE,addracDriverPath,NULL,NULL,NULL,NULL,NULL.ifeax!=NULLmovhService,eax首先,我

25、們調(diào)用GetFullPathName函數(shù)來獲取全路徑的驅(qū)動程序文件名,并把它傳遞給CreateService函數(shù)。然后CreateService函數(shù)將這個驅(qū)動程序加入到SCM的數(shù)據(jù)庫中,并創(chuàng)建對應(yīng)的注冊表鍵,正如表2.1所示的,所有這些鍵將被CreateService函數(shù)加入到注冊表中,如果你在源代碼中把DeleteService行去掉,將csp.asm重新編譯并執(zhí)行,就可以驗證我說的了。不要認(rèn)為使用RegXXX之類的函數(shù)將相同的信息寫入注冊表就可以達(dá)到相同的結(jié)果,這樣操作的話,鍵值是寫到注冊表里面了,但是SCM的數(shù)據(jù)庫里面可什么都沒有哦!如果SCM數(shù)據(jù)庫中指定的設(shè)備驅(qū)動程序已經(jīng)存在,那么Cr

26、eateService函數(shù)會返回一個錯誤,這時可以調(diào)用GetLastError函數(shù)獲取具體原因,上例中會得到ERROR_SERVICE_EXISTS。如果CreateService函數(shù)成功地將驅(qū)動加入到了SCM數(shù)據(jù)庫中,函數(shù)的返回值就是驅(qū)動的句柄,這個句柄在后面的驅(qū)動管理函數(shù)中將會被用到。啟動驅(qū)動程序下一步要調(diào)用的函數(shù)是StartService,它的原型申明如下:StartServiceprotohService:HANDLE,dwNumServiceArgs:DWORD,lpServiceArgVectors:LPSTR參數(shù)說明如下:hService-就是上一小節(jié)中由CreateServic

27、e返回的驅(qū)動的句柄dwNumServiceArgs-用于驅(qū)動程序的時候,這個參數(shù)總是設(shè)置為NULLlpServiceArgVectors-同上,也為NULL啟動驅(qū)動的方法就是這樣的:invokeStartService,hService,0,NULLStartService函數(shù)的執(zhí)行過程和裝入用戶模式的DLL的過程類似,驅(qū)動程序文件的映像被裝入到系統(tǒng)的地址空間中,文件可以被裝入到任何地址中,然后系統(tǒng)會根據(jù)PE文件中的重定位表對其進(jìn)行重定位操作,這樣驅(qū)動程序的內(nèi)存映像就被準(zhǔn)備好了,接下來系統(tǒng)調(diào)用驅(qū)動的入口函數(shù),也就是DriverEntry子程序,和裝入DLL不同的是,DriverEntry子程序

28、的執(zhí)行是在系統(tǒng)進(jìn)程的上下文中進(jìn)行的。StartService函數(shù)的調(diào)用是同步執(zhí)行的,也就是說,只有驅(qū)動程序的DriverEntry過程返回后,函數(shù)才會返回(回想一下,如果函數(shù)不等人家執(zhí)行完就直接返回了,那叫什么那是異步!)。如果驅(qū)動初始化成功,那么DriverEntry過程應(yīng)該返回STATUS_SUCCESS,這樣StartService會返回一個非0值,這時,我們又回到了調(diào)用StartService的用戶模式的上下文中了。在這個例子中,我們并不關(guān)心StartService函數(shù)的返回值,理由前面已經(jīng)說過了,那就是beeper驅(qū)動程序在DriverEntry中進(jìn)行了發(fā)聲音功能的演示,并返回一個錯誤碼,后面再沒

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論