程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> 更多編程語言 >> Delphi >> Delphi研究之驅動開發篇(二)--工具及環境搭建

Delphi研究之驅動開發篇(二)--工具及環境搭建

編輯:Delphi

作 者: mickeylan
時 間: 2008-01-10,21:16
鏈 接: http://bbs.pediy.com/showthread.php?t=58070

上篇教程主要是講解了用Delphi開發Windows驅動程序需要解決的一些技術上的問題,雖然啰嗦了一大堆,也不知道講清楚了沒有^_^。本篇我們開始講述用Delphi構建驅動開發環境。
用Delphi開發驅動程序所必須的工具:
   Dcc32.exe – Delphi編譯器,我用的是Delphi 2007的dcc32
   rmcoff    -- 我用BCB開發的Delphi目標文件符號名修改、OMF到coff格式轉換以及刪除obj文件中無用代碼及重復符號的工具
   Link.exe   -- microsoft鏈接器,不要使用7.1xx版的,似乎有bug
   DDK相關結構、APIs的Delphi聲明文件(我已經完成部分結構、APIs的聲明轉換,放在我的KmdKit4D工具包裡)
有上面的東東就可以開發Windows驅動程序了,下面就讓我們來寫一個最簡單的驅動程序:

代碼:unit driver;

interface

uses nt_status, ntoskrnl;

function _DriverEntry(DriverObject:PDriverObject;RegistryPath:PUnicodeString):NTSTATUS; stdcall;

implementation

procedure DriverUnload(DriverObject:PDriverObject); stdcall;
begin
 DbgPrint(DriverUnload(DriverObject:0x%.8X),[DriverObject]);
 DbgPrint(DriverUnload(-),[]);
end;

function _DriverEntry(DriverObject:PDriverObject;RegistryPath:PUnicodeString):NTSTATUS; stdcall;
begin
 DbgPrint(DriverEntry(DriverObject:0x%.8X;RegistryPath:0x%.8X),[DriverObject,RegistryPath]);

 DriverObject^.DriverUnload:=@DriverUnload;

 Result:=STATUS_SUCCESS;
 DbgPrint(DriverEntry(-):0x%.8X,[Result]);
end;

end.
   以上就是一個最簡單的驅動程序,就像其他的可執行程序一樣,每個驅動程序也有一個入口點,這是當驅動被裝載到內存中時首先被調用的,驅動的入口點是DriverEntry過程(注:過程也就是子程序),DriverEntry這個名稱只是一個標記而已,你可以把它命名為其他任何名字--只要它是入口點就行了。DriverEntry過程用來對驅動程序的一些數據結構進行初始化,它的函數原型定義如下:
   代碼:function _DriverEntry(DriverObject:PDriverObject;RegistryPath:PUnicodeString):NTSTATUS; stdcall;
   當然你也可以不用DriverEntry這個名字,任意的名字都可以,不過前面的下劃線是必需的。nt_status和 ntoskrnl兩個單元包含了常用的數據結構和APIs的聲明。由於我常開發Unix下的程序,所以我習慣使用make編譯程序,個人感覺make比較智能和方便,因此在推薦大家使用make編譯程序。我用的是borland make 5.2版。Makefile的寫法可以參考http://bbs.pediy.com/showthread.php?t=56912,以下是編譯這個程序的makefile:

代碼:NAME=driver
DCC=dcc32
INCLUDE=d:mickeylanKmdKit4Dinclude
LIB_PATH=d:mickeylanKmdKit4Dlib
DCCFLAGS=-U$(INCLUDE) -B -CG -JP -$A-,C-,D-,G-,H-,I-,L-,P-,V-,W+,Y-
LIBS=ntoskrnl.lib hal.lib win32k.lib ntdll.lib
LINKFLAGS=/NOLOGO /ALIGN:32 /BASE:0x10000 /SUBSYSTEM:NATIVE /DRIVER /LIBPATH:$(LIB_PATH) /FORCE:UNRESOLVED /FORCE:MULTIPLE /ENTRY:DriverEntry

all : $(NAME).sys

$(NAME).sys : $(NAME).obj     
     omf2d $(NAME).obj /U_*
     link $(LINKFLAGS) $(LIBS) /out:$(NAME).sys $(NAME).obj
      
$(NAME).obj : $(NAME).pas
     $(DCC) $(DCCFLAGS) $(NAME).pas

clean :     
     del *.obj
     del *.dcu
     del *.sys
       在命令行下執行make即可編譯生成驅動文件,是不是很簡單^_^。此程序的源碼放在KmdKit4D的sampleasic目錄下,該目錄下還有一個loaddriver.bat,執行此批處理文件即可加載驅動,並且可以在DbgView的窗口裡看見驅動程序輸出的調試信息。
     到這裡,你應該對用Delphi開發驅動程序有了個大體的了解了,下面讓我們再來寫一個很有趣的驅動程序以加深了解。這個程序是從Four-F的KmdKit的giveio轉換來的(我比較懶,不想寫新的^_^),寫個驅動程序讓用戶模式下的進程能通過讀取端口來訪問電腦的CMOS。
     大家都知道,端口是被Windows保護起來的,正常情況下,用戶模式下的程序是無法直接操作端口的,通過我們的驅動程序修改I/O許可位圖(I/O permission bit map,IOPM),這樣用戶模式下的相應進程就被允許自由地存取I/O端口,這方面詳細資料見http://www.intel.com/design/intarch/techinfo/pentium/PDF/inout.pdf。每個進程都有自己的I/O許可位圖,每個單獨的I/O端口的訪問權限都可以對每個進程進行單獨授權,如果相關的位被設置的話,對對應端口的訪問就是被禁止的,如果相關的位被清除,那麼進程就可以訪問對應的端口。既然I/O地址空間由64K個可單獨尋址的8位I/O端口組成,IOPM表的最大尺寸就是2000h字節(注:每個端口的權限用1個bit表示,64K個端口除以8得到的就是IOPM的字節數,也就是65536/8=8192字節=2000h字節)。
     TSS的設計意圖是為了在任務切換的時候保存處理器狀態,從執行效率的考慮出發,Windows NT並沒有使用這個特征,它只維護一個TSS供多個進程共享,這就意味著IOPM也是共享的,因此某個進程改變了IOPM的話,造成的影響是系統范圍的。
     ntoskrnl.exe中有些未公開的函數是用來維護IOPM的,它們是Ke386QueryIoAccessMap和Ke386SetIoAccessMap函數。
代碼:function Ke386QueryIoAccessMap(
     dwFlag:DWORD;
     pIopm:PVOID): NTSTATUS; stdcall;
       Ke386QueryIoAccessMap函數從TSS中拷貝2000h字節的當前IOPM到指定的內存緩沖區中,緩沖區指針由pIopm參數指定。
     各參數描述如下:
     ◎ dwFlag--0表示將全部緩沖區用0FFh填寫,也就是所有的位都被設置,所有的端口都被禁止訪問;1表示從TSS中將當前IOPM拷貝到緩沖區中
     ◎ pIopm--用來接收當前IOPM的緩沖區指針,注意緩沖區的大小不能小於2000h字節

     如果函數執行成功的話會在返回值的低8位返回非0值;如果執行失敗則返回零。

     代碼:function Ke386SetIoAccessMap(
           dwFlag:DWORD;
           pIopm:PVOID): NTSTATUS; stdcall;
       Ke386SetIoAccessMap函數剛好相反,它從pIopm參數指定的緩沖區中拷貝2000h字節的IOPM到TSS中去。
     各參數描述如下:
     ◎ dwFlag--這個參數只能是1,其他任何值函數都會返回失敗
     ◎ pIopm--指向包含IOPM數據的緩沖區,緩沖區的尺寸不能小於2000h字節

     如果函數執行成功的話會在返回值的低8位返回非0值;如果執行失敗則返回零
當IOPM拷貝到TSS後,IOPM的偏移指針必須被定位到新的數據中去,這可以通過Ke386IoSetAccessProcess函數來完成,這也是ntoskrnl.exe中的一個很有用的未公開函數。

     代碼:function Ke386IoSetAccessProcess(
           pProcess: PKPROCESS;
           dwFlag:DWORD): NTSTATUS; stdcall;
       Ke386IoSetAccessProcess允許或者禁止對進程使用IOPM。其參數說明如下:
     ◎ pProcess--指向KPROCESS結構
     ◎ dwFlag--0表示禁止對I/O端口進行存取,將IOPM的偏移指針指到TSS段外面;1表示允許存

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved