作 者: mickeylan
時 間: 2008-01-14,20:58
鏈 接: http://bbs.pediy.com/showthread.php?t=58301
Delphi研究之驅動開發篇(三)
(注:本篇的原理部分均摘自羅雲彬大俠翻譯的驅動開發教程)
在前面的兩篇教程中我們寫了三個玩具驅動程序,為什麼說是玩具驅動呢?因為它們確確實實是驅動程序,而且也能完成一些有趣的功能,但是它們都不完整,沒有同用戶交流的功能,這一篇就讓我們來完成一個簡單的全功能驅動程序。
在寫程序之前,我們有必要了解一些基礎知識。
在用戶模式下,我們可以通過訪問某個地址來直接調用dll中的函數,但是在內核模式下,從系統的穩定性考慮,這樣做是非常危險的。所以,系統提供了和內核模式通訊的媒介--I/O管理器,它是I/O子系統的部件之一。I/O管理器將應用程序、系統部件和設備連接起來,並定義了一個架構來支持設備驅動程序。
一般來說,用戶模式的操作都被轉換成了對具體硬件設備的I/O操作,僅對於某些設備,設備由驅動程序來創建和控制,這些設備就是虛擬設備。當然,創建這些設備並不意味著你創造了什麼硬件,而僅僅是在內存中創建了一個新的對象而已。每個對象和一個物理設備或者邏輯設備對應,用於描述它們的特征。
創建設備後,驅動程序告訴I/O管理器:“這裡有個我控制的設備,如果你收到了操作這個設備的I/O請求的話,直接發給我好了,剩下的由我來搞定!”。驅動程序知道如何對自己管理的設備進行I/O操作,I/O管理器唯一的職責在於創建I/O請求並把它發送給適當的設備驅動程序。用戶模式的代碼不知道(也不必知道)其中的細節,也不用知道究竟是哪個驅動程序在管理哪個設備。
下面先讓我們來看一下用戶模式下的控制程序:
代碼:program VirToPhys;
{$APPTYPE CONSOLE}
uses
SysUtils, Windows, WinSvc, Dialogs, nt_status;
const
NUM_DATA_ENTRY =4;
DATA_SIZE = sizeof(DWORD) * NUM_DATA_ENTRY;
_Delete = $10000;
var
hSCManager:THANDLE;
hService:THANDLE;
acModulePath: array [0..MAX_PATH] of char;
_ss:SERVICE_STATUS;
hDevice:THANDLE;
adwInBuffer: array [0..NUM_DATA_ENTRY] of DWORD;
adwOutBuffer: array [0..NUM_DATA_ENTRY] of DWORD;
dwBytesReturned:DWORD;
IOCTL_GET_PHYS_ADDRESS: DWORD;
lpTemp: PChar;
iRetValue: boolean;
{生成控制碼}
function CTL_CODE(DeviceType, Func, Method, Access: DWORD): DWORD;
begin
result := (((DeviceType) SHL 16) or ((Access) SHL 14) or ((Func) SHL 2) or (Method));
end;
begin
IOCTL_GET_PHYS_ADDRESS := CTL_CODE(FILE_DEVICE_UNKNOWN,
$800, METHOD_BUFFERED,
FILE_READ_ACCESS + FILE_WRITE_ACCESS);
hSCManager := OpenSCManager(nil, nil, SC_MANAGER_ALL_ACCESS);
if hSCManager <> 0 then
begin
GetFullPathName(PChar(VirtToPhys.sys), sizeof(acModulePath), acModulePath, lpTemp);
hService := CreateService(hSCManager, VirtToPhys, Virtual To Physical Address Converter,
SERVICE_START + SERVICE_STOP + _Delete, SERVICE_KERNEL_DRIVER,
SERVICE_DEMAND_START, SERVICE_ERROR_IGNORE, acModulePath,
nil, nil, nil, nil, nil);
if hService <> 0 then
begin
{驅動程序的DriverEntry過程將被調用}
if StartService(hService, 0, lpTemp) = true then
begin
{驅動程序將接收IRP_MJ_Create I/O請求包(IRP)}
hDevice := CreateFile(\.slVirtToPhys, GENERIC_READ+GENERIC_WRITE,
0, nil, OPEN_EXISTING, 0, 0);
if hDevice <> INVALID_HANDLE_VALUE then
begin
{准備送往驅動程序的數據包}
adwInBuffer[0] := GetModuleHandle(nil);
adwInBuffer[1] := GetModuleHandle(kernel32.dll);
adwInBuffer[2] := GetModuleHandle(user32.dll);