驅動對象,設備對象,IRP之間的關系?
- 類似于程序,窗口,消息三者之間的關系;
- 每個驅動程序只有一個驅動對象(程序實例句柄),一個驅動對象對應若干個(大于等于1個)設備對象(窗口),每個設備對象可以處理不同的IRP(I/O請求包,I/O Request Package)
IRP棧:
IRP其實本質上是由IRP頭部和IRP棧組成,一般所說的IRP只是"I/O請求包"IRP的頭部,在IRP數據結構的后面還有一個IO_STACK_LOCATION結構體數組
typedef struct _IO_STACK_LOCATION {<br />
UCHAR MajorFunction;<br />
UCHAR MinorFunction;<br />
UCHAR Flags;<br />
UCHAR Control;<br />
//<br />
// The following user parameters are based on the service that is being<br />
// invoked. Drivers and file systems can determine which set to use based<br />
// on the above major and minor function codes.<br />
//<br />
union {<br />
//<br />
// System service parameters for: NtCreateFile<br />
//<br />
struct {<br />
PIO_SECURITY_CONTEXT SecurityContext;<br />
ULONG Options;<br />
USHORT POINTER_ALIGNMENT FileAttributes;<br />
USHORT ShareAccess;<br />
ULONG POINTER_ALIGNMENT EaLength;<br />
} Create;</p>
<p> //<br />
// System service parameters for: NtReadFile<br />
//<br />
struct {<br />
ULONG Length;<br />
ULONG POINTER_ALIGNMENT Key;<br />
LARGE_INTEGER ByteOffset;<br />
} Read;<br />
//<br />
// System service parameters for: NtWriteFile<br />
//<br />
struct {<br />
ULONG Length;<br />
ULONG POINTER_ALIGNMENT Key;<br />
LARGE_INTEGER ByteOffset;<br />
} Write;</p>
<p> //<br />
// System service parameters for: NtQueryInformationFile<br />
//<br />
struct {<br />
ULONG Length;<br />
FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;<br />
} QueryFile;<br />
//<br />
// System service parameters for: NtSetInformationFile<br />
//<br />
struct {<br />
ULONG Length;<br />
FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;<br />
PFILE_OBJECT FileObject;<br />
union {<br />
struct {<br />
BOOLEAN ReplaceIfExists;<br />
BOOLEAN AdvanceOnly;<br />
};<br />
ULONG ClusterCount;<br />
HANDLE DeleteHandle;<br />
};<br />
} SetFile;</p>
<p> //<br />
// System service parameters for: NtQueryVolumeInformationFile<br />
//<br />
struct {<br />
ULONG Length;<br />
FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;<br />
} QueryVolume;</p>
<p> //<br />
// System service parameters for: NtFlushBuffersFile<br />
//<br />
// No extra user-supplied parameters.<br />
//</p>
<p> //<br />
// System service parameters for: NtDeviceIoControlFile<br />
//<br />
// Note that the user's output buffer is stored in the UserBuffer field<br />
// and the user's input buffer is stored in the SystemBuffer field.<br />
//<br />
struct {<br />
ULONG OutputBufferLength;<br />
ULONG POINTER_ALIGNMENT InputBufferLength;<br />
ULONG POINTER_ALIGNMENT IoControlCode;<br />
PVOID Type3InputBuffer;<br />
} DeviceIoControl;<br />
// end_wdm<br />
//<br />
// System service parameters for: NtQuerySecurityObject<br />
//<br />
struct {<br />
SECURITY_INFORMATION SecurityInformation;<br />
ULONG POINTER_ALIGNMENT Length;<br />
} QuerySecurity;<br />
//<br />
// System service parameters for: NtSetSecurityObject<br />
//<br />
struct {<br />
SECURITY_INFORMATION SecurityInformation;<br />
PSECURITY_DESCRIPTOR SecurityDescriptor;<br />
} SetSecurity;<br />
// begin_wdm<br />
//<br />
// Non-system service parameters.<br />
//<br />
// Parameters for MountVolume<br />
//<br />
struct {<br />
PVPB Vpb;<br />
PDEVICE_OBJECT DeviceObject;<br />
} MountVolume;<br />
//<br />
// Parameters for VerifyVolume<br />
//<br />
struct {<br />
PVPB Vpb;<br />
PDEVICE_OBJECT DeviceObject;<br />
} VerifyVolume;<br />
//<br />
// Parameters for Scsi with internal device contorl.<br />
//<br />
struct {<br />
struct _SCSI_REQUEST_BLOCK *Srb;<br />
} Scsi;</p>
<p> //<br />
// Parameters for IRP_MN_QUERY_DEVICE_RELATIONS<br />
//<br />
struct {<br />
DEVICE_RELATION_TYPE Type;<br />
} QueryDeviceRelations;<br />
//<br />
// Parameters for IRP_MN_QUERY_INTERFACE<br />
//<br />
struct {<br />
CONST GUID *InterfaceType;<br />
USHORT Size;<br />
USHORT Version;<br />
PINTERFACE Interface;<br />
PVOID InterfaceSpecificData;<br />
} QueryInterface;<br />
// end_ntifs<br />
//<br />
// Parameters for IRP_MN_QUERY_CAPABILITIES<br />
//<br />
struct {<br />
PDEVICE_CAPABILITIES Capabilities;<br />
} DeviceCapabilities;<br />
//<br />
// Parameters for IRP_MN_FILTER_RESOURCE_REQUIREMENTS<br />
//<br />
struct {<br />
PIO_RESOURCE_REQUIREMENTS_LIST IoResourceRequirementList;<br />
} FilterResourceRequirements;<br />
//<br />
// Parameters for IRP_MN_READ_CONFIG and IRP_MN_WRITE_CONFIG<br />
//<br />
struct {<br />
ULONG WhichSpace;<br />
PVOID Buffer;<br />
ULONG Offset;<br />
ULONG POINTER_ALIGNMENT Length;<br />
} ReadWriteConfig;<br />
//<br />
// Parameters for IRP_MN_SET_LOCK<br />
//<br />
struct {<br />
BOOLEAN Lock;<br />
} SetLock;<br />
//<br />
// Parameters for IRP_MN_QUERY_ID<br />
//<br />
struct {<br />
BUS_QUERY_ID_TYPE IdType;<br />
} QueryId;<br />
//<br />
// Parameters for IRP_MN_QUERY_DEVICE_TEXT<br />
//<br />
struct {<br />
DEVICE_TEXT_TYPE DeviceTextType;<br />
LCID POINTER_ALIGNMENT LocaleId;<br />
} QueryDeviceText;<br />
//<br />
// Parameters for IRP_MN_DEVICE_USAGE_NOTIFICATION<br />
//<br />
struct {<br />
BOOLEAN InPath;<br />
BOOLEAN Reserved[3];<br />
DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT Type;<br />
} UsageNotification;<br />
//<br />
// Parameters for IRP_MN_WAIT_WAKE<br />
//<br />
struct {<br />
SYSTEM_POWER_STATE PowerState;<br />
} WaitWake;<br />
//<br />
// Parameter for IRP_MN_POWER_SEQUENCE<br />
//<br />
struct {<br />
PPOWER_SEQUENCE PowerSequence;<br />
} PowerSequence;<br />
//<br />
// Parameters for IRP_MN_SET_POWER and IRP_MN_QUERY_POWER<br />
//<br />
struct {<br />
ULONG SystemContext;<br />
POWER_STATE_TYPE POINTER_ALIGNMENT Type;<br />
POWER_STATE POINTER_ALIGNMENT State;<br />
POWER_ACTION POINTER_ALIGNMENT ShutdownType;<br />
} Power;<br />
//<br />
// Parameters for StartDevice<br />
//<br />
struct {<br />
PCM_RESOURCE_LIST AllocatedResources;<br />
PCM_RESOURCE_LIST AllocatedResourcesTranslated;<br />
} StartDevice;<br />
// begin_ntifs<br />
//<br />
// Parameters for Cleanup<br />
//<br />
// No extra parameters supplied<br />
//<br />
//<br />
// WMI Irps<br />
//<br />
struct {<br />
ULONG_PTR ProviderId;<br />
PVOID DataPath;<br />
ULONG BufferSize;<br />
PVOID Buffer;<br />
} WMI;<br />
//<br />
// Others - driver-specific<br />
//<br />
struct {<br />
PVOID Argument1;<br />
PVOID Argument2;<br />
PVOID Argument3;<br />
PVOID Argument4;<br />
} Others;<br />
} Parameters;<br />
//<br />
// Save a pointer to this device driver's device object for this request<br />
// so it can be passed to the completion routine if needed.<br />
//<br />
PDEVICE_OBJECT DeviceObject;<br />
//<br />
// The following location contains a pointer to the file object for this<br />
//<br />
PFILE_OBJECT FileObject;<br />
//<br />
// The following routine is invoked depending on the flags in the above<br />
// flags field.<br />
//<br />
PIO_COMPLETION_ROUTINE CompletionRoutine;<br />
//<br />
// The following is used to store the address of the context parameter<br />
// that should be passed to the CompletionRoutine.<br />
//<br />
PVOID Context;<br />
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;
IRP會一層一層的傳遞,每一層都對應著一個IO_STACK_LOCATION
- 上面那個結構體,最為重要的是一個大聯合體,其中對應著不同類型IRP所攜帶的參數
請簡述IRP與IRP棧之間的關系
- 任何內核模式程序在創建一個IRP時,同時還創建了一個與之相關聯的IO_STACK_LOCATION結構數組;
- 數組中的每個堆棧單元都對應一個將處理該IRP的驅動程序,堆棧單元中包含該IRP類型代碼(1)和參數信息(2)以及完成函數的地址(3)
上面一句話的總結:每個堆棧單元都對應一個驅動程序;堆棧單元中IRP包含類型、參數信息、完成函數地址.
- IO_STACK_LOCATION內有兩個重要成員,他們分別是MajorFunction和MinorFunction,分別記錄了IRP的主類型與子類型,通過MajorFunction可以知道是什么IRP,通過MinorFunction可以知道一些子消息.
還有一個重要的聯合體,根據不同的IRP,它會傳遞不同的消息.
IRP的處理:
- 驅動中的請求處理都是通過I/O請求包(IRP)與派遣函數完成的
- 當我們在用戶層調用CreateFile,ReadFile,CloseHandle等系統API的時候,操作系統則會產生與之對應的IRP_MJ_CREATE,IRP_MJ_READ,IRP_MJ_CLOSE,并發送到相應的設備
-
Windows中的設備有:
image.png
MDL(內存描述表)
- 內存描述符表(Memory Descriptor List)是Windows未公開的一個結構,可以通過Windows提供的函數使用此結構將內存重新映射,并指定我們自己的內存屬性.
小結:MDL功能->將內存重新映射,并指定我們自己的內存屬性.
- 當需要對其他模塊的內存空間進行操作時,微軟可以確保MDL的讀寫操作不會引發其他問題
設備通訊有三種方式,哪三種,有什么區別?
- 緩沖區設備讀寫方式:將用戶態緩沖區拷貝至內核態,在內核態使用完畢之后會再拷貝至用戶態
- 直接讀取方式(MDL):對用戶態內存地址進程重新映射,映射到內核空間
- 其他方式:取決于創建完設備對象之后,映射到內核空間
常見的IRP結構體中的字段有哪些,以及他們的作用?
PMDL MdlAddress
:MDLAddress
域指向一個內存描述符(MDL),描述了一個與該IO請求相關聯的用戶模式緩沖區;AssociateIrp
:我們WDM驅動會用到AssociatedIrp.SystemBuffer
,這是一個指向系統空間的緩沖區.當使用直接IO的時候,,這個緩沖區的用途由與IRP相關的Majorfunction
決定;IRP_MJ_DEVICE_CONTROL
或者IRP_MJ_INTERNAL_DEVICE_CONTROL
這兩類IRP,該緩沖區被作為DeviceConTrol函數的輸入緩沖區;該緩沖區的長度由IO_STACK_LOCATION結構中的Paramters.DeviceIoControl.InputBufferLehgth成員確定.IOStatus(IO_STATUS_BLOCK)
:是一個僅包含兩個域的結構,驅動程序在最終完成請求的時候設置這個結構(這里沒有寫全。。。。。。)
目前學習了IO_STACK_LOCATION中的哪些字段,有什么作用?
MajorFunction:I/O操作的類型
MinorFunction:MajorFunction的附屬碼
Paramters:不同MajorFunction攜帶的附加信息.