和本節對應的例子代碼見KmdKitexamplessimpleBeepe_第1頁
和本節對應的例子代碼見KmdKitexamplessimpleBeepe_第2頁
和本節對應的例子代碼見KmdKitexamplessimpleBeepe_第3頁
和本節對應的例子代碼見KmdKitexamplessimpleBeepe_第4頁
和本節對應的例子代碼見KmdKitexamplessimpleBeepe_第5頁
已閱讀5頁,還剩4頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

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

2、想見光的程序也是這樣的),服務可以在系統啟動的時候自動啟動,也可以被手工啟動,從這一點來看,設備驅動程序和服務是類似的。WindowsNT還支持驅動程序服務,只要使用的時候遵循設備驅動程序協議就可以了,這和用戶模式的服務類似,所以,服務一詞既可以指用戶模式的服務進程或者內核模式的設備驅動程序,微軟不知何故沒有明確地區分兩者的概念,所以下面的敘述可能看起來有點讓人疑惑。可能有的地方我會說到driver詞,但在其他的文章中可能說到service詞,但既然這篇教程講的是如何編寫內核設備驅動程序,那么我們就約定無論說到service還是driver,我們的意思都是指驅動程序,當的確需要提及服務的時候,

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

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

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

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

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

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

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

10、庫中并沒有這個詞)。2.3服務控制程序(SCP)從名稱理解,服務控制程序(servicecontrolprogram/SCP)可以控制服務或者設備驅動程序,這些功能是在SCM的管理下,通過調用適當的函數來完成的,這些函數位于%SystemRoot%System32advapi.dll(AdvancedAPI)中。這里是一段關于使用SCP來控制beeper.sys驅動的代碼例子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函數來建立到SCM的連接,以便在指定的計算機上打開服務數據庫。OpenSCManagerprotolpMachineName:LPSTR,lpDatabaseName:LPSTR,dwDesiredAccess:DWORD函

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

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

17、使用其他函數在對SCM數據庫進行操作的時候會用到這個句柄。另外,忘了提醒大家,安裝內核模式驅動程序需要超級用戶的權限,為了安全起見,普通權限的用戶沒有被授權的話是無法執行特權代碼的。當然,本文的例子總是假設你是有超級用戶權限的。安裝一個新的驅動打開SCM后,我們可以用CreateService函數將驅動添加到服務數據庫中,這里是該函數的原型,CreateService函數遠不止三個參數,但不要害怕,這些參數都是很簡單的: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參數說明如下:hSCManager-不用說了吧?就是上一節中得到的SCM句柄lpServiceName-指向一個以0字符結尾的表示服務名稱的字符串,字符串的最大長度是256個字符,名稱中不允許使用/或者字符(因

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

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

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

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

23、ULL,我們就把它拋到腦后去好了,第一個參數是SCM句柄,而dwDesiredAccess參數也是很好理解的,剩下的參數是什么?聰明的你一定已經猜到了-它們實際上就是和注冊表里面的鍵一一對應的!看看下表就明白了:CreateService函數的參數注冊表lpServiceNamelpDisplayNamedwServiceTypedwStartTypedwErrorControllpBinaryPathName鍵名DisplayNameTypeStartErrorControlImagePath表2.1參數和注冊表鍵的對應關系好了,現在回過頭來看看例子代碼: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、們調用GetFullPathName函數來獲取全路徑的驅動程序文件名,并把它傳遞給CreateService函數。然后CreateService函數將這個驅動程序加入到SCM的數據庫中,并創建對應的注冊表鍵,正如表2.1所示的,所有這些鍵將被CreateService函數加入到注冊表中,如果你在源代碼中把DeleteService行去掉,將csp.asm重新編譯并執行,就可以驗證我說的了。不要認為使用RegXXX之類的函數將相同的信息寫入注冊表就可以達到相同的結果,這樣操作的話,鍵值是寫到注冊表里面了,但是SCM的數據庫里面可什么都沒有哦!如果SCM數據庫中指定的設備驅動程序已經存在,那么Cr

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

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

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

溫馨提示

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

評論

0/150

提交評論