IRP(I/O Request Package)详解

篇一:


简介:

IRP(I/O Request Package)在windows内核中,有一种系统组件——IRP,即输入输出请求包。

当上层应用程序需要访问底层输入输出设备时,发出I/O请求,系统会把这些请求转化为IRP数

据,不同的IRP会启动I/O设备驱动中对应的派遣函数。

IRP类型

由于IRP是响应上层应用程序的。可想而知,IRP类型是与上层对底层设备的访问类型相对应。

文件相关的I/O函数如:CreateFile/ReadFile/WriteFile/CloseHandle等,操作系统就会将其转为

IRP_MJ_CREATE/IRP_MJ_READ/IRP_MJ_WRITE/IRP_MJ_CLOSE等IRP类型,这些

IRP再被传送到驱动程序的派遣函数中。


IRP列表如下:

   名称 

  描述 

 调用者

IRP_MJ_CREATE                 

请求一个句柄  

CreateFile 

IRP_MJ_CLEANUP

在关闭句柄时取消悬挂的IRP  

CloseHandle 

IRP_MJ_CLOSE

关闭句柄 

CloseHandle 

IRP_MJ_READ 

 从设备得到数据

ReadFile

IRP_MJ_WRITE   

传送数据到设备  

WriteFile 

IRP_MJ_DEVICE_CONTROL 

 控制操作(利用IOCTL宏)

DeviceIoControl 

RP_MJ_INTERNAL_DEVICE_CONTROL

控制操作(只能被内核调用) 

 N/A 

IRP_MJ_QUERY_INFORMATION

得到文件的长度  

 GetFileSize 

IRP_MJ_SET_INFORMATION 

设置文件的长度

 SetFileSize 

IRP_MJ_FLUSH_BUFFERS

写输出缓冲区或者丢弃输入缓冲区 

FlushFileBuffers 

FlushConsoleInputBuffer 

PurgeComm

IRP_MJ_SHUTDOWN

  系统关闭  

 InitiateSystemShutdown



IRP对应的派遣函数处理过程

多数的IRP都来自于Win32 API函数,如CreateFile,ReadFile,WriteFile函数等等。

一种简单的IRP派遣函数的实现就是:将该IRP中的状态置为成功(pIRP->IoStatus =

STATUS_SUCCESS ),然后结束该IRP请求(调用I噢CompleteRequest函数),并返回

成功状态。

  1.        NTSTATUS status = STATUS_SUCCESS;  
  2. // 完成IRP  
  3. pIrp->IoStatus.Status = status;  
  4. pIrp->IoStatus.Information = 0;  // bytes xfered  
  5. IoCompleteRequest( pIrp, IO_NO_INCREMENT );  
  6.   
  7. KdPrint(("Leave HelloDDKDispatchRoutin\n"));  
  8.   
  9. return status;  

 
 
  1. NTSTATUS status = STATUS_SUCCESS;
  2. // 完成IRP
  3. pIrp->IoStatus.Status = status;
  4. pIrp->IoStatus.Information = 0; // bytes xfered
  5. IoCompleteRequest( pIrp, IO_NO_INCREMENT );
  6. KdPrint(( "Leave HelloDDKDispatchRoutin\n"));
  7. return status;

VOID 
  IoCompleteRequest(
    IN PIRP
  Irp,
    IN CCHAR
  PriorityBoost
    );


下面以ReadFile为例,详细介绍。
1.ReadFile调用ntdll中的N他ReadFile。其中ReadFile函数是Win32 API,而NtReadFile

   函数是Native API。

2.ntdll中的N他ReadFile进入内核模式,并调用系统服务中的N他ReadFile函数。

3.系统服务函数N他ReadFile创建IRP_MJ_WRITE类型的IRP,然后将这个IRP函数发

   送到对应驱动程序的派遣函数中。

4.在对应的派遣函数中一般会通过IoCompleteRequest函数将IRP请求结束。

篇2:


第5章 I/O Request Packet

5.1 数据结构
在处理 I/O 请求上,有两个重要的数据结构:IRP(I/O request packet)和 IO_STACK_LOCATION

5.1.1 IRP 的结构
下面是在 windbg 里得到的 IRP 结构:

nt!_IRP
+0x000 Type : Int2B
+0x002 Size : Uint2B
+0x004 MdlAddress : Ptr32 _MDL
+0x008 Flags : Uint4B
+0x00c AssociatedIrp : <unnamed-tag>
+0x010 ThreadListEntry : _LIST_ENTRY
+0x018 IoStatus : _IO_STATUS_BLOCK
+0x020 RequestorMode : Char
+0x021 PendingReturned : UChar
+0x022 StackCount : Char
+0x023 CurrentLocation : Char
+0x024 Cancel : UChar
+0x025 CancelIrql : UChar
+0x026 ApcEnvironment : Char
+0x027 AllocationFlags : UChar
+0x028 UserIosb : Ptr32 _IO_STATUS_BLOCK
+0x02c UserEvent : Ptr32 _KEVENT
+0x030 Overlay : <unnamed-tag>
+0x038 CancelRoutine : Ptr32 void
+0x03c UserBuffer : Ptr32 Void
+0x040 Tail : <unnamed-tag>

MdlAddress 用来描述 user-mode buffer 的 MDL(memory descriptor list),这个域仅用于“direct I/O”。
假如最上层的 device object 的 flags 标志设置为 DO_DIRECT_IO 时:
(1) I/O 建立 IRP_MJ_READ 和 IRP_MJ_WRITE 时使用 MDL。
(2) I/O 建立 IRP_MJ_DEVICE_CONTROL 时假如 control 代码为 METHOD_IN_DIRECT 或 METHOD_OUT_DIRECT,使用 MDL。
MDL 描述 user-mode virtual buffer 也包含对应的 physical address,driver 使用它能尽快地访问 user-mode buffer。

AssociatedIrq 是一个 union 成员,它的结构如下:
union {
struct _IRP *MasterIrp; // 此 IRP 是 associate IRP,它指向 master IRP
LONG IrpCount; // 此 IRP 是 master IRP,它指示 associate IRP 的个数
PVOID SystemBuffer; // 此 IRP 是 master IRP,它指向 system buffer
} AssociatedIrp; // 用于和 user-mode buffer 进行数据交换。

AssociatedIrq.SystemBuffer 指向 kernel-mode nonpaged 的 data buffer 区域,它使用在下面情形:
(1) 在 IRP_MJ_READ 和 IRP_MJ_WRITE 操作里,假如最上层的 device object 的 flags 提供了 DO_BUFFERED_IO
(2) 在 IRP_MJ_DEVICE_CONTROL 操作里,假如 I/O control code 指示需要 buffer。调用 WriteFile() 或者 DeviceIoControl() 用作输入 data
I/O manager 复制 user-mode data buffer 到 kernel-mode data buffer 里。
(3) 在读操作里,I/O manager 复制 kernel-mode data buffer 到 user-mode data buffer 里。
IoStatus 是一个结构体,包含了两个域:Status 与 Information。IoStatus.Status 接收 NTSTATUS 码,而 IoStatus.Information 是 ULONG 类型,
接收一个确切的值依赖于 IRP 的类型和完成的状态。一个通常的用法是:Information 域保存传送数据的 bytes 数(例如在 IRP_MJ_READ 操作上)。
它的结构类似如下:
typedef struct _IO_STATUS_BLOCK
{
union {
ULONG Status;
PVOID Pointer;
};
ULONG Information;
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;

RequestorMode 是 UserMode 或者 KernelMode 这个值之一。
CancelRoutine 是 driver 中 IRP cancel routine 的地址,需要使用 IoSetCancelRoutine() 设置,避免直接对它进行设置。
UserBuffer 是保存 user-mode 的 data buffer,与 kernel-mode data buffer 进行数据交换。
最后是 Tail 成员,它是一个 union 变量,这个 Tail 比较复杂,它的结构如下:

union
{
struct
{
union
{
KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
struct
{
PVOID DriverContext[4];
};
};

	PETHREAD thread;
	PCHAR AuxiliaryBuffer;

	struct
	{
		LIST_ENTRY ListEntry;
		union
		{
			struct _IO_STACK_LOCATION *CurrentStackLocation;
			ULONG PacketType;
		};
	};

	PFILE_OBJECT OriginalFileObject;
} Overlay;

KAPC Apc;
PVOID CompletionKey;

} Tail;

Tail union 包括三个部分:Overlay,Apc 以及 CompletionKey。

5.1.2 I/O stack
当 kernel-mode 程序建立一个 IRP 时,它同时也建立相应的 IO_STACK_LOCATION 结构的数组,每个元素被称为 stack location。
一个 stack location 包含着 IRP 的 type 和 parameter 信息,也包含着 completion routine 地址,它的结构如下:

nt!_IO_STACK_LOCATION
+0x000 MajorFunction : UChar
+0x001 MinorFunction : UChar
+0x002 Flags : UChar
+0x003 Control : UChar
+0x004 Parameters : <unnamed-tag>
+0x014 DeviceObject : Ptr32 _DEVICE_OBJECT
+0x018 FileObject : Ptr32 _FILE_OBJECT
+0x01c CompletionRoutine : Ptr32 long
+0x020 Context : Ptr32 Void

其中,Parameters 成员定义为一个复杂的 union 结构,如下:

union
{
//
// NtCreateFIle 参数
//
struct
{
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT POINTER_ALIGNMENT FileAttributes;
USHORT ShareAccess;
ULONG POINTER_ALIGNMENT EaLength;
} Create;

//
// NtCreateNamedPipeFile 参数
//
struct
{
	PIO_SECURITY_CONTEXT SecurityContext;
	ULONG Options;
	USHORT POINTER_ALIGNMENT Reserved;
	USHORT SharedAccess;
	PNAMED_PIPE_CREATE_PARAMETERS Parameters;
} CreatePipe;

//
// NtCreateMailsotFIle  参数
//
struct
{
	PIO_SECURITY_CONTEXT SecurityContext;
	ULONG Options;
	USHORT POINTER_ALIGNMENT Reserved;
	USHORT SharedAccess;
	PMAILSLOT_CREATE_PARAMETERS Parameters;
} CreateMailslot;


//
// NtReadFile 参数
//
struct
{
	ULONG Length;
	ULONG PINTER_ALIGNMENT Key;
	LARGE_INTEGER ByteOffset;
} Read;

//
// NtWriteFile 参数
//
struct
{
	ULONG Length;
	ULONG POINTER_ALIGNMENT Key;
	LARGE_INTEGER ByteOffset;
} Write;

//
// NtQueryDirectoryFile 参数
//
struct
{
	ULONG Length;
	PSTRING FileName;
	FILE_INFORMATION_CLASS FileInformationClass;
	ULONG POINTER_ALIGNMENT FileIndex;
} QueryDirectory;

//
// NtNotifyChangeDirectoryFile 参数
//
struct
{
	ULONG Length;
	ULONG POINTER_ALIGNMENT CompletionFilter;
} NotifyDirectory;


//
// NtQueryInformationFile 参数
//
struct
{
	ULONG Length;
	FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;
} QueryFile;

//
// NtSetInformationFile 参数
//
struct
{
	ULONG Length;
	FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;
	PFILE_OBJECT FileObject;
	union
	{
		struct
		{
			BOOLEAN ReplaceIfExists;
			BOOLEAN AdvanceOnly;
		};
		ULONG ClusterCount;
		HANDLE DeleteHandle;
	};
} SetFile;


//
// NtQueryEaFile 参数
//
struct
{
	ULONG Length;
	PVOID EaList;
	ULONG EaListLength;
	ULONG POINTER_ALIGNMENT EaIndex;
} QueryEa;

//
// NtSetEaFIle 参数
//
struct
{
	ULONG Length;
} SetEa;

//
// NtQueryVolumeInformationFile 参数
//
struct
{
	ULONG Length;
	FS_INORTMATION_CLASS POINTER_ALIGNMENT FsInformationClass;
} QueryVoume;


// 
// NtSetVolumeInformationFile  参数
//
struct 
{
	ULONG Length;
	FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;
} setValue;


//
// NtFsControlFile  参数
//
struct
{
	ULONG OutputBufferLength;
	ULONG POINTER_ALIGNMENT InputBufferLength;
	ULONG POINTER_ALIGNMENT  FsControlCode;
	PVOID Type3InputBuffer;
} FileSystemControl;


//
// NtLockFile/NtUnlockFile 参数
//
struct
{
	PLARGE_INTEGER Length;
	ULONG POINTER_ALIGNMENT Key;
	LARGE_INTEGER ByteOffset;
} LockControl;


//
// NtDeviceIoControlFile 参数
//
struct
{
	ULONG OutputBufferLength;
	ULONG POINTER_ALIGNMENT InputBufferLength;
	ULONG POINTER_ALIGNMENT IoControlCode;
	PVOID Type3InputBuffer;
} DeviceIoControl;


//
// NtQuerySecurityObject 参数
//
struct
{
	SECURITY_INFORMATION SecurityInformation;
	ULONG POINTER_ALIGNMENT Length;
} QuerySecurity;


//
// NtSetScurityObject 参数
//
struct
{
	SECURITY_INFORMATION SecurityInformation;
	PSECURITY_DESCRIPTOR SecurityDescriptor;
} SetSecurity;


//
// MountVoluem  参数
//
struct
{
	PVPB Vpb;
	PDEVICE_OBJECT DeviceObject;
} MountVolume;


//
// VerifyVolume 参数
//
struct
{
	PVPB Vpb;
	PDEVICE_OBJECT DeviceObject;
} VerityVolume;


//
// Scsi 内部 device control
//
struct
{
	struct _SCSI_REQUEST_BLOCK *Srb;
} Scsi;


//
// NtQueryQuotaInformationFile  参数
//
struct
{
	ULONG Length;
	PSID StartSid;
	PFILE_GET_QUOTA_INFORMATION SidList;
	ULONG SidListLength;
} QueryQuota;


//
// NtSetQuotaInformationFile  参数
//
struct
{
	ULONG Length;
} SetQuota;


//
// IRP_MN_QUERY_DEVICE_RELATIONS 参数
//
struct
{
	DEVICE_RELATION_TYPE Type;
} QueryDevceRelations;


//
// IRP_MN_QUERY_INTERFACE 参数
//
struct
{
	CONST GUID *InterfaceType;
	USHORT Size;
	USHORT Version;
	PINTERFACE Interface;
	PVOID InterfacespecificData;
} QueryInterface;

//
// IRP_MN_QUERY_CAPABILITIES 参数
//
struct
{
	PDEVICE_CAPABILITIES Capabilities;
} DeviceCapabilities;


//
// IRP_MN_FILTER_RESOURCE_REQUIREMENTS 参数
//
struct
{
	PIO_RESOURCE_REQUIREMENTS_LIST IoResourceRequirementList;
} FilterResourceRequirements;
	

//
// IRP_MN_READ_CONFIG 和 IRP_MN_WRITE_CONFIG 参数
//
struct
{
	ULONG WhichSpace;
	PVOID Buffer;
	ULONG Offset;
	ULONG POINTER_ALIGNMENT Length;
} ReadWriteConfig;


//
// IRP_MN_SET_LOCK 参数
//
struct
{
	BOOLEAN Lock;
} SetLock;

//
// IRP_MN_QUERY_ID 参数
//
struct
{
	BUS_QUERY_ID_TYPE IdType;	
} QueryId;


//
// IRP_MN_QUERY_DEVICE_TEXT 参数
//
struct
{
	DEVICE_TEXT_TYPE DeviceTextType;
	LCID POINTER_ALIGNMENT LocaleId;
}  QueryDeviceText;


//
// IRP_MN_DEVICE_USAGE_NOTIFICATION 参数
//
struct
{
	BOOLEAN InPath;
	BOOLEAN Reserved[3];
	DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT Type;
} UsageNotification;


//
// IRP_MN_WAIT_WAKE 参数
//
struct
{
	SYSTEM_POWER_STATE PowerState;
} WaitWake;


//
// IRP_MN_POWER_SEQUENCE 参数
//
struct
{
	PPOWER_SEQUENCE PowerSequence;
} PowerSquence;


//
// IRP_MN_SET_POWER 和 IRP_MN_QUERY_POWER 参数
//
struct
{
	ULONG SystemCotext;
	POWER_STATE_TYPE POINTER_ALIGNMENT Type;	
	POWER_STATE POINTER_ALIGNMENT State;
	POWER_ACTION POINTER_ALIGNMENT ShutdownType;
} Power;


//
// StartDevice  参数
//
struct
{
	PCM_RESOURCE_LIST AllocatedResources;
	PCM_RESOURCE_LIST AllocatedResourcesTranslated;
} StartDevice;


//
// WMI Irps 参数
//
struct
{
	ULONG_PTR ProviderId;
	PVOID DataPath;
	ULONG BufferSize;
	PVOID Buffer;
} WMI;


//
// 其它 device 提供的参数
//
struct
{
	PVOID Argument1
	PVOID Argument2;
	PVOID Argument3;
	PVOID Argument4;
} Others;

} Parameters;

Parameters 为每个类型的 request 提供参数,例如:Create(IRP_MJ_CREATE 请求),Read(IRP_MJ_READ 请求),StartDevice(IRP_MJ_PNP 的子类 IRP_MN_START_DEVICE)
MajorFunction 和 MinorFunction 分别的 IRP 的主功能号和子功能号。DeviceObject 是 stack entry 相应的 device object,IoCallDriver() 将填写此域。
FileObject 指向 kernel file object。driver 经常使用这个 FileObject 指向关联的 IRP 在一个 request 队列里。
CompletionRoutine 是提供一个 I/O completion routine,不要直接设置这个域,而是使用 IoSetCompletionRoutine() 来设置。
Context 是任意的值,传递给 completion routine 作为参数。不要直接设置这个域,而是使用 IoSetCompletionRoutine() 来设置。

5.2 IRP 处理的标准模式
下面几个阶段:
I/O manager —> Dispatch routine —> StartIo routine —> ISR —> DPC routine —> I/O manager

5.2.1 建立一个 IRP
IRP 的生存期从调用 I/O manager function 建立 IRP 开始,你可以使用下面 4 个 function 来建立一个新的 IRP:
(1) IoBuildAsynchronousFsdRequest(): 建立一个 IRP 不希望等待。这个函数只适合用于某类的 IRP
(2) IoBuildSynchronousFsdRequest(): 建立一个 IRP 需要等待完成。
(3) IoBuildDeviceIoControlRequest(): 建立一个同步的 IRP_MJ_DEVICE_CONTROL 或者 IRP_MJ_INTERNAL_DEVICE_CONTROL
(4) IoAllcateIrp(): 建立一个 asynchronous 的 IRP

>>> 建立 synchronous IRP
使用 IoBuildSynchronousFsdRequest() 或 IoBuildDeviceIoControlRequest() 来建立同步的 IRP,同步 IRP 是属于创建者线程。
由它有一个物主,由此有下面的一系列结果:
(1) 假如物主线程终止,I/O manager 自动取消属于该线程的同步 IRP 的 pending
(2) 由于创建线程拥有这个同步 IRP 的缘故,你不能在任意线程 context 里创建同步 IRP,当物主线程终止后不能请求 I/O manager 取消 IRP。
(3) 调用 IoCompleteRequest(),I/O manager 自动清同步 IRP,并且置你必须提供的 event 置 signaled 状态。
(4) 在 I/O manager 置 event object signaled 状态后,event object 仍存在时你必须小心地处理 event object。
必须在 PASSIVE_LEVEL 里调用这两个函数,特别是不能在 APC_LEVEL 级别上。因为:在获得 fast mutex 后进入到 APC_LEVEL,然后 I/O manager
不能提交 special APC routine 去处理所有 complete 处理。

PIRP Irp = IoBuildSycnhronousFsdRequest(…);
ExAcqurireFastMutex(…);
NTSTATUS status = IoCallDriver(…);
if (status == STATUS_PENDING)
{
KeWaitForSingleObject(…); // 错误:不要这样做
}
ExReleaseFastMutex(…);

在上面的代码里,使用 KeWaitForSingleObject() 等待会进入死锁:当完成执行 IoCompleteRequest(),这个 APC routine 运行将设置 event,
因为已经在 APC_LEVEL 级别上,APC routine 不能运行去设置 event signled。
假如你需要发送一个 synchronous IRP 到其它 driver,考虑下面的选择:
(1) 使用定期的 kernel mutex 来代替 fast mutex,kernel mutex 将返回到 PASSIVE_LEVEL 级别上,并不会抑制 special APC 执行。
(2) 使用 KeEnterCriticalRegion() 来抑制所有除了 special APC 外,然后使用 ExAcquireFastMutexUnsafe() 来获得 mutex。
(3) 使用 asynchronous IRP(代替 synchronous IRP),完成后 signaled event。

这两个函数所建立的 IRP 为下表所示:
support function IRP 类型

IoBuildSynchronousFsdRequest() IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_SHUTDOWN
IRP_MJ_PNP
IRP_MJ_POWER(仅用于 IRP_MN_POWER_SEQUENCE)

IoBuildDeviceControlRequest() IRP_MJ_DEVICE_CONTROL
IRP_MJ_INTERNAL_DEVICE_CONTROL

>>> 建立异步 IRP
IoBuildAsynchronousFsdRequest() 和 IoAllocateIrp() 这两上函数建立异步的 IRP,这些可以建立 IRP 如下表所示:

support function IRP 类型

IoBuildAsynchronousFsdRequest() IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_FLUSH_BUFFERS
IRP_MJ_SHUTDOWN
IRP_MJ_PNP
IRP_MJ_POWER(仅用于 IRP_MN_POWER_SEQUENCE)

IoAllocateIrp() 任何(但必须初始化 Marjor function 表)

异步 IRP 不属于创建者线程,当 IRP 完成后,I/O manager 不调用 APC 以及不清理 IRP。考虑下面的问题:
(1) 当线程终止后,I/O manager 不会取消任何异步 IRP 的 pending
(2) 可以在任意线程 context 里创建
(3) 由于 IRP 完成后 I/O manager 不清理 IRP,你必须提供一个complete routine 去释放 buffer 以及调用 IoFreeIrp() 释放 IRP 所使用的内存。
(4) 当长时期没发生操作时,你可能需要提供一个 cancel routine。
(5) 由于不需要等待异步 IRP 的完成,你可以创建 IRP 在 IRQL <= DISPATCH_LEVEL 级别上,当获得 fast mutex 发送异步 IRP 是可以的。

5.2.2 dispatch routine
当建立一个 IRP 后,可以使用 IoGetNextIrpStackLocation() 来获得 first stack location,然后需要对 stack location 进行初始化。
如果是使用 IoAllcateIrp() 建立的需要填写相关的 MajorFunction 表。

PEDEVICE_OBJECT DeviceObject;
PIO_STACK_LOCATION stack = IoGetNextIrpStackLoction(Irp);
stack->MajorFunction = IRP_MJ_Xxx;
// … stack 初始化代码
NTSTATUS status = IoCallDriver(DeviceObject, Irp);

IoGetNextIrpStackLocation() 是一个宏用来获得当前的 stack location,它的定义如下:
#define IoGetNextIrpStackLocation(Irp) ((Irp)->Tail.Overlay.CurrentStackLocation - 1)

>>> What IoCallDriver Does
IoCallDriver() 看起来像下面:

NTSTATUS IoCallDriver(PDEVICE_OBJECT DeviceObject,
PIRP Irp)
{
IoSetNextIrpStackLocation(Irp);
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
Stack->DeviceObject = DeviceObject;
ULONG fcn = Stack->MajorFunction;
PDRVIER_OBJECT Driver = DeviceObject->DriverObject;
return (*Driver->MajorFunction[fcn]))(DeviceObject, Irp);
}

IoCallDriver() 简单地调用 stack 指针对应的 driver 的 dispatch routine。

>>> location device objects
除了使用 IoAttachDeviceToDeviceStack() 外,可以使用另外的两个方法:IoGetDeviceObjectPointer() 和 IoGetAttachedDeviceReference()
NTSTATUS
IoGetDeviceObjectPointer(
IN PUNICODE_STRING ObjectName,
IN ACCESS_MASK DesiredAccess,
OUT PFILE_OBJECT *FileObject,
OUT PDEVICE_OBJECT *DeviceObject
);
假如你知道 device object 的名字,那么你可以使用这个函数 IoGetDeviceObjectPointer() 得到 device object,像下面的用法:
PUNICODE_STRING devname;
ASSESS_MASK access;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
NTSTATUS status;

ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
status = IoGetDeviceObjectPointer(devname, access, &FileObject, &DeviceObject);

这个函数返回两个指针:一个指向 FILE_OBJECT, 一个指向 DEVICE_OBJECT。

PIRP Irp = IoXxx(…);
PIO_STACK_LOCATION Stack = IoGetNextIrpStackLocation(Irp);
ObReferenceObject(FileObject);
Stack->FileObject = FileObject;
IoCallDriver(DeviceObject, Irp);
ObDereferenceObject(FileObject);

IoGetDeviceObjectPointer() 执行一些步骤来定位返回的两个指针:
(1) 使用 ZwOpenFile() 打开一个命名的 device object,它将引发 object manager 建立一个 file object 和发送 IRP_MJ_CREATE 到目标设备,ZwOpenFile() 返回 file handle
(2) 调用 ObReferenceObjectByHandle() 得到代表 file handle 的 FILE_OBJECT 结构地址,这个地址以 FileObject 返回。
(3) 调用 IoGetRelatedDeviceObject() 得到被 FileObject 引用的 DEVICE_OBJECT 结构地址,这个地址以 DeviceObject 返回。
(4) 调用 ZwClose() 关闭 Handle

5.2.3 Dispatch routine 职责
一个 Dispatch routine 的原型,看起来像下面:
NTSTATUS DispatchXxx(PDEVICE_OBJECT fdo, PRIP Irp)
{
PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp);
PDEVICE_EXTENSION pdx = (PDEVICE_EXTENSION)fdo->DeviceExtension;

    ...
    return STATUS_Xxx;

}
1.你通常需要访问当前 stack location 去检测参数或都检查 minor 功能号
2.你通常也需要访问你建立的 device extension 结构(在 AddDevice() 时候初始化的)。
3.最后要返回到 IoCallDriver() 调用上。传送一个 NTSTATUS 值。

>>> IRP 的完成
完成一个 IRP 必须填允 IRP 的 IoStatus 域内的 Status 与 Information 值,然后调用 IoCompleteRequest() 函数。
这个 Status 值是在 NTSTATUS.h 文件里定义的 status code 之一。而 Information 值依赖于 IRP 的类型而定,大多时候当 IRP 失败后 Information 设置为 0
当 IRP 引发数据的传送操作,通常设置 Information 值为传送的字节数。

  • 1
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值