漫谈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;
View Code

 

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

 

 

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;
View Code

 

结构图如下

 

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 }

 

posted on 2016-04-17 22:34  zbility  阅读(4019)  评论(0编辑  收藏  举报

导航