漫谈IRP
阅读原文时间:2023年07月10日阅读:2

I/O Request Packet(IRP)

IRP概述:

IRP是由I/O管理器发出的,I/O管理器是用户态与内核态之间的桥梁,当用户态进程发出I/O请求时,I/O管理器就捕获这些请求,将其转换为IRP请求,发送给驱动程序。

I/O管理器无疑是非常重要的,具有核心地位。它负责所有I/O请求的调度和管理工作,根据请求的不同内容,选择相应的驱动程序对象,设备对象,并生成、发送、释放各种不同的IRP。

整个I/O处理流程是在它的指挥下完成的。

一个IRP是从非分页内存中分配的可变大小的结构,它包括两部分:IRP首部和I/O堆栈。

IRP首部中包含了指向IRP输入输出缓冲区指针、当前拥有IRP的驱动指针等。

紧接着首部的IO_STACK_LOCATION结构的数组。它的大小由设备栈中的设备数确定。IO_STACK_LOCATION结构中保存了一个I/O请求的参数及代码、请求当前对应的设备指针、完成函数指针(IoCompletion)等。

IRP结构介绍:

我们先看看WRK中对IRP的定义

1 typedef struct DECLSPEC_ALIGN(MEMORY_ALLOCATION_ALIGNMENT) _IRP {
2 CSHORT Type;
3 USHORT Size;
4
5 //
6 // Define the common fields used to control the IRP.
7 //
8
9 //
10 // Define a pointer to the Memory Descriptor List (MDL) for this I/O
11 // request. This field is only used if the I/O is "direct I/O".
12 //
13
14 PMDL MdlAddress;
15
16 //
17 // Flags word - used to remember various flags.
18 //
19
20 ULONG Flags;
21
22 //
23 // The following union is used for one of three purposes:
24 //
25 // 1. This IRP is an associated IRP. The field is a pointer to a master
26 // IRP.
27 //
28 // 2. This is the master IRP. The field is the count of the number of
29 // IRPs which must complete (associated IRPs) before the master can
30 // complete.
31 //
32 // 3. This operation is being buffered and the field is the address of
33 // the system space buffer.
34 //
35
36 union {
37 struct _IRP *MasterIrp;
38 __volatile LONG IrpCount;
39 PVOID SystemBuffer;
40 } AssociatedIrp;
41
42 //
43 // Thread list entry - allows queueing the IRP to the thread pending I/O
44 // request packet list.
45 //
46
47 LIST_ENTRY ThreadListEntry;
48
49 //
50 // I/O status - final status of operation.
51 //
52
53 IO_STATUS_BLOCK IoStatus;
54
55 //
56 // Requestor mode - mode of the original requestor of this operation.
57 //
58
59 KPROCESSOR_MODE RequestorMode;
60
61 //
62 // Pending returned - TRUE if pending was initially returned as the
63 // status for this packet.
64 //
65
66 BOOLEAN PendingReturned;
67
68 //
69 // Stack state information.
70 //
71
72 CHAR StackCount;
73 CHAR CurrentLocation;
74
75 //
76 // Cancel - packet has been canceled.
77 //
78
79 BOOLEAN Cancel;
80
81 //
82 // Cancel Irql - Irql at which the cancel spinlock was acquired.
83 //
84
85 KIRQL CancelIrql;
86
87 //
88 // ApcEnvironment - Used to save the APC environment at the time that the
89 // packet was initialized.
90 //
91
92 CCHAR ApcEnvironment;
93
94 //
95 // Allocation control flags.
96 //
97
98 UCHAR AllocationFlags;
99
100 //
101 // User parameters.
102 //
103
104 PIO_STATUS_BLOCK UserIosb;
105 PKEVENT UserEvent;
106 union {
107 struct {
108 union {
109 PIO_APC_ROUTINE UserApcRoutine;
110 PVOID IssuingProcess;
111 };
112 PVOID UserApcContext;
113 } AsynchronousParameters;
114 LARGE_INTEGER AllocationSize;
115 } Overlay;
116
117 //
118 // CancelRoutine - Used to contain the address of a cancel routine supplied
119 // by a device driver when the IRP is in a cancelable state.
120 //
121
122 __volatile PDRIVER_CANCEL CancelRoutine;
123
124 //
125 // Note that the UserBuffer parameter is outside of the stack so that I/O
126 // completion can copy data back into the user's address space without
127 // having to know exactly which service was being invoked. The length
128 // of the copy is stored in the second half of the I/O status block. If
129 // the UserBuffer field is NULL, then no copy is performed.
130 //
131
132 PVOID UserBuffer;
133
134 //
135 // Kernel structures
136 //
137 // The following section contains kernel structures which the IRP needs
138 // in order to place various work information in kernel controller system
139 // queues. Because the size and alignment cannot be controlled, they are
140 // placed here at the end so they just hang off and do not affect the
141 // alignment of other fields in the IRP.
142 //
143
144 union {
145
146 struct {
147
148 union {
149
150 //
151 // DeviceQueueEntry - The device queue entry field is used to
152 // queue the IRP to the device driver device queue.
153 //
154
155 KDEVICE_QUEUE_ENTRY DeviceQueueEntry;
156
157 struct {
158
159 //
160 // The following are available to the driver to use in
161 // whatever manner is desired, while the driver owns the
162 // packet.
163 //
164
165 PVOID DriverContext[4];
166
167 } ;
168
169 } ;
170
171 //
172 // Thread - pointer to caller's Thread Control Block.
173 //
174
175 PETHREAD Thread;
176
177 //
178 // Auxiliary buffer - pointer to any auxiliary buffer that is
179 // required to pass information to a driver that is not contained
180 // in a normal buffer.
181 //
182
183 PCHAR AuxiliaryBuffer;
184
185 //
186 // The following unnamed structure must be exactly identical
187 // to the unnamed structure used in the minipacket header used
188 // for completion queue entries.
189 //
190
191 struct {
192
193 //
194 // List entry - used to queue the packet to completion queue, among
195 // others.
196 //
197
198 LIST_ENTRY ListEntry;
199
200 union {
201
202 //
203 // Current stack location - contains a pointer to the current
204 // IO_STACK_LOCATION structure in the IRP stack. This field
205 // should never be directly accessed by drivers. They should
206 // use the standard functions.
207 //
208
209 struct _IO_STACK_LOCATION *CurrentStackLocation;
210
211 //
212 // Minipacket type.
213 //
214
215 ULONG PacketType;
216 };
217 };
218
219 //
220 // Original file object - pointer to the original file object
221 // that was used to open the file. This field is owned by the
222 // I/O system and should not be used by any other drivers.
223 //
224
225 PFILE_OBJECT OriginalFileObject;
226
227 } Overlay;
228
229 //
230 // APC - This APC control block is used for the special kernel APC as
231 // well as for the caller's APC, if one was specified in the original
232 // argument list. If so, then the APC is reused for the normal APC for
233 // whatever mode the caller was in and the "special" routine that is
234 // invoked before the APC gets control simply deallocates the IRP.
235 //
236
237 KAPC Apc;
238
239 //
240 // CompletionKey - This is the key that is used to distinguish
241 // individual I/O operations initiated on a single file handle.
242 //
243
244 PVOID CompletionKey;
245
246 } Tail;
247
248 } IRP;

结构图如下,其中灰色部分为不可见区域,这里主要讲解一下可见区域。

1.1 PMDL  MdlAddress : 设备执行直接I/O时,指向用户空间的内存描述表

1.2 ULONG Flags: 包含一些对驱动程序只读的标志。但这些标志与WDM驱动程序无关

1.3 AssociatedIrp.SystemBuffer : SystemBuffer指针指向一个数据缓冲区,该缓冲区位于内核模式的非分页内存中I/O管理器把用户模式程序发送给驱动程序的数据复制到这个缓冲区,这也是创建IRP过程的一部分。对于读请求,设备驱动程序把读出的数据填到这个缓冲区,然后I/O管理器再把缓冲区的内容复制到用户模式缓冲区。

1.4 IoStatus : 是一个结构体IO_STATUS_BLOCK, 这个结构体仅包含两个域,驱动程序在最终完成请求时设置这个结构。
IoStatus.Status : 将收到一个NTSTATUS代码。
IoStatus.Information 的类型为ULONG_PTR,它将收到一个信息值,该信息值的确切含义要取决于具体的IRP类型和请求完成的状态。Information域的一个公认用法是用于保存数据传输操作。某些PnP请求把这个域作为指向另外一个结构的指针,这个结构通常包含查询请求的结果。

1.5 RequestorMode将等于一个枚举常量UserModeKernelMode,指定原始I/O请求的来源。驱动程序有时需要查看这个值来决定是否要信任某些参数。

1.6 PendingReturned(BOOLEAN)如果为TRUE,则表明处理该IRP的最低级派遣例程返回了STATUS_PENDING。完成例程通过参考该域来避免自己与派遣例程间的潜在竞争。

1.7 Cancel(BOOLEAN)如果为TRUE,则表明IoCancelIrp已被调用,该函数用于取消这个请求。如果为FALSE,则表明没有调用IoCancelIrp函数。取消IRP是一个相对复杂的主题,我将在本章的最后详细描述它。

1.8 CancelIrql(KIRQL)是一个IRQL值,表明那个专用的取消自旋锁是在这个IRQL上获取的。当你在取消例程中释放自旋锁时应参考这个域。

1.9 CancelRoutine(PDRIVER_CANCEL)是驱动程序取消例程的地址。你应该使用IoSetCancelRoutine函数设置这个域而不是直接修改该域。

2.0 UserBuffer(PVOID) 对于METHOD_NEITHER方式的IRP_MJ_DEVICE_CONTROL请求,该域包含输出缓冲区的用户模式虚拟地址。该域还用于保存读写请求缓冲区的用户模式虚拟地址,但指定了DO_BUFFERED_IO或DO_DIRECT_IO标志的驱动程序,其读写例程通常不需要访问这个域。当处理一个METHOD_NEITHER控制操作时,驱动程序能用这个地址创建自己的MDL。

PIO_STACK_LOCATION结构介绍:

我们再来看看WRK中对PIO_STACK_LOCATION结构的定义

typedef struct _IO_STACK_LOCATION {
UCHAR MajorFunction;
UCHAR MinorFunction;
UCHAR Flags;
UCHAR Control;

//  
// The following user parameters are based on the service that is being  
// invoked.  Drivers and file systems can determine which set to use based  
// on the above major and minor function codes.  
//

union {

    //  
    // System service parameters for:  NtCreateFile  
    //

    struct {  
        PIO\_SECURITY\_CONTEXT SecurityContext;  
        ULONG Options;  
        USHORT POINTER\_ALIGNMENT FileAttributes;  
        USHORT ShareAccess;  
        ULONG POINTER\_ALIGNMENT EaLength;  
    } Create;

    //  
    // System service parameters for:  NtReadFile  
    //

    struct {  
        ULONG Length;  
        ULONG POINTER\_ALIGNMENT Key;  
        LARGE\_INTEGER ByteOffset;  
    } Read;

    //  
    // System service parameters for:  NtWriteFile  
    //

    struct {  
        ULONG Length;  
        ULONG POINTER\_ALIGNMENT Key;  
        LARGE\_INTEGER ByteOffset;  
    } Write;

    //  
    // System service parameters for:  NtQueryDirectoryFile  
    //

    struct {  
        ULONG Length;  
        PUNICODE\_STRING FileName;  
        FILE\_INFORMATION\_CLASS FileInformationClass;  
        ULONG POINTER\_ALIGNMENT FileIndex;  
    } QueryDirectory;

    //  
    // System service parameters for:  NtNotifyChangeDirectoryFile  
    //

    struct {  
        ULONG Length;  
        ULONG POINTER\_ALIGNMENT CompletionFilter;  
    } NotifyDirectory;

    //  
    // System service parameters for:  NtQueryInformationFile  
    //

    struct {  
        ULONG Length;  
        FILE\_INFORMATION\_CLASS POINTER\_ALIGNMENT FileInformationClass;  
    } QueryFile;

    //  
    // System service parameters for:  NtSetInformationFile  
    //

    struct {  
        ULONG Length;  
        FILE\_INFORMATION\_CLASS POINTER\_ALIGNMENT FileInformationClass;  
        PFILE\_OBJECT FileObject;  
        union {  
            struct {  
                BOOLEAN ReplaceIfExists;  
                BOOLEAN AdvanceOnly;  
            };  
            ULONG ClusterCount;  
            HANDLE DeleteHandle;  
        };  
    } SetFile;

    //  
    // System service parameters for:  NtQueryEaFile  
    //

    struct {  
        ULONG Length;  
        PVOID EaList;  
        ULONG EaListLength;  
        ULONG POINTER\_ALIGNMENT EaIndex;  
    } QueryEa;

    //  
    // System service parameters for:  NtSetEaFile  
    //

    struct {  
        ULONG Length;  
    } SetEa;

    //  
    // System service parameters for:  NtQueryVolumeInformationFile  
    //

    struct {  
        ULONG Length;  
        FS\_INFORMATION\_CLASS POINTER\_ALIGNMENT FsInformationClass;  
    } QueryVolume;

    //  
    // System service parameters for:  NtSetVolumeInformationFile  
    //

    struct {  
        ULONG Length;  
        FS\_INFORMATION\_CLASS POINTER\_ALIGNMENT FsInformationClass;  
    } SetVolume;

    //  
    // System service parameters for:  NtFsControlFile  
    //  
    // Note that the user's output buffer is stored in the UserBuffer field  
    // and the user's input buffer is stored in the SystemBuffer field.  
    //

    struct {  
        ULONG OutputBufferLength;  
        ULONG POINTER\_ALIGNMENT InputBufferLength;  
        ULONG POINTER\_ALIGNMENT FsControlCode;  
        PVOID Type3InputBuffer;  
    } FileSystemControl;  
    //  
    // System service parameters for:  NtLockFile/NtUnlockFile  
    //

    struct {  
        PLARGE\_INTEGER Length;  
        ULONG POINTER\_ALIGNMENT Key;  
        LARGE\_INTEGER ByteOffset;  
    } LockControl;

    //  
    // System service parameters for:  NtFlushBuffersFile  
    //  
    // No extra user-supplied parameters.  
    //

    //  
    // System service parameters for:  NtCancelIoFile  
    //  
    // No extra user-supplied parameters.  
    //

    //  
    // System service parameters for:  NtDeviceIoControlFile  
    //  
    // Note that the user's output buffer is stored in the UserBuffer field  
    // and the user's input buffer is stored in the SystemBuffer field.  
    //

    struct {  
        ULONG OutputBufferLength;  
        ULONG POINTER\_ALIGNMENT InputBufferLength;  
        ULONG POINTER\_ALIGNMENT IoControlCode;  
        PVOID Type3InputBuffer;  
    } DeviceIoControl;

    //  
    // System service parameters for:  NtQuerySecurityObject  
    //

    struct {  
        SECURITY\_INFORMATION SecurityInformation;  
        ULONG POINTER\_ALIGNMENT Length;  
    } QuerySecurity;

    //  
    // System service parameters for:  NtSetSecurityObject  
    //

    struct {  
        SECURITY\_INFORMATION SecurityInformation;  
        PSECURITY\_DESCRIPTOR SecurityDescriptor;  
    } SetSecurity;

    //  
    // Non-system service parameters.  
    //  
    // Parameters for MountVolume  
    //

    struct {  
        PVPB Vpb;  
        PDEVICE\_OBJECT DeviceObject;  
    } MountVolume;

    //  
    // Parameters for VerifyVolume  
    //

    struct {  
        PVPB Vpb;  
        PDEVICE\_OBJECT DeviceObject;  
    } VerifyVolume;

    //  
    // Parameters for Scsi with internal device contorl.  
    //

    struct {  
        struct \_SCSI\_REQUEST\_BLOCK \*Srb;  
    } Scsi;

    //  
    // System service parameters for:  NtQueryQuotaInformationFile  
    //

    struct {  
        ULONG Length;  
        PSID StartSid;  
        PFILE\_GET\_QUOTA\_INFORMATION SidList;  
        ULONG SidListLength;  
    } QueryQuota;

    //  
    // System service parameters for:  NtSetQuotaInformationFile  
    //

    struct {  
        ULONG Length;  
    } SetQuota;

    //  
    // Parameters for IRP\_MN\_QUERY\_DEVICE\_RELATIONS  
    //

    struct {  
        DEVICE\_RELATION\_TYPE Type;  
    } QueryDeviceRelations;

    //  
    // Parameters for IRP\_MN\_QUERY\_INTERFACE  
    //

    struct {  
        CONST GUID \*InterfaceType;  
        USHORT Size;  
        USHORT Version;  
        PINTERFACE Interface;  
        PVOID InterfaceSpecificData;  
    } QueryInterface;

    //  
    // Parameters for IRP\_MN\_QUERY\_CAPABILITIES  
    //

    struct {  
        PDEVICE\_CAPABILITIES Capabilities;  
    } DeviceCapabilities;

    //  
    // Parameters for IRP\_MN\_FILTER\_RESOURCE\_REQUIREMENTS  
    //

    struct {  
        PIO\_RESOURCE\_REQUIREMENTS\_LIST IoResourceRequirementList;  
    } FilterResourceRequirements;

    //  
    // Parameters for IRP\_MN\_READ\_CONFIG and IRP\_MN\_WRITE\_CONFIG  
    //

    struct {  
        ULONG WhichSpace;  
        PVOID Buffer;  
        ULONG Offset;  
        ULONG POINTER\_ALIGNMENT Length;  
    } ReadWriteConfig;

    //  
    // Parameters for IRP\_MN\_SET\_LOCK  
    //

    struct {  
        BOOLEAN Lock;  
    } SetLock;

    //  
    // Parameters for IRP\_MN\_QUERY\_ID  
    //

    struct {  
        BUS\_QUERY\_ID\_TYPE IdType;  
    } QueryId;

    //  
    // Parameters for IRP\_MN\_QUERY\_DEVICE\_TEXT  
    //

    struct {  
        DEVICE\_TEXT\_TYPE DeviceTextType;  
        LCID POINTER\_ALIGNMENT LocaleId;  
    } QueryDeviceText;

    //  
    // Parameters for IRP\_MN\_DEVICE\_USAGE\_NOTIFICATION  
    //

    struct {  
        BOOLEAN InPath;  
        BOOLEAN Reserved\[3\];  
        DEVICE\_USAGE\_NOTIFICATION\_TYPE POINTER\_ALIGNMENT Type;  
    } UsageNotification;

    //  
    // Parameters for IRP\_MN\_WAIT\_WAKE  
    //

    struct {  
        SYSTEM\_POWER\_STATE PowerState;  
    } WaitWake;

    //  
    // Parameter for IRP\_MN\_POWER\_SEQUENCE  
    //

    struct {  
        PPOWER\_SEQUENCE PowerSequence;  
    } PowerSequence;

    //  
    // Parameters for IRP\_MN\_SET\_POWER and IRP\_MN\_QUERY\_POWER  
    //

#if (NTDDI_VERSION >= NTDDI_VISTA)
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 // (NTDDI_VERSION >= NTDDI_VISTA)

    //  
    // Parameters for StartDevice  
    //

    struct {  
        PCM\_RESOURCE\_LIST AllocatedResources;  
        PCM\_RESOURCE\_LIST AllocatedResourcesTranslated;  
    } StartDevice;

    //  
    // Parameters for Cleanup  
    //  
    // No extra parameters supplied  
    //

    //  
    // WMI Irps  
    //

    struct {  
        ULONG\_PTR ProviderId;  
        PVOID DataPath;  
        ULONG BufferSize;  
        PVOID Buffer;  
    } WMI;

    //  
    // Others - driver-specific  
    //

    struct {  
        PVOID Argument1;  
        PVOID Argument2;  
        PVOID Argument3;  
        PVOID Argument4;  
    } Others;

} Parameters;

//  
// Save a pointer to this device driver's device object for this request  
// so it can be passed to the completion routine if needed.  
//

PDEVICE\_OBJECT DeviceObject;

//  
// The following location contains a pointer to the file object for this  
// request.  
//

PFILE\_OBJECT FileObject;

//  
// The following routine is invoked depending on the flags in the above  
// flags field.  
//

PIO\_COMPLETION\_ROUTINE CompletionRoutine;

//  
// The following is used to store the address of the context parameter  
// that should be passed to the CompletionRoutine.  
//

PVOID Context;

} IO_STACK_LOCATION, *PIO_STACK_LOCATION;

结构图如下

MajorFunction(UCHAR)是该IRP的主功能码

MinorFunction(UCHAR)是该IRP的副功能码

Parameters(union)是几个子结构的联合,每个请求类型都有自己专用的参数,而每个子结构就是一种参数。这些子结构包括Create(IRP_MJ_CREATE请求)、Read(IRP_MJ_READ请求)、StartDevice(IRP_MJ_PNP的IRP_MN_START_DEVICE子类型),等等。

DeviceObject(PDEVICE_OBJECT)是与该堆栈单元对应的设备对象的地址。该域由IoCallDriver函数负责填写。

FileObject(PFILE_OBJECT)是内核文件对象的地址,IRP的目标就是这个文件对象。驱动程序通常在处理清除请求(IRP_MJ_CLEANUP)时使用FileObject指针,以区分队列中与该文件对象无关的IRP。

CompletionRoutine(PIO_COMPLETION_ROUTINE)是一个I/O完成例程的地址,该地址是由与这个堆栈单元对应的驱动程序的更上一层驱动程序设置的。你绝对不要直接设置这个域,应该调用IoSetCompletionRoutine函数,该函数知道如何参考下一层驱动程序的堆栈单元。设备堆栈的最低一级驱动程序并不需要完成例程,因为它们必须直接完成请求。然而,请求的发起者有时确实需要一个完成例程,但通常没有自己的堆栈单元。这就是为什么每一级驱动程序都使用下一级驱动程序的堆栈单元保存自己完成例程指针的原因。

IRP、PIO_STACK_LOCATIONDEVICE:

1)I/O堆栈位置的主要目的是,保存一个I/O请求的函数代码和参数。
2)I/O堆栈数量实际上就是参与I/O请求的I/O层的数量。
3)在一个IRP中,上层驱动负责为下层驱动设置堆栈位置指针。  i)驱动程序可以为每个IRP调用IoGetCurrentStackLocation来获得指向其自身堆栈位置的指针,
  ii)上层驱动程序必须调用IoGetNextIrpStackLocation来获得指向下层驱动程序堆栈位置的指针。
因此,上层驱动可以在传送IRP给下层驱动之前设置堆栈位置的内容。4)上层驱动调用IoCallDriver,将DeviceObject成员设置成下层驱动目标设备对象。当上层驱动完成IRP时,IoCompletion 函数被调用,I/O管理器传送给IoCompletion函数一个指向上层驱动的设备对象的指针。

示例:

下面我们通过构造IPR去删除一个文件来加深对IPR的认识

1 #include "DeleteFile.h"
2
3 NTSTATUS
4 DriverEntry(PDRIVER_OBJECT DriverObject,PUNICODE_STRING RegisterPath)
5 {
6
7 HANDLE hFile = GetFileHandle(L"\\??\\D:\\1.exe");
8 DriverObject->DriverUnload = UnloadDriver;
9
10 if (hFile!=NULL)
11 {
12
13 DbgPrint("Get File Success\r\n");
14 DestroyFile(hFile);
15
16 ZwClose(hFile);
17 }
18
19 return STATUS_SUCCESS;
20 }
21
22
23 VOID
24 UnloadDriver(PDRIVER_OBJECT DriverObject)
25 {
26
27 }
28
29
30 HANDLE
31 GetFileHandle(PCWSTR FileName)
32 {
33
34 NTSTATUS Status;
35 UNICODE_STRING uniFileName;
36 OBJECT_ATTRIBUTES oa;
37 HANDLE hFile;
38 IO_STATUS_BLOCK Iosb;
39
40 RtlInitUnicodeString(&uniFileName,FileName);
41
42 InitializeObjectAttributes(&oa,&uniFileName,
43 OBJ_KERNEL_HANDLE|OBJ_CASE_INSENSITIVE,NULL,NULL);
44
45 //通过文件名得文件句柄
46 Status = IoCreateFile(&hFile,FILE_READ_ATTRIBUTES,
47 &oa,&Iosb,0,FILE_ATTRIBUTE_NORMAL,FILE_SHARE_DELETE,FILE_OPEN,0,NULL,0,0,NULL,
48 IO_NO_PARAMETER_CHECKING);
49
50
51 if (!NT_SUCCESS(Status))
52 {
53 return NULL;
54 }
55
56 return hFile;
57
58 }
59
60
61 VOID
62 DestroyFile(HANDLE hFile)
63 {
64
65 IO_STATUS_BLOCK Iosb;
66 PIO_STACK_LOCATION IrpSp;
67 NTSTATUS Status;
68 PFILE_OBJECT FileObject;
69 PIRP Irp;
70 PDEVICE_OBJECT DeviceObject;
71 KEVENT hEvent;
72 FILE_DISPOSITION_INFORMATION FileInfor;//微软官方结构体
73
74
75 static PVOID ImageSectionObject = NULL;
76 static PVOID DataSectionObject = NULL;
77 static PVOID SharedCacheMap = NULL;
78
79 //通过文件句柄得文件对象
80 Status = ObReferenceObjectByHandle(hFile,DELETE,*IoFileObjectType,KernelMode,
81 &FileObject,NULL);
82
83
84 DeviceObject = IoGetRelatedDeviceObject(FileObject); //文件系统栈最上层的设备对象 //也可以获得卷设备直接发送
85
86
87
88 //去除文件的只读属性
89 if (SKillStripFileAttributes(hFile)==FALSE)
90 {
91 return;
92 }
93 //构建一个IRP
94
95 Irp = IoAllocateIrp(DeviceObject->StackSize,TRUE);
96 if (Irp==NULL)
97 {
98 ObDereferenceObject(FileObject);
99
100 return;
101 }
102
103
104 KeInitializeEvent(&hEvent,SynchronizationEvent,FALSE);
105
106
107 FileInfor.DeleteFile = TRUE;
108
109
110 Irp->AssociatedIrp.SystemBuffer = &FileInfor;
111 Irp->UserEvent = &hEvent;
112 Irp->UserIosb = &Iosb;
113 Irp->Tail.Overlay.OriginalFileObject = FileObject;
114 Irp->Tail.Overlay.Thread = KeGetCurrentThread();
115 Irp->RequestorMode = KernelMode;
116
117
118 IrpSp = IoGetNextIrpStackLocation(Irp);
119
120 IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
121
122 IrpSp->DeviceObject = DeviceObject;// Irp栈中保存的设备对象是文件系统设备对象
123 IrpSp->FileObject = FileObject; //
124
125 IrpSp->Parameters.SetFile.FileObject = FileObject;
126 IrpSp->Parameters.SetFile.Length = sizeof(FILE_DISPOSITION_INFORMATION);
127 IrpSp->Parameters.SetFile.FileObject = FileObject;
128
129 IrpSp->Parameters.SetFile.FileInformationClass = FileDispositionInformation;
130
131
132 //将文件的物理页面的属性先保存起来
133 //文件对象指向的物理页(IRP会对他进行检测,如果不为空不删除文件)
134 if (MmIsAddressValid(FileObject->SectionObjectPointer))
135 {
136 ImageSectionObject = FileObject->SectionObjectPointer->ImageSectionObject;
137 DataSectionObject = FileObject->SectionObjectPointer->DataSectionObject;
138 SharedCacheMap = FileObject->SectionObjectPointer->SharedCacheMap;
139
140 FileObject->SectionObjectPointer->ImageSectionObject = NULL;
141 FileObject->SectionObjectPointer->DataSectionObject = NULL;
142 FileObject->SectionObjectPointer->SharedCacheMap = NULL;
143 }
144
145
146
147
148 IoSetCompletionRoutine(Irp,IrpCompleteRoutine,&hEvent,TRUE,TRUE,TRUE);
149
150
151 IoCallDriver(DeviceObject,Irp);
152
153 KeWaitForSingleObject(&hEvent,Executive,KernelMode,TRUE,NULL);
154
155
156
157
158 //恢复环境
159 if (MmIsAddressValid(FileObject->SectionObjectPointer))
160 {
161 FileObject->SectionObjectPointer->ImageSectionObject = ImageSectionObject;
162 FileObject->SectionObjectPointer->DataSectionObject = DataSectionObject;
163 FileObject->SectionObjectPointer->SharedCacheMap = SharedCacheMap;
164 }
165
166
167
168 ObDereferenceObject(FileObject);
169 }
170
171
172
173 BOOLEAN
174 SKillStripFileAttributes(HANDLE hFile)
175 {
176 NTSTATUS Status = STATUS_SUCCESS;
177 PFILE_OBJECT FileObject;
178 PDEVICE_OBJECT DeviceObject;
179 PIRP Irp;
180 KEVENT kEvent;
181 FILE_BASIC_INFORMATION FileBaseInfor;
182 IO_STATUS_BLOCK Iosb;
183 PIO_STACK_LOCATION IrpSp;
184
185 BOOLEAN bInit = FALSE;
186
187
188
189 Status = ObReferenceObjectByHandle(hFile,
190 DELETE,
191 *IoFileObjectType,
192 KernelMode,
193 &FileObject,
194 NULL);
195
196 if (!NT_SUCCESS(Status))
197 {
198 return FALSE;
199 }
200
201 DeviceObject = IoGetRelatedDeviceObject(FileObject); //VPB->DeviceObject
202 Irp = IoAllocateIrp(DeviceObject->StackSize, TRUE);
203
204 if (Irp == NULL)
205 {
206 ObDereferenceObject(FileObject);
207 return FALSE;
208 }
209
210 KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
211
212 memset(&FileBaseInfor,0,sizeof(FILE_BASIC_INFORMATION));
213
214 FileBaseInfor.FileAttributes = FILE_ATTRIBUTE_NORMAL;
215 Irp->AssociatedIrp.SystemBuffer = &FileBaseInfor;
216 Irp->UserEvent = &kEvent;
217 Irp->UserIosb = &Iosb;
218 Irp->Tail.Overlay.OriginalFileObject = FileObject;
219 Irp->Tail.Overlay.Thread = (PETHREAD)KeGetCurrentThread();
220 Irp->RequestorMode = KernelMode;
221
222 IrpSp = IoGetNextIrpStackLocation(Irp);
223 IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
224 IrpSp->DeviceObject = DeviceObject;
225 IrpSp->FileObject = FileObject;
226 IrpSp->Parameters.SetFile.Length = sizeof(FILE_BASIC_INFORMATION);
227 IrpSp->Parameters.SetFile.FileInformationClass = FileBasicInformation;
228
229
230 IoSetCompletionRoutine(
231 Irp,
232 IrpCompleteRoutine,
233 &kEvent,
234 TRUE,
235 TRUE,
236 TRUE);
237
238 IoCallDriver(DeviceObject,Irp);
239 KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, NULL);
240 ObDereferenceObject(FileObject);
241
242 return TRUE;
243 }
244
245
246
247 NTSTATUS
248 IrpCompleteRoutine(PDEVICE_OBJECT DeviceObject,PIRP Irp,PVOID Context)
249 {
250 KeSetEvent(Irp->UserEvent,IO_NO_INCREMENT,FALSE);
251
252 IoFreeIrp(Irp);
253
254 return STATUS_MORE_PROCESSING_REQUIRED;
255
256 }