分层驱动程序

分层驱动程序的概念
分层驱动概念主要是为了区分前面介绍的单层驱动程序。分层驱动是指两个或两个以
上的驱动程序,它们分别创建设备对象,并且形成一个由高到低的设备对象栈。

IRP请求
一-般会被传送到设备栈的最顶层的设备对象,顶层的设备对象可以选择直接结束IRP请求,也可以选择将IRP请求向下层的设备对象转发。如果是向下层设备对象转发IRP请求,当
IRP请求结束时,IRP会顺着设备栈的反方向原路返回。当得知下层驱动程序已经结束IRP
请求时,本层设备对象可以选择继续将IRP向上返回,或者选择重新将IRP再次传递给底
层设备驱动。
由此看来,分层驱动处理IRP要比单层驱动灵活得多。事实上,单层驱动也很少被用
到,程序员大部分需要编写的是分层驱动程序。

分层驱动程序使设计变得模块化。一个功能复杂的驱动程序可以划分为若干个小
驱动程序,每个小驱动程序对上层驱动程序提供一个接口,上层驱动程序只关心下层驱动
程序的接口,而不必关心底层驱动程序是如何实现的。

在Windows 2000后,微软提出了WDM ( Windows Driver Model)驱动程序模型
的概念。WDM驱动程序就属于分层驱动程序。最简单的WDM驱动程序分为两层,一层
是PDO (物理设备对象Physical Device Object),另一 层是FDO (功能设备对象Function
Device Object)。 FDO是挂载在PDO之上的,PDO实现了即插即用的功能,FDO完成逻
辑功能,而将一些硬件 相关的请求发往PDO。

设备堆栈与挂载

挂载指的是将高一层的设备对象挂载在低一层的设备对象上,从而形成一个设备栈。

IRP处理的顺序是位于设备栈中高层的设备先处理IRP,然后决定是否传给低一层的设备.

实现挂载的内核函数是loAttachDeviceToDeviceStack,其声明如下:

PDEVICE_OBJECT
IoAttachDeviCeToDeviceStack (
IN PDEVICE_OBJECT SourceDevice,		//设备栈中的一个设备指针
IN PDEVICE_OEITECT TargetDevice	//将TargetDevice	挂载在设备栈的栈顶
);

当驱动程序卸载的时候,驱动程序所创建的设备对象应该从设备栈中弹出。出栈的顺
序必须和入栈的顺序相反。从设备栈弹出的内核函数是IoDetachDevice,其函数声明如下:

VOID
IoDetachDevice (
IN OUT PDEVICE_OBJECT TargetDevice	//如果删除的设备栈栈顶的设备C  那么函数运行完TargetDevice的值就是设备B
);

在这里插入图片描述

I/O堆栈

在Windows驱动模型中,还有一个概念叫做“I/O堆栈”,用IO_STACK_LOCATION
数据结构表示。它和设备堆栈紧密联合。IRP一般会由应用程序的ReadFile或WriteFile创
建,然后发送到设备堆栈的顶层。如果最上层的设备不处理IRP,就会将IRP转发到下一
层设备。每一-层设备堆栈都有可能处理IRP。

在IRP的数据结构中,存储着一个IO STACK LOCATION数组的指针。调用lAllocateIrp
内核函数创建IRP时,有一个StackSize 参数,该参数就是I0_STACK_LOCATION数组的
大小。

作用:IRP每穿越一次设备堆栈, 就会用I0_STACK_LOCATION记录下本次操作的某些属

I/O堆栈和设备堆栈的关系如图12-2所示。

在这里插入图片描述

向下转发IRP

当顶层驱动的设备对象收到IRP请求并进入派遣函数后,有多种选择方式处理IRP。
(1)直接处理该IRP,即调用IoCompleteRequest内核函数。
(2)调用StartIO,操作系统会将IRP请求串行化。除了当前运行的IRP,其他的IRP请求进入IRP队列。
(3)选择让底层驱动完成IRP。

向下转发IRP涉及设备堆栈和I/O 堆栈。一一个设备堆栈对应着一个I/O 堆栈元素( IO_STACK_LOCATION)。 IRP内部有个指针指向当前正在使用的IO_STACK_LOCATION,可以使用内核宏loGetCurrentIrpStackLocation获得当前IO堆栈。
每次调用loCallDriver时,内核函数都会将IRP的当前指针下移,指向下一个IO_STACK_ LOCATION指针。

但有时候,当前设备堆栈不对IRP做任何处理。因此,当前设备就不需要对应I/O堆
栈。但是loCallDriver已经将当前I/O堆栈向下移动了一个单位,所以DDK提供了内核宏
IoSkipCurrentIrpStackLocation,它的作用就是将当前I/O堆栈又往回(上)移动一个单位。

这样loCallDriver和loSkipCurrentIrpStackI ocation对设备堆栈的移动就实现了平衡,
也就是没有改变。这时loCallDriver调用的低一层驱动所用到的IO堆栈,实际上和一层用到的是同一个。因此,当本层驱动不需要用I/O堆栈时,

挂载设备对象实例

下面的示例是将DriverB加载在DriverA上,并且在DriverB的派遣函数中不对当前
设备栈处理,直接将IRP转发到下层设备上,即DriverA上。
DriverA是实现读的普通驱动,DriverB 首先在DriverEntry上,用loGetDeviceObject
Pointer找到DriverA所创建的设备对象,并将自己的设备对象挂载在设备栈上,并用设备
扩展将底层驱动的设备对象记录下来。

NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{

	NTSTATUS status = 0;
	ULONG uIndex = 0;
	PDEVICE_OBJECT pDeviceObj = NULL;
	UNICODE_STRING DeviceName;
	UNICODE_STRING SymbolicLinkName;

	//Irp默认处理
	pDriver->MajorFunction[IRP_MJ_CREATE] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_CLOSE] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_WRITE] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_READ] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_CLEANUP] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_SET_INFORMATION] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_SHUTDOWN] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IrpDefaultProc;

	//设置派遣函数和卸载函数	
	pDriver->DriverUnload = DriverUnload;

	pDriver->MajorFunction[IRP_MJ_READ] = IrpReadProc;
	

	//创建设备名称
	RtlInitUnicodeString(&DeviceName, DEVICE_NAME);

	//创建设备  让三环的API能够找到,才能实现通信
	status = IoCreateDevice(pDriver,
		sizeof(DEVICE_EXTENSION),	//扩展设备大小 
		&DeviceName,
		FILE_DEVICE_UNKNOWN,
		0,
		TRUE,
		&pDeviceObj);
	if (status != STATUS_SUCCESS)
	{
		DbgPrint("创建设备失败! status=%x\r\n", status);
		return status;
	}

	//设置交互数据方式
	pDeviceObj->Flags |= DO_BUFFERED_IO;

	//创建符号链接名称,就是给该设备在三环起个能用的别名
	RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINE_NAME);

	//创建符号链接
	status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("创建符号链接失败!\r\n");
		IoDeleteDevice(pDeviceObj);
		return status;
	}
	PDEVICE_EXTENSION pDevExt = pDeviceObj->DeviceExtension;
	pDevExt->pDevice = pDeviceObj;
	pDevExt->ustrDeviceName = DeviceName;
	pDevExt->ustrSymLinkName = SymbolicLinkName;

	/*测试代码*/

	UNICODE_STRING DevName;
	RtlInitUnicodeString(&DevName, CALLED_DEVICE_NAME);

	PDEVICE_OBJECT DeviceObject = NULL;
	PFILE_OBJECT FileObject = NULL;

	//第一步 得到设备对象指针,计数器加1
	//如果是第一次调用IoGetDeviceObjectPointer,会打开设备,相当于调用ZwCreateFile
	status = IoGetDeviceObjectPointer(&DevName, FILE_ALL_ACCESS, &FileObject, &DeviceObject);
	DbgPrint("打开的设备对象指针是:%p\n", DeviceObject);

	//附加设备到目标的设备栈
	PDEVICE_OBJECT pTargetDevice = IoAttachDeviceToDeviceStack(pDeviceObj, DeviceObject);
	DbgPrint("附加的设备对象指针是:%p\n", pTargetDevice);

	//保存附加的目标设备指针
	pDevExt->AttachedDeciveObjectPointer = pTargetDevice;
	/*测试代码*/

	//ObDereferenceObject函数对象引用计数-1, 该函数先是对传过去的内核对象-0x18 得到_OBJECT_HEADER结构地址,然后PointCount-1  再比较该值是否为0,如果为0 就删除该内核对象.
	ObDereferenceObject(FileObject);
	//解除附加可以在卸载函数中进行.
	IoDetachDevice(pTargetDevice);
	return status;

}

转发IRP实例

#pragma PAGEDCODE
NTSTATUS IrpReadProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
	NTSTATUS status = STATUS_SUCCESS;

	//得到设备扩展
	PDEVICE_EXTENSION pDeviceExtension = pDeviceObject->DeviceExtension;

	//略过当前I/O堆栈
	IoSkipCurrentIrpStackLocation(pIrp);

	//调用底层驱动
	status = IoCallDriver(pDeviceExtension->AttachedDeciveObjectPointer,pIrp);
	DbgPrint("设备栈顶层设备不处理此IRP  转发给下一层处理\n");
	return status;
}

driver.h头文件

#pragma once

#include <ntddk.h>
#define PAGEDCODE code_seg("PAGE")
#define LOCKEDCODE code_seg()
#define INITCODE code_seg("INIT")

#define PAGEDDATA data_seg("PAGE")
#define LOCKEDDATA data_seg()
#define INITDATA data_seg("INIT")

#define arraysize(p) (sizeof(p)/sizeof((p)[0]))


typedef struct _DEVICE_EXTENSION {
	PDEVICE_OBJECT pDevice;
	UNICODE_STRING ustrDeviceName;	//设备名称
	UNICODE_STRING ustrSymLinkName;	//符号链接名


	PDEVICE_OBJECT	AttachedDeciveObjectPointer;

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;

完整代码: 被附加驱动A

#include<ntddk.h>
#include<ntstatus.h>

#define DEVICE_NAME L"\\Device\\MyDevice"
#define SYMBOLICLINE_NAME L"\\??\\MyTestDriver"  //ring3用CreateFile打开设备时,用"\\\\.\\MyTestDriver"//相当于起的别名

#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)


//实现卸载函数和派遣函数
VOID DriverUnload(PDRIVER_OBJECT pDriver)
{
	UNICODE_STRING SymbolicLinkName={0};
	RtlInitUnicodeString(&SymbolicLinkName,SYMBOLICLINE_NAME);
	IoDeleteDevice(pDriver->DeviceObject);
	IoDeleteSymbolicLink(&SymbolicLinkName);

}

NTSTATUS IrpCreateProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{

	pIrp->IoStatus.Status = STATUS_SUCCESS;//getlasterror()得到的就是这个值
	pIrp->IoStatus.Information = 0;//返回给3环多少数据,没有填0
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

NTSTATUS IrpCloseProc(PDEVICE_OBJECT pdriver, PIRP pIrp)
{

	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}

NTSTATUS IrpReadProc(PDEVICE_OBJECT pdriver, PIRP pIrp)
{
	DbgPrint("驱动A 处理IRP\n");
	pIrp->IoStatus.Status = STATUS_SUCCESS;
	pIrp->IoStatus.Information = 0;
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}


NTSTATUS DriverEntry(PDRIVER_OBJECT pdriver, PUNICODE_STRING reg_path)
{

	NTSTATUS status = 0;
	ULONG uIndex = 0;
	PDEVICE_OBJECT pDeviceObj = NULL;
	UNICODE_STRING DeviceName;
	UNICODE_STRING SymbolicLinkName;
	//创建设备名称
	RtlInitUnicodeString(&DeviceName, DEVICE_NAME);

	//创建设备  让三环的API能够找到,才能实现通信
	status = IoCreateDevice(pdriver, 0, &DeviceName, FILE_DEVICE_UNKNOWN, FILE_DEVICE_SECURE_OPEN, FALSE, &pDeviceObj);
	if (status != STATUS_SUCCESS)
	{
		DbgPrint("创建设备失败! status=%x\r\n",status);
		return status;
	}

	//设置交互数据方式
	pDeviceObj->Flags |= DO_BUFFERED_IO;

	//创建符号链接名称,就是给该设备在三环起个能用的别名
	RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINE_NAME);

	//创建符号链接
	status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("创建符号链接失败!\r\n");
		IoDeleteDevice(pDeviceObj);
		return status;
	}

	//设置派遣函数和卸载函数
	pdriver->MajorFunction[IRP_MJ_CREATE] = IrpCreateProc;
	pdriver->MajorFunction[IRP_MJ_CLOSE] = IrpCloseProc;
	pdriver->MajorFunction[IRP_MJ_READ] = IrpReadProc;

	pdriver->DriverUnload = DriverUnload;
	return STATUS_SUCCESS;

}

附加的驱动B

#include<ntddk.h>
#include<ntstatus.h>
#include "Driver.h"
#define DEVICE_NAME L"\\Device\\dale"
#define CALLED_DEVICE_NAME L"\\Device\\MyDevice"
#define SYMBOLICLINE_NAME L"\\??\\dale_symbol"  //ring3用CreateFile打开设备时,用"\\\\.\\MyTestDriver"//相当于起的别名
#define OPER1 CTL_CODE(FILE_DEVICE_UNKNOWN,0x800,METHOD_BUFFERED,FILE_ANY_ACCESS)
#define OPER2 CTL_CODE(FILE_DEVICE_UNKNOWN,0x900,METHOD_BUFFERED,FILE_ANY_ACCESS)


//实现卸载函数
VOID DriverUnload(PDRIVER_OBJECT pDriverObject)
{
	PDEVICE_OBJECT	pNextObj;
	KdPrint(("Enter DriverUnload\n"));
	pNextObj = pDriverObject->DeviceObject;
	while (pNextObj != NULL)
	{
		PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)
			pNextObj->DeviceExtension;

		//删除符号链接
		UNICODE_STRING pLinkName = pDevExt->ustrSymLinkName;
		IoDeleteSymbolicLink(&pLinkName);
		IoDetachDevice(pDevExt->AttachedDeciveObjectPointer);
		pNextObj = pNextObj->NextDevice;
		IoDeleteDevice(pDevExt->pDevice);
		DbgPrint("删除设备\n");
	}

}

NTSTATUS IrpDefaultProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{

	pIrp->IoStatus.Status = STATUS_SUCCESS;//getlasterror()得到的就是这个值
	pIrp->IoStatus.Information = 0;//返回给3环多少数据,没有填0
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	return STATUS_SUCCESS;
}


#pragma PAGEDCODE
NTSTATUS IrpReadProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
	DbgPrint("设备栈顶层设备不处理此IRP  转发给下一层处理\n");
	NTSTATUS status = STATUS_SUCCESS;

	//得到设备扩展
	PDEVICE_EXTENSION pDeviceExtension = pDeviceObject->DeviceExtension;

	//略过当前I/O堆栈
	IoSkipCurrentIrpStackLocation(pIrp);

	//调用底层驱动
	status = IoCallDriver(pDeviceExtension->AttachedDeciveObjectPointer, pIrp);
	
	return status;
}



NTSTATUS DriverEntry(PDRIVER_OBJECT pDriver, PUNICODE_STRING reg_path)
{

	NTSTATUS status = 0;
	ULONG uIndex = 0;
	PDEVICE_OBJECT pDeviceObj = NULL;
	UNICODE_STRING DeviceName;
	UNICODE_STRING SymbolicLinkName;

	//Irp默认处理
	pDriver->MajorFunction[IRP_MJ_CREATE] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_CLOSE] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_WRITE] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_READ] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_CLEANUP] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_DEVICE_CONTROL] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_SET_INFORMATION] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_SHUTDOWN] = IrpDefaultProc;
	pDriver->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = IrpDefaultProc;

	//设置派遣函数和卸载函数	
	pDriver->DriverUnload = DriverUnload;

	pDriver->MajorFunction[IRP_MJ_READ] = IrpReadProc;


	//创建设备名称
	RtlInitUnicodeString(&DeviceName, DEVICE_NAME);

	//创建设备  让三环的API能够找到,才能实现通信
	status = IoCreateDevice(pDriver,
		sizeof(DEVICE_EXTENSION),	//扩展设备大小 
		&DeviceName,
		FILE_DEVICE_UNKNOWN,
		0,
		TRUE,
		&pDeviceObj);
	if (status != STATUS_SUCCESS)
	{
		DbgPrint("创建设备失败! status=%x\r\n", status);
		return status;
	}

	//设置交互数据方式
	pDeviceObj->Flags |= DO_BUFFERED_IO;

	//创建符号链接名称,就是给该设备在三环起个能用的别名
	RtlInitUnicodeString(&SymbolicLinkName, SYMBOLICLINE_NAME);

	//创建符号链接
	status = IoCreateSymbolicLink(&SymbolicLinkName, &DeviceName);
	if (!NT_SUCCESS(status))
	{
		DbgPrint("创建符号链接失败!\r\n");
		IoDeleteDevice(pDeviceObj);
		return status;
	}
	PDEVICE_EXTENSION pDevExt = pDeviceObj->DeviceExtension;
	pDevExt->pDevice = pDeviceObj;
	pDevExt->ustrDeviceName = DeviceName;
	pDevExt->ustrSymLinkName = SymbolicLinkName;

	/*测试代码*/

	//获得设备指针
	UNICODE_STRING TargetDeviceName;
	RtlInitUnicodeString(&TargetDeviceName, CALLED_DEVICE_NAME);
	PFILE_OBJECT fileObject;
	PDEVICE_OBJECT pTargetDevice;
	status = IoGetDeviceObjectPointer(&TargetDeviceName, FILE_ALL_ACCESS, &fileObject, &pTargetDevice);

	if (!NT_SUCCESS(status))
	{
		IoDeleteSymbolicLink(&SymbolicLinkName);
		IoDeleteDevice(pDeviceObj);
		//文件对象引用计数-1
		ObDereferenceObject(fileObject);

		return status;
	}

	
	status = IoGetDeviceObjectPointer(&TargetDeviceName, FILE_ALL_ACCESS, &fileObject, &pTargetDevice);
	PDEVICE_OBJECT attactedDevice = IoAttachDeviceToDeviceStack(pDeviceObj, pTargetDevice);

	if (!attactedDevice)
	{
		IoDeleteSymbolicLink(&SymbolicLinkName);
		IoDeleteDevice(pDeviceObj);
		//文件对象引用计数-1
		ObDereferenceObject(fileObject);
		return STATUS_DEVICE_ALREADY_ATTACHED;
	}

	pDevExt->AttachedDeciveObjectPointer = attactedDevice;
	DbgPrint("attactedDevice=%p!\r\n", attactedDevice);
	DbgPrint("pTargetDevice=%p!\r\n", pTargetDevice);
	//文件对象引用计数-1
	pDevExt->pDevice->DeviceType = attactedDevice->DeviceType;
	pDevExt->pDevice->Characteristics = attactedDevice->Characteristics;
	pDevExt->pDevice->Flags &= ~DO_DEVICE_INITIALIZING;
	pDevExt->pDevice->Flags |= (attactedDevice->Flags & (DO_DIRECT_IO | DO_BUFFERED_IO));

	ObDereferenceObject(fileObject);

	/*测试代码*/

	return STATUS_SUCCESS;

}

3环测试代码

#include "stdafx.h"
#include <windows.h>
#include <stdio.h>

int main()
{

	HANDLE hDevice = 
		CreateFile(L"\\\\.\\MyTestDriver",
		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 "
			"with Win32 error code: %d\n",
			GetLastError() );
		return 1;
	}

	DWORD dRet;
	ReadFile(hDevice,NULL,0,&dRet,NULL);

	CloseHandle(hDevice);

	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值