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 }