漫谈IRP
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将等于一个枚举常量UserMode或KernelMode,指定原始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_LOCATION与DEVICE:
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 }