驱动程序调用驱动程序

同步调用

被调用驱动程序代码:

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

	//自己的扩展
	PIRP currentPendingIRP;
	KDPC dpc;
	KTIMER timer;

} DEVICE_EXTENSION, *PDEVICE_EXTENSION;



#include<ntddk.h>
#include<ntstatus.h>
#include "Driver.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)

PVOID pDeviceExtension = 0;

//实现卸载函数
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);

		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/*参数信息*/)
{
	//将IRP设置为挂起
	IoMarkIrpPending(pIrp);

	//设置一个DPC 如果超时就在DPC的回调处理中把IRP取消掉。
	PDEVICE_EXTENSION pDevExt = pDeviceObject->DeviceExtension;

	//保存IRP指针 
	pDevExt->currentPendingIRP = pIrp;

	//定义3s的超时
	ULONG ulMicroSecond = 3000000;

	//将32位整数转换成64位整数
	LARGE_INTEGER timeOut = RtlConvertLongToLargeInteger(-10 * ulMicroSecond);

	//开启计时器
	KeSetTimer(&pDevExt->timer, timeOut, &pDevExt->dpc);

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

#pragma LOCKEDCODE
void DpcRoutine(
	PKDPC  pDpc,
	PVOID Context,
	PVOID Arg1,
	PVOID Arg2
	)
{
	//获得设备扩展的指针
	PDEVICE_EXTENSION pDevExt = (PDEVICE_EXTENSION)Context;

	//获得挂起的IRP
	PIRP pIrp = pDevExt->currentPendingIRP;

	//设置完成状态为STATUS_CANCELLED
	pIrp->IoStatus.Status = STATUS_CANCELLED;

	//设置操作的字节数
	pIrp->IoStatus.Information = 0;
	DbgPrint("Delay IRP run\n");
	//完成请求
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);

}

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;

	/*测试代码*/

	//初始化定时器对象
	KeInitializeTimer(&pDevExt->timer);

	//初始化DPC对象
	KeInitializeDpc(&pDevExt->dpc, DpcRoutine, pDevExt);

	/*测试代码*/

	return STATUS_SUCCESS;

}



}

调用者代码:



#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)

PVOID pDeviceExtension = 0;

//实现卸载函数
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);

		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/*参数信息*/)
{
	KdPrint(("DriverB:Enter B HelloDDKRead\n"));
	NTSTATUS ntStatus = STATUS_SUCCESS;

	UNICODE_STRING DeviceName;
	RtlInitUnicodeString(&DeviceName, CALLED_DEVICE_NAME);

	//初始化objectAttributes
	OBJECT_ATTRIBUTES objectAttributes;
	InitializeObjectAttributes(&objectAttributes,
		&DeviceName,
		OBJ_CASE_INSENSITIVE,
		NULL,
		NULL);

	HANDLE hDevice;
	IO_STATUS_BLOCK status_block;
	//同步打开设备
	//设定了FILE_SYNCHRONOUS_IO_NONALERT或者FILE_SYNCHRONOUS_IO_ALERT为同步打开设备
	ntStatus = ZwCreateFile(&hDevice,
		FILE_READ_ATTRIBUTES | SYNCHRONIZE,
		&objectAttributes,
		&status_block,
		NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,
		FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);

	if (NT_SUCCESS(ntStatus))
	{
		ZwReadFile(hDevice, NULL, NULL, NULL, &status_block, NULL, 0, NULL, NULL);
	}

	ZwClose(hDevice);

	// 完成IRP
	pIrp->IoStatus.Status = ntStatus;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	KdPrint(("DriverB:Leave B HelloDDKRead\n"));
	return ntStatus;
}



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;

	/*测试代码*/



	/*测试代码*/

	return STATUS_SUCCESS;

}



3环测试代码

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

int main()
{
	HANDLE hDevice = 
		CreateFile(L"\\\\.\\dale_symbol",
		GENERIC_READ | GENERIC_WRITE,
		0,
		NULL,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL,//使用同步方式
		NULL );

	if (hDevice == INVALID_HANDLE_VALUE)
	{
		printf("Open Device failed!");
		getchar();
		return 1;
	}

	char buffer[20]={0};
	OVERLAPPED OverLapped={0};
	ReadFile(hDevice,buffer,10,0,&OverLapped);

	//创建IRP_MJ_CLEANUP IRP
	CloseHandle(hDevice);
	return 0;
}

运行流程: 3环ReadFile -》调用驱动B 的Read IRP处理 -》Read IRP调用CreateFile 同步打开被调用驱动A 调用 ReadFile 发送IRP -》被调用驱动A Read IRP 挂起IRP 设置DPC -》DPC IRP超时处理

异步调用

被调用驱动代码不变



#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)

PVOID pDeviceExtension = 0;

//实现卸载函数
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);

		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;
}


VOID CompleteDriverA_Read(PVOID context, PIO_STATUS_BLOCK pStatus_block, ULONG Reserved)
{
	KdPrint(("DriverB:The Driver A Read completed now!\n"));
	KeSetEvent((PKEVENT)context, IO_NO_INCREMENT, FALSE);
}


#pragma PAGEDCODE
NTSTATUS IrpReadProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
	KdPrint(("DriverB:Enter B HelloDDKRead\n"));
	NTSTATUS ntStatus = STATUS_SUCCESS;
	UNICODE_STRING DeviceName;
	RtlInitUnicodeString(&DeviceName, CALLED_DEVICE_NAME);

	//初始化objectAttributes
	OBJECT_ATTRIBUTES objectAttributes;
	InitializeObjectAttributes(&objectAttributes,
		&DeviceName,
		OBJ_CASE_INSENSITIVE,
		NULL,
		NULL);

	HANDLE hDevice;
	IO_STATUS_BLOCK status_block;
	//异步打开设备
	//没有设定了FILE_SYNCHRONOUS_IO_NONALERT和FILE_SYNCHRONOUS_IO_ALERT为异步打开设备
	ntStatus = ZwCreateFile(&hDevice,
		FILE_READ_ATTRIBUTES,//没有设SYNCHRONIZE
		&objectAttributes,
		&status_block,
		NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,
		FILE_OPEN_IF, 0, NULL, 0);

	KEVENT event;
	//初始化事件,用于异步读
	KeInitializeEvent(&event, SynchronizationEvent, FALSE);

	LARGE_INTEGER offset = RtlConvertLongToLargeInteger(0);
	if (NT_SUCCESS(ntStatus))
	{
		ntStatus = ZwReadFile(hDevice, NULL, CompleteDriverA_Read, &event, &status_block, NULL, 0, &offset, NULL);
	}

	if (ntStatus == STATUS_PENDING)
	{
		KdPrint(("DriverB:ZwReadFile return STATUS_PENDING!\n"));
		KdPrint(("DriverB:Waiting..."));
		KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
	}
	ZwClose(hDevice);

	ntStatus = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = ntStatus;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	KdPrint(("DriverB:Leave B HelloDDKRead\n"));
	return ntStatus;
}



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;

	/*测试代码*/



	/*测试代码*/

	return STATUS_SUCCESS;

}

3环代码

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

int main()
{
	//打开指定设备  加上FILE_FLAG_OVERLAPPED标志 表示设备操作为异步的
	HANDLE hDevice=CreateFileW(	   L"\\\\.\\dale_symbol",
		GENERIC_READ | GENERIC_WRITE,
		0,
		0,
		OPEN_EXISTING,
		FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED ,//FILE_FLAG_OVERLAPPED表示使用异步打开
		0
		);

	if (hDevice==INVALID_HANDLE_VALUE)
	{
		printf("设备打开失败\n");
		getchar();
		return false;
	}

	OVERLAPPED Overlap={0};
	Overlap.hEvent=CreateEvent(0,0,0,0);
	UCHAR buffer[100];
	DWORD dwRead;
	ReadFile(hDevice,buffer,100,&dwRead,&Overlap);
	//使用异步操作,程序不会等待ReadFile执行完,而是继续往下执行
	printf("并行执行");
	WaitForSingleObject(Overlap.hEvent,INFINITE);
	CloseHandle(hDevice);
	getchar();
	return 0;
}

总结
异步方式调用驱动在ZwReadFile里面传入了一个APC函数,当IRP_MJ_READ在被调用驱动A处理结束后(驱动B ReadFile读取A时产生的IRP)会调用这个APC函数。

异步调用方式二

每打开一个设备,都会存在一个关联的文件对象(FILE_OBJECT),利用内核函数ObReferenceObjectByHandle可以获得和设备相关的文件对象指针。
当IRP_MJ_READ请求被结束后,文件对象的Event会被设置。因此可以利用文件对象的Event来当做同步点使用。

NTSTATUS IrpReadProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
	KdPrint(("DriverB:Enter B HelloDDKRead\n"));
	NTSTATUS ntStatus = STATUS_SUCCESS;

	UNICODE_STRING DeviceName;
	RtlInitUnicodeString(&DeviceName, L"\\Device\\MyDDKDeviceA");

	//初始化objectAttributes
	OBJECT_ATTRIBUTES objectAttributes;
	InitializeObjectAttributes(&objectAttributes,
		&DeviceName,
		OBJ_CASE_INSENSITIVE,
		NULL,
		NULL);

	HANDLE hDevice;
	IO_STATUS_BLOCK status_block;

	//异步打开设备
	ntStatus = ZwCreateFile(&hDevice,
		FILE_READ_ATTRIBUTES,//没有设SYNCHRONIZE
		&objectAttributes,
		&status_block,
		NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,
		FILE_OPEN_IF, 0, NULL, 0);

	LARGE_INTEGER offset = RtlConvertLongToLargeInteger(0);
	if (NT_SUCCESS(ntStatus))
	{
		ntStatus = ZwReadFile(hDevice, NULL, NULL, NULL, &status_block, NULL, 0, &offset, NULL);
	}

	if (ntStatus == STATUS_PENDING)
	{
		KdPrint(("DriverB:ZwReadFile return STATUS_PENDING!\n"));

		PFILE_OBJECT FileObject;
		ntStatus = ObReferenceObjectByHandle(hDevice,
											 0,	//源代码中为什么使用EVENT_MODIFY_STATE这个值?
											 *IoFileObjectType,
											 KernelMode, 
											 (PVOID*)&FileObject,
											 NULL);
		if (NT_SUCCESS(ntStatus))
		{
			KdPrint(("DriverB:Waiting..."));
			KeWaitForSingleObject(&FileObject->Event, Executive, KernelMode, FALSE, NULL);
			KdPrint(("DriverB:Driver A Read IRP completed now!\n"));
			ObDereferenceObject(FileObject);
		}
	}
	ZwClose(hDevice);

	ntStatus = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = ntStatus;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	KdPrint(("DriverB:Leave B HelloDDKRead\n"));
	return ntStatus;
}

通过符号链接打开设备

利用ZwOpenSymbolicLinkObject 内核函数先得到符号链接的句柄,然后使用
ZwQuerySymbolicLinkObject内核函数查找到设备名。通过设备名就可以方便地打开设
备了。

NTSYSAPI NTSTATUS ZwOpenSymbolicLinkObject(
  PHANDLE            LinkHandle,		//打开的符号链接句柄
  ACCESS_MASK        DesiredAccess,		//访问掩码  FILE_ALL_ACCESS
  POBJECT_ATTRIBUTES ObjectAttributes	//对象属性,符号链接名在对象里
);
NTSYSAPI NTSTATUS ZwQuerySymbolicLinkObject(
IN  HANDLE          LinkHandle,   //ZwOpenSymbolicLinkObject成功打开的句柄
OUT  PUNICODE_STRING LinkTarget,	//设备名
OUT  PULONG          ReturnedLength	//如果调用失败,该值指示了LinkTarget的最大长度
);
#pragma PAGEDCODE
NTSTATUS IrpReadProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
	KdPrint(("DriverB:Enter B HelloDDKRead\n"));
	NTSTATUS ntStatus = STATUS_SUCCESS;

	UNICODE_STRING DeviceSymbolicLinkName;
	RtlInitUnicodeString(&DeviceSymbolicLinkName, CALLED_SYMBOLICLINE_NAME);  //被调用驱动A的符号连接名

	//初始化objectAttributes
	OBJECT_ATTRIBUTES objectAttributes;
	InitializeObjectAttributes(&objectAttributes,
		&DeviceSymbolicLinkName,
		OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
		NULL,
		NULL);
	HANDLE hSymbolic;
	//设定了FILE_SYNCHRONOUS_IO_NONALERT或者FILE_SYNCHRONOUS_IO_ALERT为同步打开设备
	ntStatus = ZwOpenSymbolicLinkObject(&hSymbolic, FILE_ALL_ACCESS, &objectAttributes);
#define UNICODE_SIZE 50
	UNICODE_STRING LinkTarget;
	LinkTarget.Buffer = (PWSTR)ExAllocatePool(PagedPool, UNICODE_SIZE);
	LinkTarget.Length = 0;
	LinkTarget.MaximumLength = UNICODE_SIZE;

	ULONG unicode_length;
	ntStatus = ZwQuerySymbolicLinkObject(hSymbolic, &LinkTarget, &unicode_length);

	KdPrint(("DriverB:The device name is %wZ\n", &LinkTarget));

	InitializeObjectAttributes(&objectAttributes,
		&LinkTarget,
		OBJ_CASE_INSENSITIVE,
		NULL,
		NULL);

	HANDLE hDevice;
	IO_STATUS_BLOCK status_block;
	//设定了FILE_SYNCHRONOUS_IO_NONALERT或者FILE_SYNCHRONOUS_IO_ALERT为同步打开设备
	ntStatus = ZwCreateFile(&hDevice,
		FILE_READ_ATTRIBUTES | SYNCHRONIZE,
		&objectAttributes,
		&status_block,
		NULL, FILE_ATTRIBUTE_NORMAL, FILE_SHARE_READ,
		FILE_OPEN_IF, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0);

	if (!NT_SUCCESS(ntStatus))
	{
		ZwClose(hSymbolic);
		ExFreePool(LinkTarget.Buffer);
		return ntStatus;
	}
	ZwReadFile(hDevice, NULL, NULL, NULL, &status_block, NULL, 0, NULL, NULL);
	ZwClose(hDevice);
	ZwClose(hSymbolic);
	ExFreePool(LinkTarget.Buffer);

	ntStatus = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = ntStatus;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	KdPrint(("DriverB:Leave B HelloDDKRead\n"));
	return ntStatus;
}

通过设备指针调用其他驱动程序

用loBuildSynchronousFsdRequest创建IRP

NTSTATUS IoGetDeviceObjectPointer(
 IN PUNICODE_STRING ObjectName,	//设备名,用UNICODE字符串表示
 IN ACCESS_MASK     DesiredAccess,	//以什么样的权限得到设备指针
 OUT PFILE_OBJECT    *FileObject,	//返回一个和设备相关的文件对象指针
 OUT PDEVICE_OBJECT  *DeviceObject	//返回设备对象指针
);	

可以通过loBuildSynchronousFsdRequest和loBuildAsynchronousFsdRcquest 两个内核
函数创建IRP,它们分别用来创建同步类型的IRP和创建异步类型的IRP。这两个内核函
数可以创建IRP_ MJ_ PNP、IRP_ MJ_ READ、IRP_ MJ_ WRITE、IRP_ MJ_ FLUSH_ BUFFERS和IRP_ MJ_ SHUTDOWN类型的IRP。

另外,还可以使用loAllocateIrp 内核函数,它可以创建任意类型的IRP。
IoBuildSynchronousFsdRequest、loBuildAsynchronousFsdRequest 、loBuildDeviceloControlRequest这三个内核函数是属于靠近上层的内核函数。而loAllocatelrp 是比较底层的内核函数,以上三个内核函数都是通过调用loAllocateIrp实现的。

创建完IRP后,还要构造IRP的I/O堆栈,每层I/O堆栈对应一个设备对象。由于示
例程序DriverA是单层驱动程序,所以只需要构造IRP的第一层I/O堆栈。
最后是通过loCallDriver内核函数调用相应的驱动。loCallDriver 内核函数会根据IRP
的类型,找到相应的派遣函数。

总结一下,手动创建IRP有以下几个步骤。
➊先得到设备的指针。一种 方法是用IoGetDeviceObjectPointer 内核函数得到设备对
象指针。另外一种方法是用ZwCreateFile内核函数先得到设备句柄,然后调用
ObReferenceObjectByPointer内核函数通过设备句柄得到设备对象指针。

❷手动创建IRP, 有4个内核函数可以选择,它们分别是loBuildSynchronous
FsdRequest、loBuildAsynchronousFsdRequest、 loBuildDeviceloControlRequest 和IoAllocatelrp。

其中IoAllocateIrp 内核函数是最灵活的,使用也最复杂。
❸构造IRP的IO堆栈。

④调用loCallDriver内核函数,其内部会调用设备对象的派遣函数。

  1. 用IoBuildSynchronousFsdRequest创建IRP
  PIRP IoBuildSynchronousFsdRequest(
  ULONG            MajorFunction, //第一个参数MajorFunction:这个参数是创建的IRP的主类型,loBuildSynchronous
//FsdRequest函数只支持IRP_MJ_PNP、IRP_MJ_READ、IRP_MJ_WRITE、
//IRP_MJ_FLUSH_BUFFERS和IRP_MJ_SHUTDOWN。

  PDEVICE_OBJECT   DeviceObject,	//设备对象指针 IRP将会传递给这个设备指针
  PVOID            Buffer,	//对于IRP_MJ_READ和IRP_MJ_WRITE buffer指的是输入和输出缓冲区
  ULONG            Length,	//缓冲区的大小
  PLARGE_INTEGER   StartingOffset,	//指向磁盘上偏移量的指针,用于读取和写入请求。这个值的单位和意义是特定于驱动程序的.此参数是读写请求所必需的,但对于刷新和关闭请求,则必须为零
  PKEVENT          Event,//同步事件,这是创建同步类型IRP的关键
  PIO_STATUS_BLOCK IoStatusBlock //操作状态
);

使用loBuildSynchronousFsdRequest内核函数创建同步类型IRP,关键在于第六个参数
Event。在调用loBuildSynchronousFsdRequest之前,需要准备一“个事件。 这个事件会和IRP

请求进行关联,当IRP请求被结束时该事件被触发。loBuildSynchronousFsdRequest 和
loBuildAsynchronousFsdRequest内核函数之间的区别就是是否提供事件

#pragma PAGEDCODE
NTSTATUS IrpReadProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
	
	KdPrint(("DriverB:Enter B HelloDDKRead\n"));
	NTSTATUS ntStatus = STATUS_SUCCESS;

	UNICODE_STRING DeviceName;
	RtlInitUnicodeString(&DeviceName, CALLED_DEVICE_NAME);

	PDEVICE_OBJECT DeviceObject = NULL;
	PFILE_OBJECT FileObject = NULL;
	//第一步 得到设备对象指针,计数器加1
	//如果是第一次调用IoGetDeviceObjectPointer,会打开设备,相当于调用ZwCreateFile
	ntStatus = IoGetDeviceObjectPointer(&DeviceName, FILE_ALL_ACCESS, &FileObject, &DeviceObject);

	KdPrint(("DriverB:FileObject:%x\n", FileObject));
	KdPrint(("DriverB:DeviceObject:%x\n", DeviceObject));

	if (!NT_SUCCESS(ntStatus))
	{
		KdPrint(("DriverB:IoGetDeviceObjectPointer() 0x%x\n", ntStatus));

		ntStatus = STATUS_UNSUCCESSFUL;
		// 完成IRP
		pIrp->IoStatus.Status = ntStatus;
		pIrp->IoStatus.Information = 0;	// bytes xfered
		IoCompleteRequest(pIrp, IO_NO_INCREMENT);
		KdPrint(("DriverB:Leave B HelloDDKRead\n"));

		return ntStatus;
	}

	//初始化一个事件对象
	KEVENT event;
	KeInitializeEvent(&event, NotificationEvent, FALSE);
	IO_STATUS_BLOCK status_block;
	LARGE_INTEGER offsert = RtlConvertLongToLargeInteger(0);

	//创建同步IRP
	PIRP pNewIrp = IoBuildSynchronousFsdRequest(IRP_MJ_READ,
		DeviceObject,
		NULL, 0,
		&offsert, &event, &status_block);
	KdPrint(("DriverB:pNewIrp:%x\n", pNewIrp));

	//构造IRP的IO堆栈   任何内核模式程序在创建一个IRP时,同时还创建了一个与之关联的IO_STACK_LOCATION结构数组:
	//数组中的每个堆栈单元都对应一个将处理该IRP的驱动程序
	PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(pNewIrp);
	stack->FileObject = FileObject;

	//调用DriverA,会一直调用到DriverA的派遣函数
	NTSTATUS status = IoCallDriver(DeviceObject, pNewIrp);

	if (status == STATUS_PENDING) {

		//如果DriverA的派遣函数没有完成IRP,则等待IRP完成
		status = KeWaitForSingleObject(
			&event,
			Executive,
			KernelMode,
			FALSE, // Not alertable
			NULL);
		status = status_block.Status;
	}

	//将引用计数减1,如果此时计数器减为0,
	//则将关闭设备,相当于调用ZwClose
	ObDereferenceObject(FileObject);


	ntStatus = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = ntStatus;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	KdPrint(("DriverB:Leave B HelloDDKRead\n"));
	return ntStatus;
}

用loBuildAsynchronousFsdRequest创建IRP
这个函数没有Event对象,如果需要等待创建的IRP处理完成的话,可以利用IRP里面的UserEvent来进行同步.

当执行loCompleteRequest内核函数时,操作系统会检查IRP的UserEvent子域是否为
空。如果UserEvent子域非空,则它代表一个事件指针,这时候loCompleteRequest会设置
这个事件。

#pragma PAGEDCODE
NTSTATUS IrpReadProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
	KdPrint(("DriverB:Enter B HelloDDKRead\n"));
	NTSTATUS ntStatus = STATUS_SUCCESS;

	UNICODE_STRING DeviceName;
	RtlInitUnicodeString(&DeviceName, L"\\Device\\MyDDKDeviceA");

	PDEVICE_OBJECT DeviceObject = NULL;
	PFILE_OBJECT FileObject = NULL;
	//得到设备对象指针
	ntStatus = IoGetDeviceObjectPointer(&DeviceName, FILE_ALL_ACCESS, &FileObject, &DeviceObject);

	KdPrint(("DriverB:FileObject:%x\n", FileObject));
	KdPrint(("DriverB:DeviceObject:%x\n", DeviceObject));

	if (!NT_SUCCESS(ntStatus))
	{
		KdPrint(("DriverB:IoGetDeviceObjectPointer() 0x%x\n", ntStatus));

		ntStatus = STATUS_UNSUCCESSFUL;
		// 完成IRP
		pIrp->IoStatus.Status = ntStatus;
		pIrp->IoStatus.Information = 0;	// bytes xfered
		IoCompleteRequest(pIrp, IO_NO_INCREMENT);
		KdPrint(("DriverB:Leave B HelloDDKRead\n"));

		return ntStatus;
	}

	KEVENT event;
	KeInitializeEvent(&event, NotificationEvent, FALSE);
	IO_STATUS_BLOCK status_block;
	LARGE_INTEGER offsert = RtlConvertLongToLargeInteger(0);

	//创建异步IRP
	PIRP pNewIrp = IoBuildAsynchronousFsdRequest(IRP_MJ_READ,
		DeviceObject,
		NULL, 0,
		&offsert, &status_block);
	KdPrint(("pNewIrp->UserEvent :%x\n", pNewIrp->UserEvent));
	//设置pNewIrp->UserEvent,这样在IRP完成后可以通知该事件
	pNewIrp->UserEvent = &event;

	KdPrint(("DriverB:pNewIrp:%x\n", pNewIrp));

	PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(pNewIrp);
	stack->FileObject = FileObject;

	NTSTATUS status = IoCallDriver(DeviceObject, pNewIrp);

	if (status == STATUS_PENDING) {
		status = KeWaitForSingleObject(
			&event,
			Executive,
			KernelMode,
			FALSE, // Not alertable
			NULL);
		status = status_block.Status;
	}

	ZwClose(FileObject);

	//关闭设备句柄
	ObDereferenceObject(FileObject);

	ntStatus = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = ntStatus;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	KdPrint(("DriverB:Leave B HelloDDKRead\n"));
	return ntStatus;
}

用loAllocatelrp创建IRP

所有对设备的操作都会转化为-一个IRP,IRP会在驱动程序中被处理。IRP 请求被结
束,就代表着对设备操作的结束,IRP 的完成状态就是操作的完成状态。而所有的IRP最
终都是由IoAllocateIrp内核函数创建的。

整个Windows是个异步的框架,IRP 请求可以被异步地结束。如果对异步请求用同步
事件进行同步时,异步请求就变成了同步请求。可以说同步请求是异步请求的一个特例,
这如同静止状态是运动状态的一一个特例一样。 驱动程序开发者大部分的任务就是创建和处
理IRP请求。

PIRP
IoAllocateIrp (
IN CCHAR Stacksize //设置堆栈大小
IN BOOLEAN ChargeQuota	//是否使用磁盘配额

使用loAllocatelrp来创建IRP时,需要自己手动调用IoFreeIrp来删除IRP对象.


#pragma PAGEDCODE
NTSTATUS IrpReadProc(PDEVICE_OBJECT pDeviceObject/*设备信息*/, PIRP pIrp/*参数信息*/)
{
	KdPrint(("DriverB:Enter B HelloDDKRead\n"));
	NTSTATUS ntStatus = STATUS_SUCCESS;

	UNICODE_STRING DeviceName;
	RtlInitUnicodeString(&DeviceName, L"\\Device\\MyDDKDeviceA");

	PDEVICE_OBJECT DeviceObject = NULL;
	PFILE_OBJECT FileObject = NULL;
	
	//得到设备对象指针
	ntStatus = IoGetDeviceObjectPointer(&DeviceName, FILE_ALL_ACCESS, &FileObject, &DeviceObject);

	KdPrint(("DriverB:FileObject:%x\n", FileObject));
	KdPrint(("DriverB:DeviceObject:%x\n", DeviceObject));

	if (!NT_SUCCESS(ntStatus))
	{
		KdPrint(("DriverB:IoGetDeviceObjectPointer() 0x%x\n", ntStatus));
		ntStatus = STATUS_UNSUCCESSFUL;
		// 完成IRP
		pIrp->IoStatus.Status = ntStatus;
		pIrp->IoStatus.Information = 0;	// bytes xfered
		IoCompleteRequest(pIrp, IO_NO_INCREMENT);
		KdPrint(("DriverB:Leave B HelloDDKRead\n"));

		return ntStatus;
	}

	KEVENT event;
	KeInitializeEvent(&event, NotificationEvent, FALSE);

	PIRP pNewIrp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
	KdPrint(("pNewIrp->UserEvent :%x\n", pNewIrp->UserEvent));
	pNewIrp->UserEvent = &event;

	IO_STATUS_BLOCK status_block;
	pNewIrp->UserIosb = &status_block;
	pNewIrp->Tail.Overlay.Thread = PsGetCurrentThread();

	//因为DriverA是BUFFER IO设备
	pNewIrp->AssociatedIrp.SystemBuffer = NULL;

	KdPrint(("DriverB:pNewIrp:%x\n", pNewIrp));

	PIO_STACK_LOCATION stack = IoGetNextIrpStackLocation(pNewIrp);
	stack->MajorFunction = IRP_MJ_READ;
	stack->MinorFunction = IRP_MN_NORMAL;//0
	stack->FileObject = FileObject;

	//调用DriverA驱动
	NTSTATUS status = IoCallDriver(DeviceObject, pNewIrp);

	if (status == STATUS_PENDING) {
		status = KeWaitForSingleObject(
			&event,
			Executive,
			KernelMode,
			FALSE, // Not alertable
			NULL);
		KdPrint(("STATUS_PENDING\n"));
	}
	//对象引用计数-1
	ObDereferenceObject(FileObject);
	
	//释放IRP对象
	IoFreeIrp(pNewIrp);

	ntStatus = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = ntStatus;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest(pIrp, IO_NO_INCREMENT);
	KdPrint(("DriverB:Leave B HelloDDKRead\n"));
	return ntStatus;

}

其它方式获得设备指针

使用未导出函数ObReferenceObjectByName来获得设备指针

NTKERNELAPI	NTSTATUS
ObReferenceObjectByName(
IN PUNICODE_STRING objectName,	//指定打开设备的设备名
IN ULONG Attributes,	//这个属性一般设置为OBJ_CASE_INSENSITIVE
IN PACCESS_STATE PassedAccessstate OPTIONAL, //一般设置为NULL
IN ACCESS_MASK DesiredAcces OPTIONAL,	//一般设置为FILE_ALL_ACCESS
IN POBJECT_TYPE ObjectType,	//如果要获得设备对象指针,需要指定这个参数为IoDeviceObjectType
IN KPROCESSOR_MODE AccessMode,	//驱动中用KernelMode
IN OUT PVOID ParseContext OPTIONAL,  //一般设置为NULL
OUT PVOID *object		//返回的内核对象的指针
);
extern POBJECT_TYPE IoDeviceObjectType;

ObReferenceObjectByName和IoGetDeviceObjectPointer内核函数虽然都是获取设备对
象指针,但是却有一些不同。 ObReferenceObjectByName 内核函数仅仅是通过名字得到对象的指针而已,除了得到设备对象指针外,也可以得到别的内核对象的指针,比如内核事件、互斥体对象等。ObReferenceObjectByName 内核函数会增加对设备对象的引用计数,因此在需要使用设备对象完毕后,需要调用ObDereferenceObject内核函数将引用计数减1。

而loGetDeviceObjectPointer 内核函数只能得到设备对象指针。在loGetDeviceObject
Pointer内核函数内部,得到设备对象指针后还会打开设备对象,也就是相当于向该设备对象发送IRP_ MJ CREATE的IRP。同时,loGetDeviceObjectPointer 内核函数还获得了与设备对象相关的文件对象句柄。在使用完设备对象后,需要对设备相关的文件对象调用
ObDereferenceObject内核函数,这样相当于向设备发送IRP MJ CLOSE。

#pragma PAGEDCODE
NTSTATUS IrpReadProc(IN PDEVICE_OBJECT pDevObj,
								 IN PIRP pIrp) 
{
	KdPrint(("DriverB:Enter B HelloDDKRead\n"));
	NTSTATUS ntStatus = STATUS_SUCCESS;

	UNICODE_STRING DeviceName;
	RtlInitUnicodeString( &DeviceName, L"\\??\\HelloDDKA" );

	PDEVICE_OBJECT DeviceObject = NULL;
	PFILE_OBJECT FileObject = NULL;
 
 	ntStatus = ObReferenceObjectByName(&DeviceName,OBJ_CASE_INSENSITIVE,NULL,FILE_ALL_ACCESS,IoDeviceObjectType,KernelMode,NULL,(PVOID*)&DeviceObject);

	KdPrint(("ntStatus %x\n",ntStatus));
	KdPrint(("DeviceObject %x\n",DeviceObject));
 	ObDereferenceObject( FileObject );
	ntStatus = STATUS_SUCCESS;
	// 完成IRP
	pIrp->IoStatus.Status = ntStatus;
	pIrp->IoStatus.Information = 0;	// bytes xfered
	IoCompleteRequest( pIrp, IO_NO_INCREMENT );
	KdPrint(("DriverB:Leave B HelloDDKRead\n"));
	return ntStatus;
}

剖析loGetDeviceObjectPointer

//模拟IoGetDeviceObjectPointer实现
NTSTATUS
MyIoGetDeviceObjectPointer(
    IN PUNICODE_STRING ObjectName,
    IN ACCESS_MASK DesiredAccess,
    OUT PFILE_OBJECT *FileObject,
    OUT PDEVICE_OBJECT *DeviceObject
    )
{
    PFILE_OBJECT fileObject;
    OBJECT_ATTRIBUTES objectAttributes;
    HANDLE fileHandle;
    IO_STATUS_BLOCK ioStatus;
    NTSTATUS status;

	//设置要打开的设备的设备名
    InitializeObjectAttributes( &objectAttributes,
                                ObjectName,
                                OBJ_KERNEL_HANDLE,
                                (HANDLE) NULL,
                                (PSECURITY_DESCRIPTOR) NULL );

	//ZwOpenFile打开设备
    status = ZwOpenFile( &fileHandle,
                        DesiredAccess,
                        &objectAttributes,
                        &ioStatus,
                        0,
                        FILE_NON_DIRECTORY_FILE );

    if (NT_SUCCESS( status )) 
	{
		//得到文件对象指针
        status = ObReferenceObjectByHandle( fileHandle,
                                            0,
                                            *IoFileObjectType,
                                            KernelMode,
                                            (PVOID *) &fileObject,
                                            NULL );
        if (NT_SUCCESS( status )) 
		{
            *FileObject = fileObject;
			//得到设备对象指针
            *DeviceObject = IoGetBaseFileSystemDeviceObject( fileObject );
        }
        ZwClose( fileHandle );
    }
    return status;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值