天天看點

過濾驅動筆記

功能說明:DriverA是實作讀的普通驅動,DriverA采用緩沖方式讀寫,DriverB是挂載在DriverA之上的上層驅動。之後調用應用程式,此應用程式是對于DriverA裝置的,DriverB會将發送到DriverA的IRP過濾掉,但DriverB隻是簡單的過濾讀寫請求,然後原樣發送到下層驅動DriverA。

DriverA的讀寫派遣函數: NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,

IN PIRP pIrp)

{

KdPrint(("Enter HelloDDKRead/n"));

PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;

NTSTATUS status = STATUS_SUCCESS;

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);

ULONG ulReadLength = stack->Parameters.Read.Length;

ULONG ulReadOffset = (ULONG)stack->Parameters.Read.ByteOffset.QuadPart;

if (ulReadOffset+ulReadLength>MAX_FILE_LENGTH)

{

status = STATUS_FILE_INVALID;

ulReadLength = 0;

}else

{

//将資料存儲在AssociatedIrp.SystemBuffer,以便應用程式使用

memcpy(pIrp->AssociatedIrp.SystemBuffer,pDevExt->buffer+ulReadOffset,ulReadLength);

status = STATUS_SUCCESS;

}

pIrp->IoStatus.Status = status;

pIrp->IoStatus.Information = ulReadLength; // bytes xfered

IoCompleteRequest( pIrp, IO_NO_INCREMENT );

KdPrint(("Leave HelloDDKRead/n"));

return status;

}

NTSTATUS HelloDDWrite(IN PDEVICE_OBJECT pDevObj,

IN PIRP pIrp)

{

KdPrint(("Enter HelloDDWrite/n"));

NTSTATUS status = STATUS_SUCCESS;

PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;

PIO_STACK_LOCATION stack = IoGetCurrentIrpStackLocation(pIrp);

//擷取存儲的長度

ULONG ulWriteLength = stack->Parameters.Write.Length;

//擷取存儲的偏移量

ULONG ulWriteOffset = (ULONG)stack->Parameters.Write.ByteOffset.QuadPart;

if (ulWriteOffset+ulWriteLength>MAX_FILE_LENGTH)

{

//如果存儲長度+偏移量大于緩沖區長度,則傳回無效

KdPrint(("如果存儲長度+偏移量大于緩沖區長度,則傳回無效"));

status = STATUS_FILE_INVALID;

ulWriteLength = 0;

}else

{

KdPrint(("%ws/n", pIrp->AssociatedIrp.SystemBuffer));

//将寫入的資料,存儲在緩沖區内

memcpy(pDevExt->buffer+ulWriteOffset,pIrp->AssociatedIrp.SystemBuffer,ulWriteLength);

status = STATUS_SUCCESS;

//設定新的檔案長度

if (ulWriteLength+ulWriteOffset>pDevExt->file_length)

{

pDevExt->file_length = ulWriteLength+ulWriteOffset;

}

}

pIrp->IoStatus.Status = status;

pIrp->IoStatus.Information = ulWriteLength; // bytes xfered

IoCompleteRequest( pIrp, IO_NO_INCREMENT );

KdPrint(("Leave HelloDDWrite/n"));

return status;

}

DriverB的主要派遣函數:/**********************************************

*寫的操作中的資料是從應用程式發出的,在請求完成之前就已經存在于輸入緩沖區裡了

*是以可以直接在上層驅動DriverB中直接捕捉到資料。

***********************************************/

#pragma PAGEDCODE

NTSTATUS HelloDDKWrite(IN PDEVICE_OBJECT pDevObj,

IN PIRP pIrp)

{

KdPrint(("DriverB:Enter B HelloDDKWrite/n"));

NTSTATUS ntStatus = STATUS_SUCCESS;

PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;

PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(pIrp);

//緩沖區長度

ULONG len = irpsp->Parameters.Write.Length;

PUCHAR buf = NULL;

//緩沖區位址

buf = (PUCHAR)pIrp->AssociatedIrp.SystemBuffer;

for(ULONG i=0; i<len; i++)

{

KdPrint(("DriverB:%2x/n", buf[i]));

}

//略過目前堆棧

IoSkipCurrentIrpStackLocation (pIrp);

//調用底層驅動

ntStatus = IoCallDriver(pdx->TargetDevice, pIrp);

KdPrint(("DriverB:Leave B HelloDDKWrite/n"));

return ntStatus;

}

pragma PAGEDCODE

NTSTATUS MyIoCompletion(PDEVICE_OBJECT DeviceObject, PIRP pIrp, PVOID Context)

{

KdPrint(("DriverB:Enter B MyIoCompletion/n"));

PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(pIrp);

//緩沖區長度

ULONG len = irpsp->Parameters.Read.Length;

PUCHAR buf = NULL;

//緩沖區位址

buf = (PUCHAR)pIrp->AssociatedIrp.SystemBuffer;

for(ULONG i=0; i<len; i++)

{

KdPrint(("DriverB:%2x/n", buf[i]));

}

KdPrint(("DriverB:Leave B MyIoCompletion/n"));

return STATUS_SUCCESS;

}

/*************************************

*讀請求資料則是必須從硬碟上獲得的,

*必須請求完成之後才存在于輸入緩沖區裡

**************************************/

#pragma PAGEDCODE

NTSTATUS HelloDDKRead(IN PDEVICE_OBJECT pDevObj,

IN PIRP pIrp)

{

KdPrint(("DriverB:Enter B HelloDDKRead/n"));

NTSTATUS ntStatus = STATUS_SUCCESS;

//将自己完成IRP,改成由底層驅動負責

PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)pDevObj->DeviceExtension;

//将目前I/O堆棧拷貝底層堆棧

IoCopyCurrentIrpStackLocationToNext (pIrp);

//設定完成例程

IoSetCompletionRoutine(pIrp, MyIoCompletion,NULL,TRUE,TRUE,TRUE);

ntStatus = IoCallDriver(pdx->TargetDevice, pIrp);

KdPrint(("DriverB:Leave B HelloDDKRead/n"));

return ntStatus;

}

應用程式的代碼:int main()

{

HANDLE hDevice =

CreateFile(".//HelloDDKA",

GENERIC_READ | GENERIC_WRITE,

0, // share mode none

NULL, // no security

OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL,

NULL ); // no template

if (hDevice == INVALID_HANDLE_VALUE)

{

printf("Failed to obtain file handle to device: "

"%s with Win32 error code: %d/n",

"MyWDMDevice", GetLastError() );

return 1;

}

UCHAR buffer[10];

memset(buffer,0xBB,10);

ULONG ulRead;

ULONG ulWrite;

BOOL bRet;

bRet = WriteFile(hDevice,buffer,10,&ulWrite,NULL);

if (bRet)

{

printf("Write %d bytes/n",ulWrite);

}

bRet = ReadFile(hDevice,buffer,5,&ulRead,NULL);

if (bRet)

{

printf("Read %d bytes:",ulRead);

for (int i=0;i<(int)ulRead;i++)

{

printf("%02X ",buffer[i]);

}

printf("/n");

}

CloseHandle(hDevice);

return 0;

}

總結:

  1. 在DriverB的DriverEntry函數中綁定下層裝置,此處為DriverA,用IoGetDeviceObjectPointer函數通過DriverA的裝置名尋找其裝置對象。再用IoAttachDeviceToDeviceStack綁定,并設定好各标志位。
  2. 寫的過濾:首先獲得IO堆棧irpsp,在irpsp->Parameters.Write.Length中獲得寫的長度,在pIrp->AssociatedIrp.SystemBuffer中獲得緩沖區。再調用IoSkipCurrentIrpStackLocation略過目前堆棧,IoCallDriver調用底層驅動。
  3. 讀的過濾:與寫的過濾不同的是不用IoSkipCurrentIrpStackLocation,而用IoCopyCurrentIrpStackLocationToNext向下複制堆棧,再用IoSetCompletionRoutine設定完成例程。完成例程中再調用IO堆棧獲得緩沖區,并進行操作。當下層驅動DriverA完成讀的IRP後會馬上進入完成例程,執行完完成例程才會再退出DriverA的讀例程。