windows驱动架构设计
Overview of Windows Components
Design Goals for Kernel-Mode Drivers
Object-Based
Packet-Driven I/O with Reusable IRPs
Overview of the Windows I/O Model
End-User I/O Requests and File Objects
Example I/O Request - An Overview
Example I/O Request - The Details
IRP Major Function Codes
IRP_MJ_READ
Input Parameters
Output Parameters
IRP_MJ_WRITE
Input Parameters
Output Parameters
IRP_MJ_DEVICE_CONTROL
Input Parameters
Output Parameters
IRP structure
IRP_MJ_READ
IRP_MJ_WRITE
IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL
SystemBuffer.IRP_MJ_READ
SystemBuffer.IRP_MJ_WRITE
SystemBuffer.IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL
MDL structure
IO_STACK_LOCATION structure
1
目的:介绍内核驱动的一般性概念和编程的技术
Reference:
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/
https://learn.microsoft.com/en-us/windows-hardware/drivers/gettingstarted/
https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/ns-wdm-_irp
https://learn.microsoft.com/en-us/windows-hardware/drivers/kernel/sample-kernel-mode-drivers
Overview of Windows Components
The following figure shows the major internal components of the Windows operating system.
2
Design Goals for Kernel-Mode Drivers
● Portable from one platform to another.
● Configurable to various hardware and software platforms.
3
● Always preemptible and always interruptible.
● Multiprocessor-safe on multiprocessor platforms.
● Object-based.
● Packet-driven I/O with reusable IRPs.
● Capable of supporting asynchronous I/O.
Object-Based
基于NT的windows操作系统都是基于对象的。不同的组件定义一个或者多个对象且每个组件会导出一组方法去
操作该对象,任何一个组件都不能直接获取另一个组件的对象,要想使用另一个组件的对象,就必须使用对应的
方法。这种设计使得操作系统更加灵活和可移植。
同样的,驱动也是基于对象的,例如:
file objects:代表用户态程序到一个设备的连接
device objects:代表驱动逻辑、虚拟或者物理的设备
driver objects:代表驱动加载的镜像
I/O mgr定义了file objects、device objects、driver objects的struct和interface。
导出的方法名称格式如下:
PrefixOperationObject
Prefix标识了组件名称
Operation标识了做了什么操作
Object标识了对象的类型
例如,I/O mgr组件的IoCreateDevice用来创建一个设备。
Packet-Driven I/O with Reusable IRPs
4
I/O mgr,plug/play mgr,power mgr使用I/O request packets(IRPs)与内核和其他组件通信。
I/O mgr实施如下操作:
● 接受来自用户态程序的I/O请求
● 为I/O请求创建IRP
● 路由IRP到合适的驱动
● 跟踪IRP直到完成
● 返回I/O操作的状态
一个IRP可能路由到多个驱动模块。例如,打开磁盘上一个文件的请求,先到文件系统驱动,然后到磁盘驱动,
最后到总线驱动。这一组驱动叫做“driver stack”。
当驱动处理IRP时,它可以获取保存在IRP中的stack位置,因此可以reuse IRP向下转发。
Overview of the Windows I/O Model
每一个操作系统都有一个明确的I/O模型,用来处理跟外部设备交互的数据流。windows的I/O模型一个鲜明特点
是支持异步I/O,除此之外,还有如下特点:
● I/O mgr对所有的内核驱动呈现一致的接口,包括最底层驱动、中间层驱动和文件系统驱动。所有发向驱动
的I/O请求都被看做是IRPs。
● I/O操作是分层的。I/O mgr提供一个I/O的系统服务,用户态的保护模式子系统可以通过调用系统服务来操
作I/O,来服务应用或者终端用户。I/O mgr拦截这些调用,建立并路由IRPs到可能的中间层驱动,并最终
到达物理设备。
● I/O mgr定义了一组标准接口,包括一些必选的和可选的。所有的驱动实现一个对外一致的I/O模型,屏蔽
了外部设备的不同。
● 驱动是基于对象的,如同操作系统一样。驱动、设备和系统硬件都被看做对象。I/O mgr和其他操作系统组
件通过导出一组方法并让其他驱动调用来操作相关对象的方式来完成相关功能。
5
End-User I/O Requests and File Objects
对于终端用户来说,windows通过一个子系统把内核驱动隐藏起来,该子系统实现了一套熟悉的编程接口,像
Windows或者POSIX。设备和子系统,对用户态代码来说,都被看做命名的文件对象,由I/O mgr管理。
下图说明了终端用户、子系统和I/O mgr之间的关系。
Example I/O Request - An Overview
下图展示了子系统打开一个代表数据文件的文件对象时的流程。
6
1. The subsystem calls an I/O system service to open a named file.
2. The I/O manager calls the object manager to look up the named file and to help it resolve any
symbolic links for the file object. It also calls the security reference monitor to check that the
subsystem has the correct access rights to open that file object.
3. If the volume is not yet mounted, the I/O manager suspends the open request temporarily and calls
one or more file systems until one of them recognizes the file object as something it has stored on
one of the mass-storage devices the file system uses. When the file system has mounted the
volume, the I/O manager resumes the request.
4. The I/O manager allocates memory for and initializes an IRP for the open request. To drivers, an
7
open is equivalent to a "create" request.
5. The I/O manager calls the file system driver, passing it the IRP. The file system driver accesses its
I/O stack location in the IRP to determine what operation it must carry out, checks parameters,
determines if the requested file is in cache, and, if not, sets up the next-lower driver's I/O stack
location in the IRP.
6. Both drivers process the IRP and complete the requested I/O operation, calling kernel-mode
support routines supplied by the I/O manager and by other system components (not shown in the
previous figure).
7. The drivers return the IRP to the I/O manager with the I/O status block set in the IRP to indicate
whether the requested operation succeeded or why it failed.
8. The I/O manager gets the I/O status from the IRP, so it can return status information through the
protected subsystem to the original caller.
9. The I/O manager frees the completed IRP.
10. The I/O manager returns a handle for the file object to the subsystem if the open operation was
successful. If there was an error, it returns appropriate status to the subsystem.
After a subsystem successfully opens a file object that represents a data file, a device, or a volume, the
subsystem uses the returned handle to identify the file object in subsequent requests for device I/O
operations (usually read, write, or device I/O control requests). To make such a request, the subsystem
calls I/O system services. The I/O manager routes these requests as IRPs sent to appropriate drivers.
Example I/O Request - The Details
The following figure illustrates in more detail how the drivers in the Opening a File Object figure use I/O
support routines (IoXxx routines) to process the IRP for a read or write request.
8
1. The I/O manager calls the file system driver (FSD) with the IRP it has allocated for the subsystem's
read/write request. The FSD accesses its I/O stack location in the IRP to determine what operation
it should carry out.
2. The FSD can break the original request into smaller requests (possibly for more than one device
driver) by calling an I/O support routine (IoAllocateIrp) one or more times to allocate additional IRPs.
The additional IRPs are returned to the FSD with zero-filled I/O stack location(s) for lower-level
driver(s). At its discretion, the FSD can reuse the original IRP, rather than allocating additional IRPs
as shown in the previous figure, by setting up the next-lower driver's I/O stack location in the
original IRP and passing it on to lower drivers.
3. For each driver-allocated IRP, the FSD in the previous figure calls an I/O support routine to register
an FSD-supplied completion routine; in the completion routine, the FSD can determine whether
9
lower drivers satisfied the request and can free each driver-allocated IRP when lower drivers have
completed it. The I/O manager will call the FSD-supplied completion routine whether each driver-
allocated IRP was completed successfully, completed with an error status, or canceled. A higher-
level driver is responsible for freeing any IRPs it allocates and sets up on its own behalf for lower-
level drivers. The I/O manager frees the IRPs that it allocates after all drivers have completed
them.Next, the FSD calls an I/O support routine (IoGetNextIrpStackLocation) to access the next-
lower-level driver's I/O stack location in order to set up the request for the next-lower driver. (In
the previous figure, the next lower driver happens to be the lowest-level driver.) The FSD then calls
an I/O support routine (IoCallDriver) to pass that IRP on to the next-lower driver.
4. When it is called with the IRP, the lowest-level driver checks its I/O stack location to determine
what operation (indicated by the IRP_MJ_XXX function code) it should carry out on the target
device. The target device is represented by the device object in its designated I/O stack location
and is passed with the IRP to the driver. The lowest-level driver can assume that the I/O manager
has routed the IRP to an entry point that the driver defined for the IRP_MJ_XXX operation (here
IRP_MJ_READ or IRP_MJ_WRITE) and that the higher-level driver has checked the validity of other
parameters for the request.If there were no higher-level driver, the lowest-level driver would check
whether the input parameters for an IRP_MJ_XXX operation are valid. If they are, the driver usually
calls I/O support routines to tell the I/O manager that a device operation is pending on the IRP and
to either queue the IRP or pass it on to another driver-supplied routine that accesses the target
device (here, a physical or logical device: the disk or a partition on the disk).
5. The I/O manager determines whether the driver is already busy processing another IRP for the
target device, queues the IRP if it is, and returns. Otherwise, the I/O manager routes the IRP to a
driver-supplied routine that starts the I/O operation on its device. (At this stage, both drivers in the
previous figure and the I/O manager return control.)
6. When the device interrupts, the driver's interrupt service routine (ISR) does only as much work as it
must to stop the device from interrupting and to save necessary context about the operation. The
ISR then calls an I/O support routine (IoRequestDpc) with the IRP to queue a driver-supplied DPC
10
(Deferred Procedure Call) routine to complete the requested operation at a lower hardware priority
than the ISR.
7. When the driver's DPC gets control, it uses the context (passed in the ISR's call to IoRequestDpc) to
complete the I/O operation. The DPC calls a support routine to dequeue the next IRP (if any) and to
pass that IRP on to the driver-supplied routine that starts I/O operations on the device (see Step
5). The DPC then sets status about the just-completed operation in the IRP's I/O status block and
returns it to the I/O manager with IoCompleteRequest.
8. The I/O manager zeros the lowest-level driver's I/O stack location in the IRP and calls the file
system's registered completion routine (see Step 3) with the FSD-allocated IRP. This completion
routine checks the I/O status block to determine whether to retry the request or to update any
internal state maintained about the original request and to free its driver-allocated IRP. The file
system can collect status information for all driver-allocated IRPs it sends to lower-level drivers so
that it can set I/O status and complete the original IRP. When the file system has completed the
original IRP, the I/O manager returns and NTSTATUS value to the original requester (the
subsystem's native function) of the I/O operation.
IRP Major Function Codes
Each driver-specific I/O stack location (IO_STACK_LOCATION) for every IRP contains a major function
code (IRP_MJ_XXX), which tells the driver what operation it or the underlying device driver should carry
out to satisfy the I/O request. Each kernel-mode driver must provide dispatch routines for the major
function codes that it must support.
The specific operations a driver carries out for a given IRP_MJ_XXX code depend somewhat on the
underlying device, particularly for IRP_MJ_DEVICE_CONTROL and
IRP_MJ_INTERNAL_DEVICE_CONTROL requests. For example, the requests sent to a keyboard driver
are necessarily somewhat different from those sent to a disk driver. However, the I/O manager defines
the parameters and I/O stack location contents for each system-defined major function code.
Every higher-level driver must set up the appropriate I/O stack location in IRPs for the next-lower-level
driver and call IoCallDriver, either with each input IRP, or with a driver-created IRP (if the higher-level
driver holds on to the input IRP). Consequently, every intermediate driver must supply a dispatch routine
for each major function code that the underlying device driver handles. Otherwise, a new intermediate
11
driver will "break the chain" whenever an application or still higher-level driver attempts to send an I/O
request down to the underlying device driver.
File system drivers and legacy file system filter drivers also handle a required subset of system-defined
IRP_MJ_XXX function codes, some with subordinate IRP_MN_XXX function codes. For more information
on how to handle these IRPs, see IRP major function codes for file system drivers and legacy FS filter
drivers.
Drivers handle IRPs set with some or all of the following major function codes:
IRP_MJ_READ
Every device driver that transfers data from its device to the system must handle read requests in a
DispatchRead or DispatchReadWrite routine, as must any higher-level driver layered over such a device
driver.
12
Input Parameters
The driver's I/O stack location in the IRP indicates how many bytes to transfer at
Parameters.Read.Length.
Some drivers use the value at Parameters.Read.Key to sort incoming read requests into a driver-
determined order in the device queue or in a driver-managed internal queue of IRPs.
Certain types of drivers also use the value at Parameters.Read.ByteOffset, which indicates the starting
offset for the transfer operation. For example, see the IRP_MJ_READ topic in the Installable File System
(IFS) documentation.
Output Parameters
Depending on whether the underlying device driver sets up the target device object's Flags with
DO_BUFFERED_IO or with DO_DIRECT_IO, data is transferred into one of the following:
● The buffer at Irp->AssociatedIrp.SystemBuffer if the driver uses buffered I/O.
● The buffer described by the MDL at Irp->MdlAddress if the underlying device driver uses direct I/O
(DMA or PIO).
IRP_MJ_WRITE
Every device driver that transfers data from its device to the system must handle read requests in a
DispatchRead or DispatchReadWrite routine, as must any higher-level driver layered over such a device
driver.
Input Parameters
The driver's I/O stack location in the IRP indicates how many bytes to transfer at
Parameters.Write.Length.
Some drivers use the value at Parameters.Write.Key to sort incoming write requests into a driver-
determined order in the device queue or in a driver-managed internal queue of IRPs.
Certain types of drivers also use the value at Parameters.Write.ByteOffset, which indicates the starting
offset for the transfer operation. For example, see the IRP_MJ_WRITE topic in the Installable File
System (IFS) documentation.
Depending on whether the underlying device driver sets up the target device object's Flags with
DO_BUFFERED_IO or with DO_DIRECT_IO, data is transferred from one of the following:
13
● The buffer at Irp->AssociatedIrp.SystemBuffer, if the driver uses buffered I/O
● The buffer described by the MDL at Irp->MdlAddress, if the underlying device driver uses direct I/O
(DMA or PIO)
Output Parameters
None
IRP_MJ_DEVICE_CONTROL
Input Parameters
The I/O control code is contained at Parameters.DeviceIoControl.IoControlCode in the driver's I/O
stack location of the IRP.
Other input parameters depend on the I/O control code's value. For more information, see Buffer
Descriptions for I/O Control Codes.
Output Parameters
Output parameters depend on the I/O control code's value. For more information, see Buffer
Descriptions for I/O Control Codes.
14
15
16
17
18
An I/O control code is a 32-bit value that consists of several fields. The following figure illustrates the
layout of I/O control codes.
#define IOCTL_Device_Function CTL_CODE(DeviceType, Function, Method, Access)
19
20
深入分析v5的来源,过程如下:
v5来自v2+24,v2来自a2+184,a2是AfdDispatchDeviceControl的第二个参数;
AfdDispatchDeviceControl是IRP_MJ_DEVICE_CONTROL的入口,由上图SioctlDeviceControl样例代码可
知,该函数的第二个参数是一个指向IRP的指针。
去内核中找到一个IRP实例,如下图:
拿/FileSystem/Ntfs举例,如下图:
21
十进制184换算成十六进制为B8,这里最后一个变量的偏移为0x78,需要确认一下B8的偏移是否超出IRP结构
体,于是计算一下IRP结构体的大小,如下图:
0xd0小于0xB8,所以需要继续分析Tail,如下图:
可以看出Tail中是一个联合体,各自看一下,如下图:
22
这次我们关注0xb8-0x78=0x40偏移位置的变量,由v5 = (*(_DWORD *)(v2 + 24) >> 2) & 0x3FF可以得出,
0x40位置应该是一个结构体指针,可以推断Tail变量中我们取overlay.CurrentStackLocation作为v2的值,考察
一下v2,如下图:
可以看出v2+24的位置位于Parameters中,考察一下Parameters,如下图:
23
可以看出,Parameters是个枚举变量,由于AfdDispatchDeviceControl是IRP_MJ_DEVICE_CONTROL例程的
入口,所以我们考察DeviceIoControl,如下图:
24=0x8+0x10,所以可以看出,v2+24的值为IoControlCode,所以重写部分IDA中的代码,如下:
__int64 __fastcall AfdDispatchDeviceControl(PDEVICE_OBJECT a1, PIRP Irp)
{
__int64 StackLocation; // rbx
__int64 FunctionCode; // rax
__int64 (__fastcall *Function)(); // rax
unsigned int v8; // ebx
__int64 v9; // rdx
24
StackLocation = *(_QWORD *)(Irp->Tail->overlay.CurrentStackLocation);
if ( (unsigned __int8)NetioNrtIsTrackerDevice() )
{
v8 = NetioNrtDispatch(a1, a2);
*(_DWORD *)(a2 + 48) = v8;
IofCompleteRequest(a2, 0i64);
return v8;
}
else
{
FunctionCode = (*(_DWORD *)(StackLocation->Parameters.DeviceIoControl.IoControlCode) >> 2) &
0x3FF;
if ( (unsigned int)FunctionCode < sizeof(AfdIoctlTable)/sizeof(AfdIoctlTable[0]) &&
AfdIoctlTable[FunctionCode] == *(_DWORD *)(StackLocation-
>Parameters.DeviceIoControl.IoControlCode) &&
(*(_BYTE *)(v2->MinorFunction) = *(_DWORD *)(v2->Parameters.DeviceIoControl.IoControlCode) >> 2,
(Function = AfdIrpCallDispatch[FunctionCode]) != 0i64) )
{
return Function(Irp, StackLocation);
}
else
{
if ( (byte_1C005942E & 0x10) != 0 )
WPP_SF_D(11i64, &WPP_750cd5b025b73ac1a6ce4c47647b8469_Traceguids);
v9 = (unsigned __int8)AfdPriorityBoost;
*(_DWORD *)(a2 + 48) = -1073741808;
IofCompleteRequest(a2, v9);
return 3221225488i64;
}
}
25
}
IRP structure
26
The IRP structure is a partially opaque structure that represents an I/O request packet. Drivers can use
the following members of the IRP structure.
typedef struct _IRP {
CSHORT Type;
USHORT Size;
PMDL MdlAddress;
ULONG Flags;
union {
struct _IRP *MasterIrp;
__volatile LONG IrpCount;
PVOID SystemBuffer;
} AssociatedIrp;
LIST_ENTRY ThreadListEntry;
IO_STATUS_BLOCK IoStatus;
KPROCESSOR_MODE RequestorMode;
BOOLEAN PendingReturned;
CHAR StackCount;
CHAR CurrentLocation;
BOOLEAN Cancel;
KIRQL CancelIrql;
CCHAR ApcEnvironment;
UCHAR AllocationFlags;
union {
PIO_STATUS_BLOCK UserIosb;
PVOID IoRingContext;
};
PKEVENT UserEvent;
union {
struct {
union {
27
PIO_APC_ROUTINE UserApcRoutine;
PVOID IssuingProcess;
};
union {
PVOID UserApcContext;
#if ...
_IORING_OBJECT *IoRing;
#else
struct _IORING_OBJECT *IoRing;
#endif
};
} AsynchronousParameters;
LARGE_INTEGER AllocationSize;
} Overlay;
__volatile PDRIVER_CANCEL CancelRoutine;
PVOID UserBuffer;
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;
28
ULONG PacketType;
};
};
PFILE_OBJECT OriginalFileObject;
} Overlay;
KAPC Apc;
PVOID CompletionKey;
} Tail;
} IRP;
MdlAddress
Pointer to an MDL describing a user buffer, if the driver is using direct I/O, and the IRP major function
code is one of the following:
IRP_MJ_READ
The MDL describes an empty buffer that the device or driver fills in.
IRP_MJ_WRITE
The MDL describes a buffer that contains data for the device or driver.
IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL
If the IOCTL code specifies the METHOD_IN_DIRECT transfer type, the MDL describes a buffer that
contains data for the device or driver.
If the IOCTL code specifies the METHOD_OUT_DIRECT transfer type, the MDL describes an empty
buffer that the device or driver fills in.
For more information about the buffers that are associated with METHOD_IN_DIRECT and
METHOD_OUT_DIRECT transfer types in IOCTL codes, see Buffer Descriptions for I/O Control Codes.
If the driver is not using direct I/O, this pointer is NULL.
AssociatedIrp.SystemBuffer
Pointer to a system-space buffer.
If the driver is using buffered I/O, the buffer's purpose is determined by the IRP major function code, as
follows:
SystemBuffer.IRP_MJ_READ
29
The buffer receives data from the device or driver. The buffer's length is specified by
Parameters.Read.Length in the driver's IO_STACK_LOCATION structure.
SystemBuffer.IRP_MJ_WRITE
The buffer supplies data for the device or driver. The buffer's length is specified by
Parameters.Write.Length in the driver's IO_STACK_LOCATION structure.
NULL.
SystemBuffer.IRP_MJ_DEVICE_CONTROL or IRP_MJ_INTERNAL_DEVICE_CONTROL
The buffer represents both the input and output buffers that are supplied to DeviceIoControl and
IoBuildDeviceIoControlRequest. Output data overwrites input data.
For input, the buffer's length is specified by Parameters.DeviceIoControl.InputBufferLength in the
driver's IO_STACK_LOCATION structure.
For output, the buffer's length is specified by Parameters.DeviceIoControl.OutputBufferLength in the
driver's IO_STACK_LOCATION structure.
For more information, see Buffer Descriptions for I/O Control Codes.
The buffer represents the input buffer that is supplied to DeviceIoControl and
IoBuildDeviceIoControlRequest.
The buffer's length is specified by Parameters.DeviceIoControl.InputBufferLength in the driver's
IO_STACK_LOCATION structure.
MDL structure
An MDL structure is a partially opaque structure that represents a memory descriptor list (MDL).
typedef struct _MDL {
struct _MDL *Next;
CSHORT Size;
CSHORT MdlFlags;
struct _EPROCESS *Process;
PVOID MappedSystemVa;
PVOID StartVa;
ULONG ByteCount;
ULONG ByteOffset;
30
} MDL, *PMDL;
IO_STACK_LOCATION structure
The IO_STACK_LOCATION structure defines an I/O stack location, which is an entry in the I/O stack
that is associated with each IRP. Each I/O stack location in an IRP has some common members and
some request-type-specific members.
typedef struct _IO_STACK_LOCATION {
UCHAR MajorFunction;
UCHAR MinorFunction;
UCHAR Flags;
UCHAR Control;
union {
struct {
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT POINTER_ALIGNMENT FileAttributes;
USHORT ShareAccess;
ULONG POINTER_ALIGNMENT EaLength;
} Create;
struct {
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT POINTER_ALIGNMENT Reserved;
USHORT ShareAccess;
PNAMED_PIPE_CREATE_PARAMETERS Parameters;
} CreatePipe;
struct {
PIO_SECURITY_CONTEXT SecurityContext;
ULONG Options;
USHORT POINTER_ALIGNMENT Reserved;
31
USHORT ShareAccess;
PMAILSLOT_CREATE_PARAMETERS Parameters;
} CreateMailslot;
struct {
ULONG Length;
ULONG POINTER_ALIGNMENT Key;
ULONG Flags;
LARGE_INTEGER ByteOffset;
} Read;
struct {
ULONG Length;
ULONG POINTER_ALIGNMENT Key;
ULONG Flags;
LARGE_INTEGER ByteOffset;
} Write;
struct {
ULONG Length;
PUNICODE_STRING FileName;
FILE_INFORMATION_CLASS FileInformationClass;
ULONG POINTER_ALIGNMENT FileIndex;
} QueryDirectory;
struct {
ULONG Length;
ULONG POINTER_ALIGNMENT CompletionFilter;
} NotifyDirectory;
struct {
ULONG Length;
ULONG POINTER_ALIGNMENT CompletionFilter;
DIRECTORY_NOTIFY_INFORMATION_CLASS POINTER_ALIGNMENT
DirectoryNotifyInformationClass;
} NotifyDirectoryEx;
32
struct {
ULONG Length;
FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;
} QueryFile;
struct {
ULONG Length;
FILE_INFORMATION_CLASS POINTER_ALIGNMENT FileInformationClass;
PFILE_OBJECT FileObject;
union {
struct {
BOOLEAN ReplaceIfExists;
BOOLEAN AdvanceOnly;
};
ULONG ClusterCount;
HANDLE DeleteHandle;
};
} SetFile;
struct {
ULONG Length;
PVOID EaList;
ULONG EaListLength;
ULONG POINTER_ALIGNMENT EaIndex;
} QueryEa;
struct {
ULONG Length;
} SetEa;
struct {
ULONG Length;
FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;
} QueryVolume;
33
struct {
ULONG Length;
FS_INFORMATION_CLASS POINTER_ALIGNMENT FsInformationClass;
} SetVolume;
struct {
ULONG OutputBufferLength;
ULONG POINTER_ALIGNMENT InputBufferLength;
ULONG POINTER_ALIGNMENT FsControlCode;
PVOID Type3InputBuffer;
} FileSystemControl;
struct {
PLARGE_INTEGER Length;
ULONG POINTER_ALIGNMENT Key;
LARGE_INTEGER ByteOffset;
} LockControl;
struct {
ULONG OutputBufferLength;
ULONG POINTER_ALIGNMENT InputBufferLength;
ULONG POINTER_ALIGNMENT IoControlCode;
PVOID Type3InputBuffer;
} DeviceIoControl;
struct {
SECURITY_INFORMATION SecurityInformation;
ULONG POINTER_ALIGNMENT Length;
} QuerySecurity;
struct {
SECURITY_INFORMATION SecurityInformation;
PSECURITY_DESCRIPTOR SecurityDescriptor;
} SetSecurity;
struct {
34
PVPB Vpb;
PDEVICE_OBJECT DeviceObject;
ULONG OutputBufferLength;
} MountVolume;
struct {
PVPB Vpb;
PDEVICE_OBJECT DeviceObject;
} VerifyVolume;
struct {
struct _SCSI_REQUEST_BLOCK *Srb;
} Scsi;
struct {
ULONG Length;
PSID StartSid;
PFILE_GET_QUOTA_INFORMATION SidList;
ULONG SidListLength;
} QueryQuota;
struct {
ULONG Length;
} SetQuota;
struct {
DEVICE_RELATION_TYPE Type;
} QueryDeviceRelations;
struct {
const GUID *InterfaceType;
USHORT Size;
USHORT Version;
PINTERFACE Interface;
PVOID InterfaceSpecificData;
} QueryInterface;
35
struct {
PDEVICE_CAPABILITIES Capabilities;
} DeviceCapabilities;
struct {
PIO_RESOURCE_REQUIREMENTS_LIST IoResourceRequirementList;
} FilterResourceRequirements;
struct {
ULONG WhichSpace;
PVOID Buffer;
ULONG Offset;
ULONG POINTER_ALIGNMENT Length;
} ReadWriteConfig;
struct {
BOOLEAN Lock;
} SetLock;
struct {
BUS_QUERY_ID_TYPE IdType;
} QueryId;
struct {
DEVICE_TEXT_TYPE DeviceTextType;
LCID POINTER_ALIGNMENT LocaleId;
} QueryDeviceText;
struct {
BOOLEAN InPath;
BOOLEAN Reserved[3];
DEVICE_USAGE_NOTIFICATION_TYPE POINTER_ALIGNMENT Type;
} UsageNotification;
struct {
SYSTEM_POWER_STATE PowerState;
} WaitWake;
36
struct {
PPOWER_SEQUENCE PowerSequence;
} PowerSequence;
#if ...
struct {
union {
ULONG SystemContext;
SYSTEM_POWER_STATE_CONTEXT SystemPowerStateContext;
};
POWER_STATE_TYPE POINTER_ALIGNMENT Type;
POWER_STATE POINTER_ALIGNMENT State;
POWER_ACTION POINTER_ALIGNMENT ShutdownType;
} Power;
#else
struct {
ULONG SystemContext;
POWER_STATE_TYPE POINTER_ALIGNMENT Type;
POWER_STATE POINTER_ALIGNMENT State;
POWER_ACTION POINTER_ALIGNMENT ShutdownType;
} Power;
#endif
struct {
PCM_RESOURCE_LIST AllocatedResources;
PCM_RESOURCE_LIST AllocatedResourcesTranslated;
} StartDevice;
struct {
ULONG_PTR ProviderId;
PVOID DataPath;
ULONG BufferSize;
PVOID Buffer;
37
} WMI;
struct {
PVOID Argument1;
PVOID Argument2;
PVOID Argument3;
PVOID Argument4;
} Others;
} Parameters;
PDEVICE_OBJECT DeviceObject;
PFILE_OBJECT FileObject;
PIO_COMPLETION_ROUTINE CompletionRoutine;
PVOID Context;
} IO_STACK_LOCATION, *PIO_STACK_LOCATION;
38