驅(qū)動(dòng)開發(fā)基礎(chǔ)知識(shí)_第1頁
驅(qū)動(dòng)開發(fā)基礎(chǔ)知識(shí)_第2頁
驅(qū)動(dòng)開發(fā)基礎(chǔ)知識(shí)_第3頁
驅(qū)動(dòng)開發(fā)基礎(chǔ)知識(shí)_第4頁
驅(qū)動(dòng)開發(fā)基礎(chǔ)知識(shí)_第5頁
已閱讀5頁,還剩18頁未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

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

文檔簡介

第六章:內(nèi)核編程介紹一、內(nèi)核開發(fā)入門一)內(nèi)核編程的環(huán)境準(zhǔn)備從現(xiàn)在開始如何編寫內(nèi)核程序和一些注意事項(xiàng),內(nèi)核程序運(yùn)行在R0層,擁有最高權(quán)限,在這里我假設(shè)你有足夠的VC開發(fā)上層應(yīng)用程序的經(jīng)驗(yàn)。開發(fā)內(nèi)核程序需要準(zhǔn)備的開發(fā)環(huán)境:VisualStudio6/2005/2010均可,微軟的驅(qū)動(dòng)程序開發(fā)包DDK(DriverDevelopmentKit),隨著Vista版本的發(fā)布這個(gè)開發(fā)包升級(jí)為WDK(WindowsDriverKit)開發(fā)內(nèi)核程序需要準(zhǔn)備的調(diào)試環(huán)境:虛擬機(jī)系統(tǒng),Windbg調(diào)試程序,Dbgview.exe查看日志程序。二)編寫第一個(gè)驅(qū)動(dòng)程序與普通的應(yīng)用程序相比,在一個(gè)內(nèi)核程序工程中,需要增加如下兩個(gè)文件:Sources文件內(nèi)容如下:Sources文件內(nèi)容如下:TARGETNAME=collectorTARGETPATH三TARGETTYPE=DRIVERDRIVERTYPE=FS〃編譯出來的目標(biāo)文件文件名〃目標(biāo)文件路徑默認(rèn)路徑TARGETLIBS=$(DDK_LIB_PATH)\wdmsec.lib\..\lib\drvlib.lib〃靜態(tài)庫INCLUDES=$(DDK_INC_PATH);\..\include〃頭文件SOURCES=filespy.c\〃源文件drv.rc其他更詳細(xì)的信息,請(qǐng)到網(wǎng)上查閱相關(guān)資料。Makefile文件內(nèi)容如下:#DONOTEDITTHISFILE!!!Edit.'sources,ifyouwanttoaddanewsourcefiletothiscomponent.ThisfilemerelyindirectstotherealmakefilethatissharedbyallthedrivercomponentsoftheWindowsNTDDK#[INCLUDE$(NTMAKEENV)\makefile.def沒有仔細(xì)研究過,寫成這樣就可以編譯通過。更多細(xì)節(jié)請(qǐng)查閱相關(guān)資料??纯打?qū)動(dòng)的DriverEntry函數(shù):NTSTATUSDriverEntry(INPDRIVER_OBJECTDriverObject,INPUNICODE_STRINGRegistryPath){DbgPrint("OK,thisisDriverEntry!");DbgPrint("DriverEntryisover\n");returnSTATUS_SUCCESS;J 當(dāng)然這個(gè)程序什么也沒有做,只是進(jìn)去打了兩句日志就退出了。通過Dbgview可以查看到本程序打印出來的日志。二、驅(qū)動(dòng)開發(fā)基礎(chǔ)(一)淺談驅(qū)動(dòng)對(duì)象、設(shè)備對(duì)象與請(qǐng)求首先,談?wù)勻?qū)動(dòng)對(duì)象(DRIVER_OBJECT),可以說驅(qū)動(dòng)對(duì)象代表的是一個(gè)驅(qū)動(dòng)程序(或者叫內(nèi)核模塊)。在寫內(nèi)核程序時(shí),必須要填寫這樣一種結(jié)構(gòu),來告訴Windows程序提供的功能。內(nèi)核程序并不生成進(jìn)程,它們有系統(tǒng)的System進(jìn)程加載,可以存在于任何的進(jìn)程。設(shè)備對(duì)象(DEVICE_OBJECT)可以是一個(gè)具體的物理設(shè)備,如:鍵盤、硬盤等;也可以是一個(gè)虛擬的“設(shè)備”,如:用于進(jìn)程間通信的管道。設(shè)備對(duì)象由驅(qū)動(dòng)對(duì)象創(chuàng)建一個(gè)驅(qū)動(dòng)對(duì)象可以創(chuàng)建很多個(gè)設(shè)備對(duì)象。這些設(shè)備對(duì)象儲(chǔ)存在一個(gè)設(shè)備棧中,這些設(shè)備對(duì)象是用鏈表連接在一起的,當(dāng)新的設(shè)備對(duì)象產(chǎn)生時(shí)應(yīng)該是用的尾插入(和人理解)。對(duì)于請(qǐng)求,我們可以理解為WindowsSDK程序設(shè)計(jì)里的消息。一般都是以IRP方式傳遞的。而設(shè)備對(duì)象是唯一可以接受請(qǐng)求的實(shí)體。然而一個(gè)驅(qū)動(dòng)對(duì)象中可能會(huì)有很多個(gè)設(shè)備對(duì)象,那么是由哪一個(gè)設(shè)備對(duì)象來處理呢?我的理解是:就像MFC中的消息傳遞機(jī)制一樣,會(huì)有一個(gè)消息的接收順序;IRP請(qǐng)求也是這樣,它先發(fā)送到設(shè)備棧中最上面的一個(gè)設(shè)備(最新加入),沒有被處理就繼續(xù)向下發(fā)送,如果到最后都還是沒有被處理,我認(rèn)為會(huì)有一個(gè)默認(rèn)的處理。(二)IoCallDriver函數(shù)與PoCallDriver函數(shù)首先來看這兩個(gè)函數(shù)的原型:NTSTATUSIoCallDriver(INPDEVICEOBJECTDeviceObject,INOUTPIRPIrp);NTSTATUSPoCallDriver(INPDEVICE_OBJECTDeviceObject,INOUTPIRPIrp); 除了函數(shù)名不同之外,其他都一樣。參數(shù)都是兩個(gè),一個(gè)是設(shè)備對(duì)象的指針,另一個(gè)是IRP請(qǐng)求對(duì)象的指針。返回值也是一樣。那么區(qū)別到底是什么呢?我們來看WDKDocumentation上的解釋:TheIoCallDriverroutinesendsanIRPtothedriverassociatedwithaspecifieddeviceobject.ThePoCallDriverroutinepassesapowerIRPtothenext-lowerdriverinthedevicestack.(WindowsServer2003,WindowsXP,andWindows2000only.)從上面的這兩句話中可以看出:IoCallDriver這個(gè)函數(shù)向DeviceObject設(shè)備對(duì)象的驅(qū)動(dòng)對(duì)象發(fā)送一個(gè)IRP請(qǐng)求;而PoCallDriver函數(shù)向設(shè)備棧中的下層設(shè)備傳遞一個(gè)主功能號(hào)為IRP_MJ_POWER的請(qǐng)求,且限于特定的OS。而且,調(diào)用IoCallDriver之前,主調(diào)驅(qū)動(dòng)程序必須要為目標(biāo)驅(qū)動(dòng)程序建立IRP里的I/Ostacklocation;同時(shí),調(diào)用時(shí),IoCallDriver函數(shù)還會(huì)幫助驅(qū)動(dòng)程序?qū)⑤斎雲(yún)?shù)的DeviceObject值賦給IO_STACK_LOCATION結(jié)構(gòu)里的DeviceObject成員。(三)irp請(qǐng)求處理及完成機(jī)制近來學(xué)習(xí)Windows內(nèi)核方面的東西,覺得對(duì)I/O處理過程沒有一個(gè)總體的概念。于是,就花了很長的時(shí)間搜集了很多這方面的知識(shí)總結(jié)了一下。在Windows內(nèi)核中的請(qǐng)求基本上是通過I/ORequestPacket完成的。前面說過,設(shè)備對(duì)象是唯一可以接受請(qǐng)求的實(shí)體。下面,我就來詳細(xì)地說下IRP請(qǐng)求是怎么樣一步一步完成的。首先,我們就需要知道IRP是怎么產(chǎn)生。IRP是由I/O管理器發(fā)出的,I/O管理器是用戶態(tài)與內(nèi)核態(tài)之間的橋梁,當(dāng)用戶態(tài)進(jìn)程發(fā)出I/O請(qǐng)求時(shí),I/O管理器就捕獲這些請(qǐng)求,將其轉(zhuǎn)換為IRP請(qǐng)求,發(fā)送給驅(qū)動(dòng)程序。I/O管理器無疑是非常重要的,具有核心地位。它負(fù)責(zé)所有I/O請(qǐng)求的調(diào)度和管理工作,根據(jù)請(qǐng)求的不同內(nèi)容,選擇相應(yīng)的驅(qū)動(dòng)程序?qū)ο?,設(shè)備對(duì)象,并生成、發(fā)送、釋放各種不同的IRP。整個(gè)I/O處理流程是在它的指揮下完成的。一個(gè)IRP是從非分頁內(nèi)存中分配的可變大小的結(jié)構(gòu),它包括兩部分:IRP首部和輔助請(qǐng)求參數(shù)數(shù)組,如圖1所示。這兩部分都是由I/O管理器建立的。圖1IRP簡單結(jié)構(gòu)圖IRP首部中包含了指向IRP輸入輸出緩沖區(qū)指針、當(dāng)前擁有IRP的驅(qū)動(dòng)指針等。緊接著首部的是一個(gè)IO_STACK_LOCATION結(jié)構(gòu)的數(shù)組。它的大小由設(shè)備棧中的設(shè)備數(shù)確定(設(shè)備棧的概念會(huì)在下文中闡述)。IO_STACK_LOCATION結(jié)構(gòu)中保存了一個(gè)I/O請(qǐng)求的參數(shù)及代碼、請(qǐng)求當(dāng)前對(duì)應(yīng)的設(shè)備指針、完成函數(shù)指針(IoCompletion)等。那么,由I/O管理器產(chǎn)生的IRP請(qǐng)求發(fā)送到哪去了呢?這里我們就要來說說設(shè)備棧的概念了,操作系統(tǒng)用設(shè)備對(duì)象(deviceobject)表示物理設(shè)備,每一個(gè)物理設(shè)備都有一個(gè)或多個(gè)設(shè)備對(duì)象與之相關(guān)聯(lián),設(shè)備對(duì)象提供了在設(shè)備上的所有操作。也有一些設(shè)備對(duì)象并不表示物理設(shè)備。一個(gè)唯軟件驅(qū)動(dòng)程序(software-onlydriver,處理I/O請(qǐng)求,但是不把這些請(qǐng)求傳遞給硬件)也必須創(chuàng)建表示它的操作的設(shè)備對(duì)象。設(shè)備常常由多個(gè)設(shè)備對(duì)象所表示,每一個(gè)設(shè)備對(duì)象在驅(qū)動(dòng)程序棧(driverstack)中對(duì)應(yīng)一個(gè)驅(qū)動(dòng)程序來管理設(shè)備的I/O請(qǐng)求。一個(gè)設(shè)備的所有設(shè)備對(duì)象被組織成一個(gè)設(shè)備棧(devicestack)。而且,IO_STACK_LOCATION數(shù)組中的每個(gè)元素和設(shè)備棧中的每個(gè)設(shè)備是一一對(duì)應(yīng)的,一般情況下,只允許層次結(jié)構(gòu)中的每個(gè)設(shè)備對(duì)象訪問它自己對(duì)應(yīng)的IO_STACK_LOCATION。無論何時(shí),一個(gè)請(qǐng)求操作都在一個(gè)設(shè)備上被完成,I/O管理器把IRP請(qǐng)求傳遞給設(shè)備棧中頂部設(shè)備的驅(qū)動(dòng)程序(IRP是傳遞給設(shè)備對(duì)象的,通過設(shè)備對(duì)象的DriverObject成員找到驅(qū)動(dòng)程序)。驅(qū)動(dòng)程序訪問它對(duì)應(yīng)的設(shè)備對(duì)象在IRP中IO_STACK_LOCATION數(shù)組中的元素檢查參數(shù),以決定要進(jìn)行什么操作(通過檢查結(jié)構(gòu)中的MajorFunction字段,確定執(zhí)行什么操作及如何解釋Parameters共用體字段的內(nèi)容)。驅(qū)動(dòng)程序可以根據(jù)IO_STACK_LOCATION結(jié)構(gòu)中的MajorFunction字段進(jìn)行處理。每一個(gè)驅(qū)動(dòng)或者處理IRP,或者把它傳遞給設(shè)備棧中下一個(gè)設(shè)備對(duì)象的驅(qū)動(dòng)程序。傳遞IRP請(qǐng)求到底層設(shè)備的驅(qū)動(dòng)程序需要經(jīng)過下面幾個(gè)步驟:1.為下一個(gè)IO_STACK_LOCATION結(jié)構(gòu)設(shè)置參數(shù)??梢杂幸韵聝煞N方式:?調(diào)用IoGetNextlrpStackLocation函數(shù)獲得下個(gè)結(jié)構(gòu)的指針,再對(duì)參數(shù)進(jìn)行賦值;?調(diào)用IoCopyCurrentIrpStackLocationToNext函數(shù)(如果第2步中驅(qū)動(dòng)設(shè)置了IoCompletion函數(shù)),或者調(diào)用IoSkipCurrentIrpStackLocation函數(shù)(如果第2步中驅(qū)動(dòng)沒有設(shè)置IoCompletion函數(shù))把當(dāng)前的參數(shù)傳遞給下一個(gè)。如果需要的話,調(diào)用IoSetCompletionRoutine函數(shù)設(shè)置IoCompletion函數(shù)進(jìn)行后續(xù)處理。調(diào)用IoCallDriver函數(shù)將IRP請(qǐng)求傳遞給下一層驅(qū)動(dòng)。這個(gè)函數(shù)會(huì)自動(dòng)調(diào)整IRP棧指針,并且執(zhí)行下一層驅(qū)動(dòng)的派遣函數(shù)。

當(dāng)驅(qū)動(dòng)程序把IRP請(qǐng)求傳遞給下一層驅(qū)動(dòng)之后,它就不再擁有對(duì)該請(qǐng)求的訪問權(quán),強(qiáng)行訪問會(huì)導(dǎo)致系統(tǒng)崩潰。如果驅(qū)動(dòng)程序在傳遞完之后還想再訪問該請(qǐng)求,就必須要設(shè)置IoCompletion函數(shù)。IRP請(qǐng)求可以再其他驅(qū)動(dòng)程序或者其他線程中完成或取消。當(dāng)某一驅(qū)動(dòng)程序調(diào)用IoCompleteRequest函數(shù)時(shí),I/O操作就完成了。這個(gè)函數(shù)使得IRP的堆棧指針向上移動(dòng)一個(gè)位置,如圖2所示:IRP

stad<

poiriterIRPHeaderCurrentI/OstacklocationIRP

stad<

poiriterIRPHeaderCurrentI/OstacklocationloStatus.Status1oStatus.InformationParameterlforAParametersforACallbad<forinitiatorParameterlforBp3r3iTiHtHr2forB/oGown'efiW?routineforAParameterlforCParametersfor-C-foCacaplettonroutineforBIF:P

ccimpletion圖2IRP完成時(shí)棧指針的移動(dòng)圖2所示的當(dāng)C驅(qū)動(dòng)程序調(diào)用完IoCompleteRequest函數(shù)后I/O棧的情況。左邊的實(shí)線箭頭表明棧指針現(xiàn)在指向驅(qū)動(dòng)B的參數(shù)和回調(diào)函數(shù);虛線箭頭是之前的情況。右邊的空心箭頭指明了IoCompletion函數(shù)被調(diào)用的順序。如果驅(qū)動(dòng)程序把IRP請(qǐng)求傳遞給設(shè)備棧中的下層設(shè)備之前設(shè)置了IoCompletion函數(shù),當(dāng)I/O棧指針再次指回到該驅(qū)動(dòng)程序時(shí),I/O管理器就將調(diào)用該IoCompletion函數(shù)。IoCompletion函數(shù)的返回值有兩種:(1)STATUS_CONTINUE_COMPLETION:告訴I/O管理器繼續(xù)執(zhí)行上層驅(qū)動(dòng)程序的IoCompletion函數(shù)。(2)STATUS_MORE_PROCESSING_REQUIRED:告訴I/O管理器停止執(zhí)行上層驅(qū)動(dòng)程序,并將棧指針停在當(dāng)前位置。在當(dāng)前驅(qū)動(dòng)程序調(diào)用IoCompleteRequest函數(shù)后再繼續(xù)執(zhí)行上層驅(qū)動(dòng)的IoCompletion函數(shù)。當(dāng)所有驅(qū)動(dòng)都完成了它們相應(yīng)的子請(qǐng)求時(shí),I/O請(qǐng)求就結(jié)束了。I/O管理器從Irp->IoStatus.Status成員更新狀態(tài)信息,從Irp->IoStatus.Information成員更新傳送字節(jié)數(shù)。四)編寫程序手動(dòng)加載驅(qū)動(dòng)程序#includevwindows.h>#include<winsvc.h>#include<conio.h>#include<stdio.h>#defineDRIVER_NAME"HelloDriver"#defineDRIVER_PATH"..\\MyDriver\\HelloDriver.sys"〃裝載NT驅(qū)動(dòng)程序BOOLLoadNTDriver(char*lpszDriverName,char*lpszDriverPath){charszDriverImagePath[256];〃得到完整的驅(qū)動(dòng)路徑GetFullPathName(lpszDriverPath,256,szDriverImagePath,NULL);BOOLbRet=FALSE;SC_HANDLEhServiceMgr=NULL;//SCM管理器的句柄SC_HANDLEhServiceDDK=NULL;//NT驅(qū)動(dòng)程序的服務(wù)句柄〃打開服務(wù)控制管理器hServiceMgr=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);if(hServiceMgr==NULL){//OpenSCManager失敗printf("OpenSCManager()Faild%d!\n",GetLastError());bRet=FALSE;gotoBeforeLeave;}else{////OpenSCManager成功printf("OpenSCManager。ok!\n");}〃創(chuàng)建驅(qū)動(dòng)所對(duì)應(yīng)的服務(wù)hServiceDDK=CreateService(hServiceMgr,lpszDriverName,//驅(qū)動(dòng)程序的在注冊(cè)表中的名字lpszDriverName,//注冊(cè)表驅(qū)動(dòng)程序的DisplayName值SERVICE_ALL_ACCESS,//加載驅(qū)動(dòng)程序的訪問權(quán)限SERVICE_KERNEL_DRIVER,〃表示加載的服務(wù)是驅(qū)動(dòng)程序SERVICE_DEMAND_START,//注冊(cè)表驅(qū)動(dòng)程序的Start值SERVICE_ERROR_IGNORE,//注冊(cè)表驅(qū)動(dòng)程序的ErrorControl值szDriverImagePath,//注冊(cè)表驅(qū)動(dòng)程序的ImagePath值NULL,NULL,NULL,NULL,NULL);DWORDdwRtn;〃判斷服務(wù)是否失敗if(hServiceDDK==NULL){dwRtn=GetLastError();if(dwRtn!=ERROR_IO_PENDING&&dwRtn!=ERROR_SERVICE_EXISTS){〃由于其他原因創(chuàng)建服務(wù)失敗printf("CrateService()Faild%d!\n",dwRtn);bRet=FALSE;gotoBeforeLeave;

else{〃服務(wù)創(chuàng)建失敗,是由于服務(wù)已經(jīng)創(chuàng)立過printf("CrateService()FaildServiceisERROR_ERROR_SERVICE_EXISTS!\n");}//驅(qū)動(dòng)程序已經(jīng)加載,只需要打開hServiceDDK=OpenService(hServiceMgr,SERVICE_ALL_ACCESS);if(hServiceDDK==NULL){〃如果打開服務(wù)也失敗,則意味錯(cuò)誤dwRtn=GetLastError();printf("OpenService()Faild%d!\n",dwRtn);bRet=FALSE;gotoBeforeLeave;}else{printf("OpenService()ok!\n");}}else{printf("CrateService()ok!\n");}〃開啟此項(xiàng)服務(wù)bRet=StartService(hServiceDDK,NULL,NULL);if(!bRet){DWORDdwRtn=GetLastError();if(dwRtn!=ERROR_IO_PENDING&&ERROR_SERVICE_ALREADY_RUNNING){printf("StartService()Faild%d!\n",dwRtn);bRet=FALSE;gotoBeforeLeave;}else{if(dwRtn==ERROR_IO_PENDING){_PENDINGorlpszDriverName,dwRtn!=〃設(shè)備被掛住_PENDINGorlpszDriverName,dwRtn!=printf("StartService()FaildERRORIOPENDING!\n");bRet=FALSE;gotoBeforeLeave;}else{〃服務(wù)已經(jīng)開啟printf("StartService()FaildERROR_SERVICE_ALREADY_RUNNING!\n");bRet=TRUE;gotoBeforeLeave;}}}bRet=TRUE;〃離開前關(guān)閉句柄BeforeLeave:if(hServiceDDK){CloseServiceHandle(hServiceDDK);}if(hServiceMgr){CloseServiceHandle(hServiceMgr);}returnbRet;}〃卸載驅(qū)動(dòng)程序BOOLUnloadNTDriver(char*szSvrName){BOOLbRet=FALSE;SC_HANDLEhServiceMgr=NULL;//SCM管理器的句柄SC_HANDLEhServiceDDK=NULL;//NT驅(qū)動(dòng)程序的服務(wù)句柄SERVICE_STATUSSvrSta;〃打開SCM管理器hServiceMgr=OpenSCManager(NULL,NULL,SC_MANAGER_ALL_ACCESS);if(hServiceMgr==NULL){〃帶開SCM管理器失敗printf("OpenSCManager()Faild%d!\n",GetLastError());bRet=FALSE;gotoBeforeLeave;}else{〃帶開SCM管理器失敗成功printf("OpenSCManager()ok!\n");}〃打開驅(qū)動(dòng)所對(duì)應(yīng)的服務(wù)hServiceDDK=OpenService(hServiceMgr,szSvrName,SERVICE_ALL_ACCESS);if(hServiceDDK==NULL){〃打開驅(qū)動(dòng)所對(duì)應(yīng)的服務(wù)失敗printf("OpenService()Faild%d!\n",GetLastError());bRet=FALSE;gotoBeforeLeave;}else{printf("OpenService()ok!\n");}〃停止驅(qū)動(dòng)程序,如果停止失敗,只有重新啟動(dòng)才能,再動(dòng)態(tài)加載。if(!ControlService(hServiceDDK,SERVICE_CONTROL_STOP,&SvrSta)){printf("ControlService()Faild%d!\n",GetLastError());}else{〃打開驅(qū)動(dòng)所對(duì)應(yīng)的失敗printf("ControlService()ok!\n");}〃動(dòng)態(tài)卸載驅(qū)動(dòng)程序。if(!DeleteService(hServiceDDK)){〃卸載失敗printf("DeleteSrevice()Faild%d!\n",GetLastError());}else{〃卸載成功printf("DelServer:eleteSrevice()ok!\n");}bRet=TRUE;BeforeLeave:〃離開前關(guān)閉打開的句柄if(hServiceDDK){CloseServiceHandle(hServiceDDK);}if(hServiceMgr){CloseServiceHandle(hServiceMgr);}returnbRet;}voidTestDriver(){〃測(cè)試驅(qū)動(dòng)程序HANDLEhDevice=CreateFile("\\\\.\\HelloDDK",GENERIC_WRITEIGENERIC_READ,0,NULL,OPEN_EXISTING0,NULL);if(hDevice!=INVALID_HANDLE_VALUE){printf("CreateDeviceok!\n");}else{printf("CreateDevicefaild%d!\n",GetLastError());}CloseHandle(hDevice);}intmain(intargc,char*argv[]){〃加載驅(qū)動(dòng)BOOLbRet=LoadNTDriver(DRIVER_NAME,DRIVER_PATH);if(!bRet){printf("LoadNTDrivererror\n");return0;}〃加載成功printf("pressanytocreatedevice!\n");getch();TestDriver();〃這時(shí)候你可以通過注冊(cè)表,或其他查看符號(hào)連接的軟件驗(yàn)證。printf("pressanytounloadthedriver!\n");getch();〃卸載驅(qū)動(dòng)UnloadNTDriver(DRIVERNAME);if(!bRet){printf("UnloadNTDrivererror\n");return0;}return0;}(五)創(chuàng)建IRP的四種不同方式在驅(qū)動(dòng)程序中,經(jīng)常會(huì)調(diào)用其他的驅(qū)動(dòng)程序;其中,手動(dòng)構(gòu)造IRP,然后將IRP傳遞到相應(yīng)驅(qū)動(dòng)程序的派遣函數(shù)中是一種比較簡單的方法,下面就來介紹下手動(dòng)創(chuàng)建IRP的幾種不同的方法及其特點(diǎn)。創(chuàng)建IRP總共有4種方法。分別通過調(diào)用:IoBuildSynchronousFsdRequest、IoBuildAsynchronousFsdRequest、IoBuildDeviceIoControl和IoAllocateIrp這4個(gè)內(nèi)核函數(shù)來完成。這其中,IoAllocateIrp是比較底層的內(nèi)核函數(shù),其余的三個(gè)內(nèi)核函數(shù)是屬于靠近上層的內(nèi)核函數(shù),而且這三個(gè)函數(shù)都是通過調(diào)用IoAllocateIrp實(shí)現(xiàn)的。這幾個(gè)函數(shù)都是文檔化的函數(shù),原型都可以在DDKDocumentation中查到,這里就不多說了,下面主要來說說它們的不同點(diǎn):1.可創(chuàng)建的IRP類型這四個(gè)函數(shù)可以創(chuàng)建的IRP的類型是不同的。IoBuildSynchronousFsdRequest用于創(chuàng)建同步的IRP請(qǐng)求,但是只可以創(chuàng)建以下類型的IRP:IRP_MJ_PNP,IRP_MJ_READ,IRP_MJ_WRITE,IRP_MJ_FLUSH_BUFFERS和IRP_MJ_SHUTDOWN;IoBuildAsynchronousFsdRequest可創(chuàng)建的IRP類型和IoBuildSynchronousFsdRequest一樣(從名字就可以看出來),只是它是用來創(chuàng)建異步的IRP請(qǐng)求。IoBuildDeviceIoControl可以創(chuàng)建的IRP類型為:IRP_MJ_DEVICE_CONTROL和IRP_MJ_INTERNAL_DEVICE_CONTROL。而且IoBuildDeviceIoControl只能創(chuàng)建同步的IRP。在這三個(gè)函數(shù)中,都有一個(gè)ULONG的輸入?yún)?shù)指定創(chuàng)建的IRP類型。IoAllocateIrp函數(shù)的使用比較靈活,他可以創(chuàng)建任意類型的IRP,但不是由參數(shù)指定,而是創(chuàng)建后自行填寫,要求用戶對(duì)IRP的結(jié)構(gòu)有比較熟悉的理解。2?創(chuàng)建后IRP對(duì)象的刪除IoBuildSynchronousFsdRequest、IoBuildAsynchronousFsdRequest和IoBuildDeviceIoControl內(nèi)核函數(shù)在創(chuàng)建完IRP后,不需要程序員負(fù)責(zé)刪除IRP,操作系統(tǒng)會(huì)自動(dòng)刪除。而用IoAllocateIrp內(nèi)核函數(shù)創(chuàng)建IRP時(shí),需要程序員自己調(diào)用IoFreeIrp內(nèi)核函數(shù)刪除IRP對(duì)象。3.關(guān)聯(lián)的事件IoBuildSynchronousFsdRequest和IoBuildDeviceIoControl在創(chuàng)建IRP時(shí),需要為它們準(zhǔn)備好一個(gè)事件,這個(gè)事件會(huì)和IRP請(qǐng)求相關(guān)聯(lián),當(dāng)IRP請(qǐng)求被結(jié)束時(shí)該事件觸發(fā)。程序中要用KeWaitForSingleObject函數(shù)等待。IoBuildAsynchronousFsdRequest函數(shù)創(chuàng)建IRP時(shí)則不需要準(zhǔn)備事件,不過可以通過IRP的UserEvent子域來通知IRP請(qǐng)求的結(jié)束。當(dāng)執(zhí)行IoCompleteRequest內(nèi)核函數(shù)時(shí),操作系統(tǒng)會(huì)檢查IRP的UserEvent子域是否為空。如果該子域?yàn)榭眨瑒t它代表一個(gè)事件指針,這時(shí)IoCompleteRequest會(huì)設(shè)置這個(gè)事件。六)驅(qū)動(dòng)和應(yīng)用層的三種通信方式驅(qū)動(dòng)程序和客戶應(yīng)用程序經(jīng)常需要進(jìn)行數(shù)據(jù)交換,但我們知道驅(qū)動(dòng)程序和客戶應(yīng)用程序可能不在同一個(gè)地址空間,因此操作系統(tǒng)必須解決兩者之間的數(shù)據(jù)交換。驅(qū)動(dòng)層和應(yīng)用層通信,主要是靠DeviceIoControl函數(shù),下面是該函數(shù)的原型:BOOLDeviceIoControl(HANDLEhDevice,//設(shè)備句柄DWORDdwIoControlCode,//IOCTL請(qǐng)求操作代碼LPVOIDlpInBuffer,//輸入緩沖區(qū)地址DWORDnInBufferSize,//輸入緩沖區(qū)大小LPVOIDlpOutBuffer,//輸出緩沖區(qū)地址DWORDnOutBufferSize,//輸出緩沖區(qū)大小LPDWORDlpBytesReturned,//存放返回字節(jié)數(shù)的指針LPOVERLAPPEDlpOverlapped//用于同步操作的Overlapped結(jié)構(gòu)體指針);dwIoControlCode要進(jìn)行操作的控制碼。驅(qū)動(dòng)程序可以通過CTL_CODE宏來組合定義一個(gè)控制碼,并在IRP_MJ_DEVICE_CONTROL的實(shí)現(xiàn)中進(jìn)行控制碼的操作。在驅(qū)動(dòng)層,irpStack->Parameters.DeviceIoControl.IoControlCode表示了這個(gè)控制碼。//////////////////////////////////////////////////////////////////////////////////////////////////////////////////IoBuildDeviceIoControl可以創(chuàng)建的IRP類型為IRP_MJ_DEVICE_CONTROL和IRP_MJ_INTERNAL_DEVICE_CONTROL。而且IoBuildDeviceIoControl只能創(chuàng)建同步的IRP//////////////////////////////////////////////////////////////////////////////////////////////////////////////////IOCTL請(qǐng)求有四種緩沖策略,下面一一介紹。1、 輸入輸出緩沖I/O(METHOD_BUFFERED)2、 直接輸入緩沖輸出I/O(METHOD_IN_DIRECT)3、 緩沖輸入直接輸出I/O(METHOD_OUT_DIRECT)4、 上面三種方法都不是(METHOD_NEITHER)為了對(duì)這些類型更詳細(xì)的描述,請(qǐng)看msdn上的解釋,我抄錄如下:"緩沖”方法(METHOD_BUFFERED)備注:在下面的討論中,"輸入"表示數(shù)據(jù)從用戶模式的應(yīng)用程序到驅(qū)動(dòng)程序,"輸出"表示數(shù)據(jù)從驅(qū)動(dòng)程序到應(yīng)用程序。對(duì)于讀取請(qǐng)求,I/O管理器分配一個(gè)與用戶模式的緩沖區(qū)大小相同的系統(tǒng)緩沖區(qū)。IRP中的SystemBuffer字段包含系統(tǒng)地址。UserBuffer字段包含初始的用戶緩沖區(qū)地址。當(dāng)完成請(qǐng)求時(shí),I/O管理器將驅(qū)動(dòng)程序已經(jīng)提供的數(shù)據(jù)從系統(tǒng)緩沖區(qū)復(fù)制到用戶緩沖區(qū)。對(duì)于寫入請(qǐng)求,會(huì)分配一個(gè)系統(tǒng)緩沖區(qū)并將SystemBuffer設(shè)置為地址。用戶緩沖區(qū)的內(nèi)容會(huì)被復(fù)制到系統(tǒng)緩沖區(qū),但是不設(shè)置UserBuffer。對(duì)于IOCTL請(qǐng)求,會(huì)分配一個(gè)容量大小足以包含輸入緩沖區(qū)或輸出緩沖區(qū)的系統(tǒng)緩沖區(qū),并將SystemBuffer設(shè)置為分配的緩沖區(qū)地址。輸入緩沖區(qū)中的數(shù)據(jù)復(fù)制到系統(tǒng)緩沖區(qū)0UserBuffer字段設(shè)置為用戶模式輸出緩沖區(qū)地址。內(nèi)核模式驅(qū)動(dòng)程序應(yīng)當(dāng)只使用系統(tǒng)緩沖區(qū),且不應(yīng)使用UserBuffer中存儲(chǔ)的地址。對(duì)于IOCTL,驅(qū)動(dòng)程序應(yīng)當(dāng)從系統(tǒng)緩沖區(qū)獲取輸入并將輸出寫入到系統(tǒng)緩沖區(qū)。當(dāng)完成請(qǐng)求時(shí),I/O系統(tǒng)將輸出數(shù)據(jù)從系統(tǒng)緩沖區(qū)復(fù)制到用戶緩沖區(qū)。"直接”方法(METHOD_IN/OUT_DIRECT)對(duì)于讀取和寫入請(qǐng)求,用戶模式緩沖區(qū)會(huì)被鎖定,并且會(huì)創(chuàng)建一個(gè)內(nèi)存描述符列表(MDL)。MDL地址會(huì)存儲(chǔ)在IRP的MdlAddress字段中。SystemBuffer和UserBuffer均沒有任何含義。但是,驅(qū)動(dòng)程序不應(yīng)當(dāng)更改這些字段的值。對(duì)于IOCTL請(qǐng)求,如果在METHOD_IN_DIRECT和METHOD_OUT_DIRECT中同時(shí)有一個(gè)輸出緩沖區(qū),則分配一個(gè)系統(tǒng)緩沖區(qū)(SystemBuffer又有了地址)并將輸入數(shù)據(jù)復(fù)制到其中。如果有一個(gè)輸出緩沖區(qū),且它被鎖定,則會(huì)創(chuàng)建MDL并設(shè)置MdlAddress。UserBuffer字段沒有任何含義。"兩者都不"方法(METHOD_NEITHER)對(duì)于讀取和寫入請(qǐng)求,UserBuffer字段被設(shè)置為指向初始的用戶緩沖區(qū)。不執(zhí)行任何其他操作。SystemAddress和MdlAddress沒有任何含義。對(duì)于IOCTL請(qǐng)求,I/O管理器將UserBuffer設(shè)置為初始的用戶輸出緩沖區(qū),而且,它將當(dāng)前I/O棧位置的Parameters.DeviceIoControl.Type3InputBuffer設(shè)置為用戶輸入緩沖區(qū)。利用該I/O方法,由驅(qū)動(dòng)程序來確定如何處理緩沖區(qū):分配系統(tǒng)緩沖區(qū)或創(chuàng)建MDL。通常,驅(qū)動(dòng)程序在訪問用戶數(shù)據(jù)時(shí)不應(yīng)當(dāng)將UserBuffer字段用作地址,即使當(dāng)用戶緩沖區(qū)被鎖定時(shí)也是如此。這是由于在調(diào)用驅(qū)動(dòng)程序時(shí),在系統(tǒng)中可能看不到調(diào)用用戶的地址空間。(對(duì)于該規(guī)則的一個(gè)例外是,在最高層驅(qū)動(dòng)程序?qū)RP向下傳遞到較低層的驅(qū)動(dòng)程序之前,它可能需要使用UserBuffer來復(fù)制數(shù)據(jù)。)如果使用"直接"或"兩者都不"方法,在創(chuàng)建MDL之后,驅(qū)動(dòng)程序可以使用MmGetSystemAddressForMdl函數(shù)來獲取有效的系統(tǒng)地址以訪問用戶緩沖區(qū)。在驅(qū)動(dòng)層,依傳輸類型的不同,輸入緩沖區(qū)的位置亦不同,見下表。傳輸類型 位置METHOD_IN_DIRECT irp->AssociatedIrp.SystemBufferMETHOD_OUT_DIRECT irp->AssociatedIrp.SystemBufferMETHOD_BUFFERED irp->AssociatedIrp.SystemBufferMETHOD_NEITHERirpStack->Parameters.DeviceIoControl.Type3InputBuffer在驅(qū)動(dòng)層,依傳輸類型的不同,輸出緩沖區(qū)的位置亦不同,見下表。傳輸類型 位置METHOD_IN_DIRECT irp->MdlAddressMETHOD_OUT_DIRECT irp->MdlAddressMETHOD_BUFFERED irp->AssociatedIrp.SystemBufferMETHOD_NEITHERirp->UserBuffer所以只要確定了傳輸方式后,就可以根據(jù)各自的位置來讀取和寫入數(shù)據(jù),從而實(shí)現(xiàn)應(yīng)用層和驅(qū)動(dòng)的通信。下面看驅(qū)動(dòng)層對(duì)ioctl控制碼的處理代碼:代碼://METHOD_OUT_DIREC方式NTSTATUSCOMM_DirectOutIo(PIRPIrp,PIO_STACK_LOCATIONploStacklrp,UINT*sizeofWrite){NTSTATUSstatus=STATUS_UNSUCCESSFUL;PVOIDpInputBuffer,pOutputBuffer;ULONGoutputLength,inputLength;DbgPrint("COMM_DirectOutIo\r\n");outputLength=pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;inputLength=pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;pInputBuffer=Irp->AssociatedIrp.SystemBuffer;pOutputBuffer=NULL;if(Irp->MdlAddress)pOutputBuffer = MmGetSystemAddressForMdlSafe(Irp->MdlAddress,NormalPagePriority);if(pInputBuffer&&pOutputBuffer){DbgPrint("COMM_DirectOutIoUserModeMessage='%s'",pInputBuffer);RtlCopyMemory(pOutputBuffer,pInputBuffer,outputLength);*sizeofWrite=outputLength;status=STATUS_SUCCESS;}returnstatus;}//METHOD_IN_DIRECTNTSTATUSCOMM_DirectInIo(PIRPIrp,PIO_STACK_LOCATIONpIoStackIrp,UINT*sizeofWrite){NTSTATUSstatus=STATUS_UNSUCCESSFUL;PVOIDpInputBuffer,pOutputBuffer;ULONGoutputLength,inputLength;DbgPrint("COMMDirectInIo\r\n");

outputLength=pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;inputLength=pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;pInputBuffer=Irp->AssociatedIrp.SystemBuffer;pOutputBuffer=NULL;MmGetSystemAddressForMdlSafe(Irp->MdlAddress,if(Irp->MdlAddress)pOutputBufferNormalPagePriority);MmGetSystemAddressForMdlSafe(Irp->MdlAddress,if(pInputBuffer&&pOutputBuffer){DbgPrint("COMM_DirectInIoUserModeMessage='%s'",pInputBuffer);RtlCopyMemory(pOutputBuffer,pInputBuffer,outputLength);*sizeofWrite=outputLength;status=STATUS_SUCCESS;}returnstatus;}//METHOD_BUFFEREDNTSTATUSCOMM_BufferedIo(PIRPIrp,PIO_STACK_LOCATIONpIoStackIrp,UINT*sizeofWrite){NTSTATUSstatus=STATUS_UNSUCCESSFUL;PVOIDpInputBuffer,pOutputBuffer;ULONGoutputLength,inputLength;DbgPrint("COMM_BufferedIo\r\n");outputLength=pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;inputLength=pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;pInputBuffer=Irp->AssociatedIrp.SystemBuffer;pOutputBuffer=Irp->AssociatedIrp.SystemBuffer;if(pInputBuffer&&pOutputBuffer){DbgPrint("COMM_BufferedIoUserModeMessage='%s'",pInputBuffer);RtlCopyMemory(pOutputBuffer,pInputBuffer,outputLength);*sizeofWrite=outputLength;status=STATUS_SUCCESS;}returnstatus;//METHOD_NEITHERNTSTATUSCOMM_NeitherIo(PIRPIrp,PIO_STACK_LOCATIONploStacklrp,UINT*sizeofWrite){NTSTATUSstatus=STATUS_UNSUCCESSFUL;PVOIDpInputBuffer,pOutputBuffer;ULONGoutputLength,inputLength;DbgPrint("COMM_NeitherIo\r\n");outputLength=pIoStackIrp->Parameters.DeviceIoControl.OutputBufferLength;inputLength=pIoStackIrp->Parameters.DeviceIoControl.InputBufferLength;pInputBuffer=pIoStackIrp->Parameters.DeviceIoControl.Type3InputBuffer;pOutputBuffer=Irp->UserBuffer;if(pInputBuffer&&pOutputBuffer){DbgPrint("COMM_NeitherIoUserModeMessage='%s'",pInputBuffer);RtlCopyMemory(pOutputBuffer,pInputBuffer,outputLength);*sizeofWrite=outputLength;status=STATUS_SUCCESS;}returnstatus;}代碼比較簡單,都是取得輸入的數(shù)據(jù),然后把數(shù)據(jù)直接拷貝到輸出,傳輸給應(yīng)用層。應(yīng)用層的代碼:procedureTfrmMain.Send_Recv_Data(AInData:String;varAOutData:String;IoctlCode:DWORD);vardwReturn:DWORD;inData:array[0..1023]ofchar;outData:array[0..1023]ofchar;beginStrPCopy(inData,AInData);ifm_hCommDevice<>0thenbeginDeviceIoControl(m_hCommDevice,IoctlCode,@inData,Length(inData),@outData,Length(outData),dwReturn,nil);AOutData:=StrPas(@outData);end;end;上面是進(jìn)行發(fā)送和接受的過程。需要通信,只要如下做:代碼:procedureTfrmMain.btnDirect_IN_IOClick(Sender:TObject);varoutData:String;beginSend_Recv_Data(Trim(edtDirect_in_in.Text),outData,IOCTL_COMM_DIRECT_IN_IO);edtDirect_in_out.Text:=outData;end;這是direct_in方式通信,其他通信方式類似,可以參考代碼了,這里就不列舉了,由于代碼比較簡單,我就不多說了,還是看代碼吧,很好明白。(七)SSDT詳解1.什么是SSDT自然,這個(gè)是我必須回答的問題。不過在此之前,請(qǐng)你打開命令行(cmd.exe)窗口,并輸入“dir”并回車一一好了,列出了當(dāng)前目錄下的所有文件和子目錄。那么,以程序員的視角來看,整個(gè)過程應(yīng)該是這樣的:由用戶輸入dir命令。cmd.exe獲取用戶輸入的dir命令,在內(nèi)部調(diào)用對(duì)應(yīng)的Win32API函數(shù)FindFirstFile、FindNextFile和FindClose,獲取當(dāng)前目錄下的文件和子目錄。cmd.exe將文件名和子目錄輸出至控制臺(tái)窗口,也就是返回給用戶。到此為止我們可以看到,cmd.exe扮演了一個(gè)非常至關(guān)重要的角色,也就是用戶與Win32API的交互?!愦蟾乓呀?jīng)可以猜到,我下面要說到的SSDT亦必將扮演這個(gè)角色,這實(shí)在是一點(diǎn)新意都沒有。沒錯(cuò),你猜對(duì)了。SSDT的全稱是SystemServicesDescriptorTable,系統(tǒng)服務(wù)描述符表。這個(gè)表就是一個(gè)把ring3的Win32API和ringO的內(nèi)核API聯(lián)系起來的角色,下面我將以API函數(shù)OpenProcess為例說明這個(gè)聯(lián)系的過程。你可以用任何反匯編工具來打開你的kernel32.dll,然后你會(huì)發(fā)現(xiàn)在OpenProcess中有類似這樣的匯編代碼:匯編代碼:Callds:NtOpenProcess這就是說,OpenProcess調(diào)用了ntdll.dll的NtOpenProcess函數(shù)。那么繼續(xù)反匯編之,你會(huì)發(fā)現(xiàn)ntdll.dll中的這個(gè)函數(shù)很短:匯編代碼:moveax,7Ah〃服務(wù)號(hào)對(duì)應(yīng)服務(wù)表索引movedx,7FFE0300h〃calldwordptr[edx]retn10h另外,call的一句實(shí)質(zhì)是調(diào)用了KiFastSystemCall:另外,匯編代碼:movedx,espsysenter上面是我的XPProfessionalsp2中ntdll.dll的反匯編結(jié)果,如果你用的是2000系統(tǒng),那么可能是這個(gè)樣子:匯編代碼:moveax,6Ahleaedx,[esp+4]int2Ehretn10h雖然它們存在著些許不同,但都可以這么來概括:把一個(gè)數(shù)放入eax(XP是0x7A,2000是0x6A),這個(gè)數(shù)值稱作系統(tǒng)的服務(wù)號(hào)。把參數(shù)堆棧指針(esp+4)放入edx。sysenter或int2Eh。好了,你在ring3能看到的東西就到此為止了。事實(shí)上,在ntdll.dll中的這些函數(shù)可以稱作真正的NT系統(tǒng)服務(wù)的存根(Stub)函數(shù)。分隔ring3與ring0城里城外的這一道嘆息之墻,也正是由它們打通的。接下來SSDT就要出場(chǎng)了,comesomemusic。2.SSDT有何用插一句先,貌似到現(xiàn)在為止我仍然沒有講出來SSDT是個(gè)什么東西,真正可以算是“猶抱琵琶半遮面”了?!獣由衔?,在你調(diào)用sysenter或int2Eh之后,Windows系統(tǒng)將會(huì)捕獲你的這個(gè)調(diào)用,然后進(jìn)入ring0層,并調(diào)用內(nèi)核服務(wù)函數(shù)NtOpenProcess,這個(gè)過程如下圖所示。SSDT在這個(gè)過程中所扮演的角色是至關(guān)重要的。讓我們先看一看它的結(jié)構(gòu),如下圖。SSDT ntoskrnl.exe(0x0000)Address1——nt!NtAcceptConnectPort???——???(0x007A)AddEess122—nt!NtOpenProcess——當(dāng)程序的處理流程進(jìn)入ringO之后,系統(tǒng)會(huì)根據(jù)服務(wù)號(hào)(eax)在SSDT這個(gè)系統(tǒng)服務(wù)描述符表中查找對(duì)應(yīng)的表項(xiàng),這個(gè)找到的表項(xiàng)就是系統(tǒng)服務(wù)函數(shù)NtOpenProcess的真正地址。之后,系統(tǒng)會(huì)根據(jù)這個(gè)地址調(diào)用相應(yīng)的系統(tǒng)服務(wù)函數(shù),并把結(jié)果返回給ntdll.dll中的NtOpenProcess。圖中的“SSDT”所示即為系統(tǒng)服務(wù)描述符表的各個(gè)表項(xiàng);右側(cè)的“ntoskrnl.exe”則為Windows系統(tǒng)內(nèi)核服務(wù)進(jìn)程(ntoskrnl即為NTOSKerneL的縮寫),它提供了相對(duì)應(yīng)的各個(gè)系統(tǒng)服務(wù)函數(shù)。ntoskrnl.exe這個(gè)文件位于Windows的system32目錄下,有興趣的朋友可以反匯編一下。附帶說兩點(diǎn)。根據(jù)你處理器的不同,系統(tǒng)內(nèi)核服務(wù)進(jìn)程可能也是不一樣的。真正運(yùn)行于系統(tǒng)上的內(nèi)核服務(wù)進(jìn)程可能還有ntkrnlmp.exe、ntkrnlpa.exe這樣的情況不過為了統(tǒng)一起見,下文仍統(tǒng)稱這個(gè)進(jìn)程為ntoskrnl.exe。另夕卜,SSDT中的各個(gè)表項(xiàng)也未必會(huì)全部指向ntoskrnl.exe中的服務(wù)函數(shù),因?yàn)槟銠C(jī)器上的殺毒監(jiān)控或其它驅(qū)動(dòng)程序可能會(huì)改寫SSDT中的某些表項(xiàng)——這也就是所謂的“掛鉤SSDT”——以達(dá)到它們的“主動(dòng)防御”式殺毒方式或其它的特定目的。KeServiceDescriptorTable事實(shí)上,SSDT并不僅僅只包含一個(gè)龐大的地址索引表,它還包含著一些其它有用的信息,諸如地址索引的基地址、服務(wù)函數(shù)個(gè)數(shù)等等。ntoskrnl.exe中的一個(gè)導(dǎo)出項(xiàng)KeServiceDescriptorTable即是SSDT的真身,亦即它在內(nèi)核中的數(shù)據(jù)實(shí)體。SSDT的數(shù)據(jù)結(jié)構(gòu)定義如下:typedefstruct_tagSSDT{PVOIDpvSSDTBase;PVOIDpvServiceCounterTable;ULONGulNumberOfServices;PVOIDpvParamTableBase;}SSDT,*PSSDT; 其中,pvSSDTBase就是上面所說的“系統(tǒng)服務(wù)描述符表”的基地址。pvServiceCounterTable則指向另一個(gè)索引表,該表包含了每個(gè)服務(wù)表項(xiàng)被調(diào)用的次數(shù);不過這個(gè)值只在CheckdBuild的內(nèi)核中有效,在FreeBuild的內(nèi)核中,這個(gè)值總為NULL(注:Check/Free是DDK的Build模式,如果你只使用SDK,可以簡單地把它們理解為Debug/Release)。ulNumberOfServices表示當(dāng)前系統(tǒng)所支持的服務(wù)個(gè)數(shù)。pvParamTableBase指向SSPT(SystemServiceParameterTable,即系統(tǒng)服務(wù)參數(shù)表),該表格包含了每個(gè)服務(wù)所需的參數(shù)字節(jié)數(shù)。下面,讓我們開看看這個(gè)結(jié)構(gòu)里邊到底有什么。打開內(nèi)核調(diào)試器(以kd為例),輸入命令顯示KeServiceDescriptorTable,如下。Windbg輸出:lkd>ddKeServiceDescriptorTable148055ab80804e3d20000000000000011c804d9f48接下來,亦可根據(jù)基地址與服務(wù)總數(shù)來查看整個(gè)服務(wù)表的各項(xiàng):Windbg輸出:lkd>dd804e3d20l11c804e3d2080587691f84317aaf84317b4f84317be804e3d30f84317c8f84317d2f84317dcf84317e6804e3d408057741cf84317faf8431804f843180e804e3d50f8431818f8431822f843182cf8431836你獲得的結(jié)果可能和我會(huì)有不同一一我指的是那堆以十六進(jìn)制f開頭的地址項(xiàng),因?yàn)槲业腟SDT被SystemSafetyMonitor接管了,沒留下幾個(gè)原生的ntoskrnl.exe表項(xiàng)?,F(xiàn)在是寫些代碼的時(shí)候了。KeServiceDescriptorTable及SSDT各個(gè)表項(xiàng)的讀取只能在ring0層完成,于是這里我使用了內(nèi)核驅(qū)動(dòng)并借助DeviceIoControl來完成。其中DeviceIoControl的分發(fā)代碼實(shí)現(xiàn)如下面的代碼所示,沒有什么技術(shù)含量,所以不再解釋。switch(IoControlCode){caseIOCTL_GETSSDT:{—try{ProbeForWrit

溫馨提示

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

評(píng)論

0/150

提交評(píng)論