久久国产成人av_抖音国产毛片_a片网站免费观看_A片无码播放手机在线观看,色五月在线观看,亚洲精品m在线观看,女人自慰的免费网址,悠悠在线观看精品视频,一级日本片免费的,亚洲精品久,国产精品成人久久久久久久

分享

手把手跟我學(xué)驅(qū)動(dòng)(1)

 創(chuàng)科之龍 2010-11-20

大概是一個(gè)多星期以前吧,也說不上是出于什么特殊目的,我開始學(xué)上驅(qū)動(dòng)來了,,這是我第一次寫點(diǎn)心得之類的文章,,我起步的時(shí)候也沒少走彎路,現(xiàn)在,,至少我可以寫一個(gè)基本的驅(qū)動(dòng)框架來了,,也挺不容易,所以我把我學(xué)習(xí)的路子寫出來,,和跟我一樣的新手們交流一下,,正要學(xué)寫驅(qū)動(dòng)的同志們可以借鑒一下。前一陣子,,不知道是怎么跑到兩個(gè)專門寫驅(qū)動(dòng)的群里面了,,在那里面,看到了傳說中的大牛,,也結(jié)識了大牛中的一些中牛,,其中也有幫了我不少的不知道是什么樣的牛。在這里我要特別感謝文件系統(tǒng)驅(qū)動(dòng)群里的“被剃毛的老鷹”,,“哆啦B夢”,,LookSail,qi等,正是因?yàn)樗麄?,我才有了今天的進(jìn)步,,盡管這只是一個(gè)小小的進(jìn)步而已。

一,、生產(chǎn)工具:

首先,,得準(zhǔn)備好微軟的驅(qū)動(dòng)開發(fā)包,我這里用的是WDK(Windows Driver Kit)6001,,因?yàn)樗锩娴木幾g環(huán)境我不會(huì)用,,所以,我選用了集成環(huán)境,,這里我使用的VS2008.這兩個(gè)工具在網(wǎng)上都有下,,至于下載和安裝,都是你自己的事情了,。

二,、開工了:

還記得我們當(dāng)初第一次寫C程序嗎?每一個(gè)C程序都有一個(gè)必須的東西,,即main主函數(shù),,它是程序執(zhí)行的起點(diǎn),后來我們熟悉了,我們會(huì)在編譯器編譯的時(shí)候指定另一個(gè)函數(shù)入口為主函數(shù)起點(diǎn),。這里所要說的驅(qū)動(dòng)程序也是有一個(gè)類似的入口,,一般我們都會(huì)把這個(gè)名字叫DriverEntry,和一般的C程序一樣,,這個(gè)函數(shù)入口也可以設(shè)置成為另外一個(gè)名字,,如果是在命令行的話,給個(gè)參數(shù) -entry: NewEntryName即可,,后面的部分,,我們可以在VS里面設(shè)置這個(gè)入口。

一般的Windows應(yīng)用程序在主入口函數(shù)完成相關(guān)的初始化工作以后,,就開始一個(gè)消息循環(huán),,進(jìn)行消息處理。驅(qū)動(dòng)程序也有點(diǎn)像像了,,驅(qū)動(dòng)程序在主入口函數(shù)中完成相關(guān)的初始化之后便處于睡眠狀態(tài),,開始等待外圍請求。驅(qū)動(dòng)程序的主要消息都被Windows打包成IRP包,,相關(guān)的知識如果你都還不明白的話,,我想你可以參考MSDN或者是百度一下,網(wǎng)絡(luò)應(yīng)該成為你的朋友,。

我們就以DriverEntry為例來說明吧,,這個(gè)函數(shù)原型如下:

NTSTATUS  DriverEntry(PDEVICE_OBJECT pDrvObj,PUNICODE_STRING pRegPath)

第一個(gè)參數(shù)是驅(qū)動(dòng)模塊對象,由操作系統(tǒng)內(nèi)核分配好傳來,,以我的理解吧,就和我們的Win32應(yīng)用程序的第一個(gè)參數(shù)HINSTANCE一樣,,第二個(gè)參數(shù)是操作系統(tǒng)傳來的驅(qū)動(dòng)在注冊表中路徑,。和以前的main函數(shù)一樣,DriverEntry函數(shù)也是做一些初始化的工作,,下面一起來看看一個(gè)基本的最簡單的驅(qū)動(dòng)程序框架,。

一個(gè)基本的驅(qū)動(dòng)程序框架里面,我們做的最主要的事情就是創(chuàng)建設(shè)備對象,,還有初始化一些必要的IRP例程入口,,如果必段的話,我們還必須創(chuàng)建必要的Dos連接符號名一樣,,就和C盤對應(yīng)于\Harddisk\partition1一樣,,行,不廢話了,,一起寫一個(gè)簡單的DriverEntry吧:

#include <wdm.h>

void Example1Unload(PDRIVER_OBJECT pDrvObj)

{

UNICODE_STRING usDosDevName;//Dos符號鏈接

DbgPrint("Example1: Driver is being unloaded.\n");

//首先我們要?jiǎng)h除的是一個(gè)Dos鏈接名,,否則,這個(gè)鏈接名便不再可用,,直到系統(tǒng)重啟

//不過,這個(gè)Dos鏈接名應(yīng)該和我們在DriverEntry里創(chuàng)建的一樣,千萬記得了

RtlInitUnicodeString(&usDosDevName,L"\\DosDevices\\Example1");

IoDeleteSymbolicLink(&usDosDevName);

//接下來,,我們再刪除驅(qū)動(dòng)程序創(chuàng)建的設(shè)備對象,,在此之后,系統(tǒng)將會(huì)把我們的驅(qū)動(dòng)從內(nèi)核移除

//我們的驅(qū)動(dòng)便是被卸載了

IoDeleteDevice(pDrvObj->DeviceObject);

//OK,所有的事情已經(jīng)解決

}

NTSTATUS Example1IrpRoutine(PDRIVER_OBJECT pDev,PIRP pIrp)

{

//在調(diào)試器中輸出一個(gè)字符串,,你還記得Win32下的TRACE系列宏嗎

DbgPrint("An driver routine is called.\n");

return STATUS_SUCCESS;//簡單地返回成功而已

}

//驅(qū)動(dòng)入口函數(shù)

NTSTATUS DriverEntry(PDRIVER_OBJECT pDrvObj,PUNICODE_STRING pUsRegPath)

{

NTSTATUS status = STATUS_UNSUCCESSFUL;//初始化為不成功

UNICODE_STRING usDevName;//我們的設(shè)備名

UNICODE_STRING usDosDevName;//Dos符號鏈接

PDEVICE_OBJECT pDevObj = NULL;//設(shè)備對象

unsigned int nIndex;//一個(gè)計(jì)數(shù)器,循環(huán)的時(shí)候可以用到

DbgPrint("Example1: Driver entry is called.\n");

//__try{

//初始化兩個(gè)Unicodestring

RtlInitUnicodeString(&usDevName,L"\\Device\\Example1");

RtlInitUnicodeString(&usDosDevName,L"\\DosDevices\\Example1");

//現(xiàn)在我們創(chuàng)建設(shè)備

status = IoCreateDevice(pDrvObj,0,&usDevName,FILE_DEVICE_UNKNOWN,

FILE_DEVICE_SECURE_OPEN,FALSE,&pDevObj);

//只有成功創(chuàng)建設(shè)備我們才有必要繼續(xù)

if(NT_SUCCESS(status)){//測試成功與否一般用這個(gè)宏,而不是讓它直接與STATUS_SUCCESS比 //較,查看一下這個(gè)宏定義就知道了

//成功創(chuàng)建設(shè)備之后,我們要作的一件事就是初使化驅(qū)動(dòng)的IRP例程,,現(xiàn)在,我們的驅(qū)動(dòng)什么 都不干,,所以,,每個(gè)例程也還是什么都不做

//每個(gè)設(shè)備最多有IRP_MJ_MAXIMUM_FUNCTION個(gè)IRP例程,現(xiàn)在,,我們都把它們初始 //化成一個(gè)相同的入口

for(nIndex=0;nIndex<IRP_MJ_MAXIMUM_FUNCTION;++nIndex)

pDrvObj->MajorFunction[nIndex] = Example1IrpRoutine;

//接下來,,我再安裝一個(gè)卸載例程,從而,,使我們的驅(qū)動(dòng)可以動(dòng)態(tài)的卸載,,這就是傳說中的 //熱插撥

pDrvObj->DriverUnload = Example1Unload;

//把創(chuàng)建的設(shè)備保存起來吧,否則以后便不能引用啦

pDrvObj->DeviceObject = pDevObj;

//好了,創(chuàng)建符號鏈接,正是由于有了符號鏈接,我們可以用C:來訪問第一個(gè)硬盤分區(qū)……

status = IoCreateSymbolicLink(&usDosDevName,&usDevName);

if(!NT_SUCCESS(status)){

//在這里定義了如果創(chuàng)建Dos鏈接失敗將做的事情,如果我們不需要一個(gè)Dos符號鏈接, //這一步便不是必須的,更不必檢驗(yàn)了

IoDeleteDevice(pDevObj);//刪除創(chuàng)建的設(shè)備對象

//這個(gè)時(shí)候,status肯定就代表失敗了,如果入口函數(shù)返回一個(gè)失敗的狀態(tài),系統(tǒng)會(huì)自動(dòng)把 //創(chuàng)建的這個(gè)Driver刪除的,我們不用擔(dān)心

}

}

//現(xiàn)在,我們測試一下成功與否

//}__except(EXCEPTION_EXECUTE_HANDLER){

//如果出現(xiàn)一般的異常,執(zhí)行流程會(huì)走到這兒來,除了一些SEH都解決不了的異常除外,這個(gè)我們以 //后再討論

//}

return status;//

}

至此,一個(gè)簡單的設(shè)備驅(qū)動(dòng)程序框架已經(jīng)完成了,,難道不是嗎,?在這個(gè)驅(qū)動(dòng)里面,我們創(chuàng)建的設(shè)備\Device\Example1,這里,Device是設(shè)備對象的所屬名字空間,,Example1才是它的名字,。事實(shí)上,它只是一個(gè)需擬設(shè)備驅(qū)動(dòng)程序,,并沒有一個(gè)實(shí)際的設(shè)備與之相對應(yīng),。

但是,這里只是介紹了這么一個(gè)框架程序代碼,,還得編譯鏈接呢,!

三、編譯鏈接:

我說過,,我水平有限,,不會(huì)使用WDK(或是DDK)集成的編譯鏈接環(huán)境,所以我選擇使用WDK+VS2008.

1.建立工程,。VS里面沒有為現(xiàn)成的驅(qū)動(dòng)工程向?qū)?,所以,我一般都建立一個(gè)Win32工程(我常會(huì)用Console),,只是,,建立一個(gè)空項(xiàng)目即可,你可別指望向?qū)傻拇a文件在你的驅(qū)動(dòng)里面有用,!

2.添加代碼文件,。添加新項(xiàng),選擇源程序代碼文件,不過,,這里一般用C文件,,至于原因,我不想多解釋,,現(xiàn)在只是一個(gè)簡單的代碼,,所以,我都在一個(gè)文件里面寫完,。就是把我剛才在上面的代碼復(fù)制到你剛新建的源文件里就行了,。

3.設(shè)置編譯選項(xiàng)。還記得安裝了WDK吧,,既然如果,,就要用到它了,再說了,,以前還沒用到過#include <wdm.h>之類的語句吧,?好了,在附加包含路徑設(shè)置成WDK中的inc路徑,,一般如下,,

WDKROOT\inc\api

WDKROOT\inc\crt

WDKROOT\inc\ddk

另外,同于驅(qū)動(dòng)是接近硬件的程序,,它可以執(zhí)行絕大多數(shù)CPU指令,,從而,我們還得為我們的驅(qū)動(dòng)程序指定目標(biāo)CPU平臺(tái),,這里,,我選X86.需要在預(yù)定義里定義添加一個(gè)_X86_的定義,否則會(huì)收到一個(gè)需要指定目標(biāo)平臺(tái)(target architecture)的編譯錯(cuò)誤,。

4.鏈接先項(xiàng)?,F(xiàn)在的設(shè)置的話,生成的文件還是exe后綴呢,,但驅(qū)動(dòng)都是sys后綴,所以,,你得改,,在什么地方改,我不說了,。另外,,得添加一個(gè)輸入庫,就是附加依賴項(xiàng):ntoskrnl.lib這個(gè)時(shí)候,,又得設(shè)置附加庫目錄了,,設(shè)置成 WDKROOT\lib\wxp\i386

別忘了,我們現(xiàn)在的工程還是個(gè)console項(xiàng)目呢,得改,,找到鏈接選項(xiàng)卡,,System(子系統(tǒng))一項(xiàng)選擇Native,還有驅(qū)動(dòng)選/Driver.

5.OK,,現(xiàn)在試著生成一下吧,。如果沒有語法錯(cuò)誤的話,它還是會(huì)有一大堆錯(cuò)誤的,,好,,我當(dāng)初寫的時(shí)候也是這樣,那,,我現(xiàn)在把所有的設(shè)置一股腦告訴你,,你就別走彎路了,遇到其它別的問題再說,,主要精力別放在這兒就行了,。

①C/C++->Preprocessor: Ignor Standard include path  YES

②C/C++->Code generation: Basic Runtime Check  Default;  Buffer security check  No(GS-)

③C/C++->Advanced: Calling convertion   __stdcall(/Gz)

③Linker->Input: Ignor All default libraries   YES

④linker->Manifest file: Generate manifest    No

⑤Linker->Advaced:  Entry point  DriverEntry;   Base address   0x100000;  Ramdomized base address  Default;   Data execution prevention   Default;

四.啟動(dòng)驅(qū)動(dòng)程序。

把生成的example1.sys復(fù)制到一個(gè)地方,,我這里是C:\然后,,使用以下程序加載程序加載驅(qū)動(dòng):

int _cdecl main(void)

{

    HANDLE hSCManager;

    HANDLE hService;

    SERVICE_STATUS ss;

    hSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CREATE_SERVICE);

    

    printf("Load Driver\n");

    if(hSCManager)

    {

        printf("Create Service\n");

        hService = CreateService(hSCManager, "Example1", 

                                 "Example1 Driver", 

                                  SERVICE_START | DELETE | SERVICE_STOP, 

                                  SERVICE_KERNEL_DRIVER,

                                  SERVICE_DEMAND_START, 

                                  SERVICE_ERROR_IGNORE, 

                                  "C:\\example1.sys", 

                                  NULL, NULL, NULL, NULL, NULL);

        if(!hService)

        {

            hService = OpenService(hSCManager, "Example1", 

                       SERVICE_START | DELETE | SERVICE_STOP);

        }

        if(hService)

        {

            printf("Start Service\n");

            StartService(hService, 0, NULL);

            printf("Press Enter to close service\r\n");

            getchar();

            ControlService(hService, SERVICE_CONTROL_STOP, &ss);

            DeleteService(hService);

            CloseServiceHandle(hService);

            

        }

        CloseServiceHandle(hSCManager);

    }

    

    return 0;

}

這段代碼是我直接從其它地方復(fù)制過來的,經(jīng)過我的試驗(yàn),,并不總是好使的,,但是,只要執(zhí)行一次就好辦了,,以后就不再需要它啦,。因?yàn)椋趫?zhí)行一次CreateService之后,,它就會(huì)在注冊表的HKLM\CurrentControlSet\System\Services\下創(chuàng)建一個(gè)子鍵Example1,在以后我們的驅(qū)動(dòng)的例子,,就不再使用上面的加載程序,而是直接修改這個(gè)注冊表鍵了(當(dāng)然,,并不是最終目標(biāo),,在此,只是圖個(gè)方便,,以后,,有一天,會(huì)使用標(biāo)準(zhǔn)安裝文件inf),。Example1子鍵下面有個(gè)ImagePath子項(xiàng)指定了這個(gè)服務(wù)的目標(biāo)路徑,。第一次,如果上面的程序執(zhí)行成功,,再按以下回車就卸載了,。以后,,將使用Dos命令來啟動(dòng)和停止它,啟動(dòng): net start example1,,停止:net stop example.是不是很簡單了,?

五、測試:

現(xiàn)在好了,,既然我們的驅(qū)動(dòng)能加載了,,我們就試一下,寫一個(gè)一般的Win32程序,,使用如下語句:

CreateFile("\\\\.\\Example1",GENERIC_READ|GENERIC_WRITE,FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,NULL,OPEN_EXISTING,0,NULL)試一下,。是不是能成功返回一個(gè)句柄了?

六,、總結(jié):

本文主要記錄了我怎么使用VS2008+WDK創(chuàng)建我的第一個(gè)驅(qū)動(dòng)程序的過程,,這個(gè)程序我保證絕對是我的第一個(gè)程序,上個(gè)周末寫的,。哈哈,。雖然我的介紹沒有楚狂人或是wowocock的那么獨(dú)到,那么吸引人,,它只是紹了構(gòu)建一個(gè)驅(qū)動(dòng)框架的基本方法,。相關(guān)的系統(tǒng)知識得參考MSDN。在下一篇中我將介紹幾種IO例程和相關(guān)的內(nèi)存使用方法,,實(shí)現(xiàn)驅(qū)動(dòng)的不同版本的讀寫例程,。有興趣的,等著吧,,嘿嘿,。

好不容易,記下了我學(xué)習(xí)的過程,,有興趣一起學(xué)習(xí)交流的或是有問題的歡迎與我聯(lián)系,,有錯(cuò)請指正,謝謝,,QQ:178041876

特別聲明:轉(zhuǎn)載請注明出處

    本站是提供個(gè)人知識管理的網(wǎng)絡(luò)存儲(chǔ)空間,,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn),。請注意甄別內(nèi)容中的聯(lián)系方式,、誘導(dǎo)購買等信息,謹(jǐn)防詐騙,。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報(bào),。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多