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
函式),並返回成功狀態。
NTSTATUS status = STATUS_SUCCESS;
// 完成IRP
pIrp->IoStatus.Status = status;
pIrp->IoStatus.Information = 0; // bytes xfered
IoCompleteRequest( pIrp, IO_NO_INCREMENT );
KdPrint(("Leave HelloDDKDispatchRoutin\n"));
return status;
VOID
IoCompleteRequest(
IN PIRP Irp,
IN CCHAR PriorityBoost
);
下面以ReadFile
為例,詳細介紹。
ReadFile
呼叫ntdll中的N他ReadFile
。其中ReadFile
函式是Win32 API
,而NtReadFile
函式是Native API
。ntdll
中的N他ReadFile
進入核心模式,並呼叫系統服務中的N他ReadFile
函式。- 系統服務函式N他
ReadFile
建立IRP_MJ_WRITE
型別的IRP
,然後將這個IRP
函式傳送到對應驅動程式的派遣函式中。 - 在對應的派遣函式中一般會通過
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
值為傳送的位元組數。
相關文章
- "萬字" Java I/O 詳解Java
- ElasticSearch:Request cannot be executed; I/O reactor status: STOPPEDElasticsearchReact
- 五種網路I/O模型詳解模型
- Linux shell I/O重定向詳解(zt)Linux
- 一起看 I/O | Flutter 3 更新詳解Flutter
- Java 程式設計要點之 I/O 流詳解Java程式設計
- 詳解Go語言I/O多路複用netpoller模型Go模型
- Linux系統的Shell I/O重定向詳解(轉)Linux
- Java訪問Elasticsearch報錯Request cannot be executed; I/O reactor status: STOPPEDJavaElasticsearchReact
- Veritas Quick I/O and Cached Quick I/OUI
- package.json詳解PackageJSON
- package.json 詳解PackageJSON
- golang package time 用法詳解GolangPackage
- puppet package資源詳解Package
- 網路I/O模型 解讀模型
- 計算機I/O與I/O模型計算機模型
- I/O埠和I/O記憶體記憶體
- Jmeter JDBC Request 使用詳解JMeterJDBC
- mmap共享儲存對映(儲存I/O對映)系列詳解
- Using UTL_FILE Package To Perform File I/O (UNIX) And Basic FAQ_44307.1PackageORM
- Java I/OJava
- 12張圖詳解O2O模式模式
- Jmeter系列(30)- 詳解 JDBC RequestJMeterJDBC
- Jmeter系列(21)- 詳解 HTTP RequestJMeterHTTP
- Cypress系列(68)- request() 命令詳解
- Java(8)I/OJava
- 【java】I/O流Java
- Java I/O流Java
- 檔案I/O
- I/O基礎
- java的I/OJava
- c++ I/OC++
- elasticsearch Request Body 與 Query DSL詳解Elasticsearch
- Python教程:精簡概述I/O模型與I/O操作Python模型
- Direct I/O (DIO) and Concurrent I/O (CIO) on AIX 5LAI
- goldengate extract abended unable to queue I/O, I/O beyond file sizeGo
- npm package.json屬性詳解NPMPackageJSON
- WARNING:Could not increase the asynch I/O limit to 164 for SQL direct I/OMITSQL