使用IRP进行文件操作

时间:2022-07-09 21:34:56

首先声明这个是菜鸟—我的学习日记,不是什么高深文章,高手们慎看.

一定要先感谢为技术的进步而付出辛勤汗水的人,感谢他们对技术的共享.

一个通用IRP访问文件的十六进制编辑器(开源代码)     --   被诅咒的神(邪恶八进制信息安全团队)

Windows平台内核级文件访问                               --   baiyuanfan (baiyuanfan@163.com)

特别感谢被诅咒的神,他写的<ExTools v1.2>里面包含了非常多IRP对文件操作的宝贵信息,对初入门的我来说帮助非常大.大家可以去下载他的源码参考.

虽然天气仍然好冻,但文章是不写不快,刚做好了一些函数,希望共享出来之后对大家有小小帮助.这个月是放假,时间比较充裕,利用这些时间可以学好多知识.很久以前就对pjf写的IceSword感兴趣,也很羡慕他能够写出这么强大的Anti-Rootkit软件,如今终于实现类似他那样文件操作的功能,好开心.(我也不敢确定他是这样写的,网上看到他是用IRP对文件操作的).

我写这些函数的过程好曲折,幸好我没放弃,我先是看了<Windows文件系统过滤驱动开发教程(第二版)--楚狂人>,没看完,自己总结:就是将自己的驱动绑定在设备栈的栈顶,让所有IRP都经过自己的驱动,对IRP过滤,其中细节非常多,如果不是楚狂人做了这么好的说明教程,光看微软给的例子可能就没那么容易了,所以要感谢楚狂人.但对自己发送IRP帮助不大.再而看了OSR_docs里面的pdf,也不是全看,看了一些关键的,例如<IrpMan.pdf>里面的<2.2.14.6 Kernel File Copy Example>,这里面写了4个IRP的使用,分别为IRP_MJ_QUERY_INFORMATION  IRP_MJ_SET_INFORMATION  IRP_MJ_READ  IRP_MJ_WRITE,建议大家也去看看,是非常好的参考资料.但这里没有写到IRP_MJ_CREATE的填写,于是我参考着这些资料填写IRP然后IoCallDriver,当然不成功拉.于是我跳过它先做IRP_MJ_DIRECTORY_CONTROL的,也就是平时枚举文件用的NtQueryDirectoryFile最终要发送的IRP,成功了,那时好开心.接下来在网上发现了被诅咒的神写的<ExTools v1.2>的源码,有这么好的参考资料,进度当然快好多啦.而<ExTools v1.2>没的IRP_MJ_SET_INFORMATION也帮您补上了^_^.现在完成了将成品共享给大家.

这里有个重点,我引用<Windows平台内核级文件访问>里面的一段话:

文件系统过滤驱动Attach在正常的文件系统之上,监视和过滤我们的文件访问。文件系统驱动栈就是由这一连串的Attach起来的过滤驱动组成。我们可以用IoGetRelatedDeviceObject这个函数来获得一个FileObject对应的最底层的那个功能驱动对象(FDO)。但是这样虽然绕过了那些过滤驱动,却同时也绕过了正常的FSD如Ntfs/Fastfat,因为正常的FSD也是作为一个过滤驱动存在的。磁盘文件对象的对应的最底层的FDO是Ftdisk.sys,它已经因为过于底层而不能处理我们投递的IRP请求。
   其实正常的FSD信息存储在一个Vpb结构中,我们可以使用IoGetBaseFileSystemDeviceObject这个未公开的内核函数来得到它。它就是我们发送IRP的目标了。

但既然是在Vpb里面有正常的FSD,我就直接用了,以免调用了被hook的函数.知道文件过滤驱动原理就可以知道这样做可以绕过栈顶的驱动直接发送IRP到正常FSD.这点很重要.

我写的大概有如下一些IRP的调用,及其所对应的函数我也列出来,好让像我这样的初学者明白.(其实这里大部分都不是我写的^_^)

IRP_MJ_CREATE

NtCreateFile

创建或新建文件返回句柄,不过发IRP返回的是FILE_OBJECT,线程无关的.

IRP_MJ_CLEANUP

NtClose

用于关闭HANDLE的

IRP_MJ_CLOSE

ObDereferenceObject

用于关闭FILE_OBJECT的

IRP_MJ_DIRECTORY_CONTROL

NtQueryDirectoryFile

枚举目录,好多时候都被hook的

IRP_MJ_QUERY_INFORMATION

NtQueryInformationFile

取得文件信息

IRP_MJ_SET_INFORMATION

NtSetInformationFile

设置文件信息:删除,改名,改属性

IRP_MJ_READ

NtReadFile

读文件

IRP_MJ_WRITE

NtWriteFile

写文件

直接发送IRP对文件进行操作是可以避免一些Rootkit的干扰的,除非Hook IoCallDriver,不过我在网上看到pjf写的IceSword是要先读取ntkrnlpa.exe(多核处理器使用)或者ntoskrnl.exe(单核处理器使用)里面的IoCallDriver的开头几字节然后还原一下,防止被hook.啊~pjf想得真周到,羡慕~~~~~(哪天我能有他那么强咧^_^).好啦,以下是代码了,代码比较长,参数比较复杂,一个细节写错可能会BSOD.我已经尽量依照好似微软给的API那样写的了,有说明(其实是复制WDK的^_^),再一次声明代码大部分不是我写的,我不过是改了点,更方便大家使用习惯,从中我也学了不少,唉,中国这些技术的文章真少,是落后?

如果发现这里面的函数调用会产生蓝屏,而确认您的传入参数准确无误,那么请在这里留言给我,谢谢.

#include "ntifs.h"
 
//
//  Define the structure used by this driver module.
//
typedef struct _AUX_ACCESS_DATA {
     PPRIVILEGE_SET PrivilegesUsed;
     GENERIC_MAPPING GenericMapping;
     ACCESS_MASK AccessesToAudit;
     ULONG Reserve;                            //unknow...
} AUX_ACCESS_DATA, *PAUX_ACCESS_DATA;
//
//  Define the local routines used by this driver module.
//
NTSTATUS
ObCreateObject (
     IN KPROCESSOR_MODE ProbeMode,
     IN POBJECT_TYPE ObjectType,
     IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
     IN KPROCESSOR_MODE OwnershipMode,
     IN OUT PVOID ParseContext OPTIONAL,
     IN ULONG ObjectBodySize,
     IN ULONG PagedPoolCharge,
     IN ULONG NonPagedPoolCharge,
     OUT PVOID *Object
     );
NTSTATUS
SeCreateAccessState(
     IN PACCESS_STATE AccessState,
     IN PAUX_ACCESS_DATA AuxData,
     IN ACCESS_MASK DesiredAccess,
     IN PGENERIC_MAPPING GenericMapping OPTIONAL
     );
//
// IoCompletionRoutine
//
// This routine is used to handle I/O (read OR write) completion
//
// Inputs:
// DeviceObject - not used
// Irp - the I/O operation being completed
// Context - not used
//
// Outputs:
// None.
//
// Returns:
// STATUS_MORE_PROCESSING_REQUIRED
//
// Notes:
// The purpose of this routine is to do "cleanup" on I/O operations
// so we don't constantly throw away perfectly good MDLs as part of
// completion processing.
//
NTSTATUS
IoCompletionRoutine(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp,
     IN PVOID Context
     );
//
// IrpCreateFile
//
// This routine is used as NtCreateFile but first and third parameter.
//
// Inputs:
// DesiredAccess - Specifies an ACCESS_MASK value that determines
//                     the requested access to the object.
// FilePath - Path of file to create,as L"C://Windows"(Unicode).
// AllocationSize - Pointer to a LARGE_INTEGER that contains the initial allocation
//                     size, in bytes, for a file that is created or overwritten.
// FileAttributes - Specifies one or more FILE_ATTRIBUTE_XXX flags, which represent
//                     the file attributes to set if you are creating or overwriting a file.
// ShareAccess - Type of share access.
// CreateDisposition - Specifies the action to perform if the file does or does not exist.
// CreateOptions - Specifies the options to apply when creating or opening the file.
// EaBuffer - For device and intermediate drivers, this parameter must be a NULL pointer.
// EaLength - For device and intermediate drivers, this parameter must be zero.
//
// Ouputs:
// FileObject - Pointer to a PFILE_OBJECT variable that
//                 receives a PFILE_OBJECT to the file.
// IoStatusBlock - Pointer to an IO_STATUS_BLOCK structure that receives the final
//                 completion status and information about the requested read operation.
//
// Returns:
// The IRP send status.
//
// Notes:
// This is equivalent to NtCreateFile,but return FILE_OBJECT not HANDLE.
//
NTSTATUS
IrpCreateFile(
     OUT PFILE_OBJECT  *FileObject,
     IN ACCESS_MASK  DesiredAccess,
     IN PUNICODE_STRING  FilePath,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     IN PLARGE_INTEGER  AllocationSize OPTIONAL,
     IN ULONG  FileAttributes,
     IN ULONG  ShareAccess,
     IN ULONG  CreateDisposition,
     IN ULONG  CreateOptions,
     IN PVOID  EaBuffer OPTIONAL,
     IN ULONG  EaLength
     );
//
// IrpClose
//
// This routine is used as ObDereferenceObject.
//
// Inputs:
// FileObject - Pointer to a PFILE_OBJECT variable that will close
//
// Ouputs:
// IoStatusBlock - Pointer to an IO_STATUS_BLOCK structure that receives the final
//                 completion status and information about the requested read operation.
//
// Returns:
// The IRP send status.
//
// Notes:
// This is equivalent to ObDereferenceObject
//
NTSTATUS
IrpClose(
     IN PFILE_OBJECT  FileObject
     );
//
// IrpQueryDirectoryFile
//
// This routine is used as NtQueryDirectoryFile.
//
// Inputs:
// FileObject - Pointer to a PFILE_OBJECT.
// Length - Size, in bytes, of the buffer pointed to by FileInformation. The caller
//            should set this parameter according to the given FileInformationClass.
// FileInformationClass - Type of information to be returned about files in the directory.
// FileName - Pointer to a caller-allocated Unicode string containing the name of a file
//            (or multiple files, if wildcards are used) within the directory specified by FileHandle.
//            This parameter is optional and can be NULL.
//
// Ouputs:
// IoStatusBlock - Pointer to an IO_STATUS_BLOCK structure that receives the final
//                 completion status and information about the requested read operation.
// FileInformation - Pointer to a buffer that receives the desired
//                          information about the file.
//
// Returns:
// The IRP send status.
//
// Notes:
// This is equivalent to NtQueryDirectoryFile, but no ApcRoutine.
//
NTSTATUS
IrpQueryDirectoryFile(
     IN PFILE_OBJECT  FileObject,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     OUT PVOID  FileInformation,
     IN ULONG  Length,
     IN FILE_INFORMATION_CLASS  FileInformationClass,
     IN PUNICODE_STRING  FileName  OPTIONAL
     );
//
// IrpQueryInformationFile
//
// This routine is used as NtQueryInformationFile.
//
// Inputs:
// FileObject - Pointer to a PFILE_OBJECT.
// Length - Size, in bytes, of the buffer pointed to by FileInformation. The caller
//            should set this parameter according to the given FileInformationClass.
// FileInformationClass - Type of information to be returned about files in the directory.
//
// Ouputs:
// IoStatusBlock - Pointer to an IO_STATUS_BLOCK structure that receives the final
//                 completion status and information about the requested read operation.
// FileInformation - Pointer to a buffer that receives the desired
//                          information about the file.
//
// Returns:
// The IRP send status.
//
// Notes:
// This is equivalent to NtQueryInformationFile.
//
NTSTATUS
IrpQueryInformationFile(
     IN PFILE_OBJECT  FileObject,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     OUT PVOID  FileInformation,
     IN ULONG  Length,
     IN FILE_INFORMATION_CLASS  FileInformationClass
     );
//
// IrpSetInformationFile
//
// This routine is used as NtSetInformationFile.
//
// Inputs:
// FileObject - Pointer to a PFILE_OBJECT.
// FileInformation - Pointer to a buffer that contains the information to set for the file. 
// Length - Size, in bytes, of the buffer pointed to by FileInformation. The caller
//            should set this parameter according to the given FileInformationClass.
// FileInformationClass - Type of information to be returned about files in the directory.
// ReplaceIfExists - Set to TRUE to specify that if a file with the same name already exists,
//                     it should be replaced with the given file. Set to FALSE if the rename
//                     operation should fail if a file with the given name already exists.
//
// Ouputs:
// IoStatusBlock - Pointer to an IO_STATUS_BLOCK structure that receives the final
//                 completion status and information about the requested read operation.
//
// Returns:
// The IRP send status.
//
// Notes:
// This is equivalent to NtSetInformationFile.
//
NTSTATUS
IrpSetInformationFile(
     IN PFILE_OBJECT  FileObject,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     IN PVOID  FileInformation,
     IN ULONG  Length,
     IN FILE_INFORMATION_CLASS  FileInformationClass,
     IN BOOLEAN  ReplaceIfExists
     );
//
// IrpReadFile
//
// This routine is used as NtReadFile.
//
// Inputs:
// FileObject - Pointer to a PFILE_OBJECT.
// Buffer - Pointer to a caller-allocated buffer that receives the data read from the file.
// Length - The size, in bytes, of the buffer pointed to by Buffer.
// ByteOffset - Pointer to a variable that specifies the starting byte offset
//                 in the file where the read operation will begin.
//
// Ouputs:
// IoStatusBlock - Pointer to an IO_STATUS_BLOCK structure that receives the final
//                completion status and information about the requested read operation.
//
// Returns:
// The IRP send status.
//
// Notes:
// This is equivalent to NtReadFile, but no ApcRoutine.
//
NTSTATUS
IrpReadFile(
     IN PFILE_OBJECT  FileObject,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     OUT PVOID  Buffer,
     IN ULONG  Length,
     IN PLARGE_INTEGER  ByteOffset  OPTIONAL
     );
//
// IrpReadFile
//
// This routine is used as NtReadFile.
//
// Inputs:
// FileObject - Pointer to a PFILE_OBJECT.
// Buffer - Pointer to a caller-allocated buffer that contains the data to write to the file.
// Length - The size, in bytes, of the buffer pointed to by Buffer.
// ByteOffset - Pointer to a variable that specifies the starting byte offset
//                 in the file for beginning the write operation.
//
// Ouputs:
// IoStatusBlock - Pointer to an IO_STATUS_BLOCK structure that receives the final
//                 completion status and information about the requested read operation.
//
// Returns:
// The IRP send status.
//
// Notes:
// This is equivalent to NtReadFile, but no ApcRoutine.
//
NTSTATUS
IrpWriteFile(
     IN PFILE_OBJECT  FileObject,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     IN PVOID  Buffer,
     IN ULONG  Length,
     IN PLARGE_INTEGER  ByteOffset  OPTIONAL
     );
 
//
// Function start.
//
NTSTATUS
IoCompletionRoutine(
     IN PDEVICE_OBJECT DeviceObject,
     IN PIRP Irp,
     IN PVOID Context)
{
     *Irp->UserIosb = Irp->IoStatus;
     if (Irp->UserEvent)
         KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, 0);
     if (Irp->MdlAddress)
     {
         IoFreeMdl(Irp->MdlAddress);
         Irp->MdlAddress = NULL;
     }
     IoFreeIrp(Irp);
     return STATUS_MORE_PROCESSING_REQUIRED;
}
 
NTSTATUS
IrpCreateFile(
     OUT PFILE_OBJECT  *FileObject,
     IN ACCESS_MASK  DesiredAccess,
     IN PUNICODE_STRING  FilePath,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     IN PLARGE_INTEGER  AllocationSize  OPTIONAL,
     IN ULONG  FileAttributes,
     IN ULONG  ShareAccess,
     IN ULONG  CreateDisposition,
     IN ULONG  CreateOptions,
     IN PVOID  EaBuffer  OPTIONAL,
     IN ULONG  EaLength)
{
     NTSTATUS ntStatus;
 
     HANDLE hFile;
     PFILE_OBJECT pFile, _FileObject;
     UNICODE_STRING UniDeviceNameString;
    OBJECT_ATTRIBUTES ObjectAttributes;
     PDEVICE_OBJECT DeviceObject, RealDevice;
 
     PIRP Irp;
     KEVENT kEvent;
     PIO_STACK_LOCATION IrpSp;
     ACCESS_STATE AccessState;
     AUX_ACCESS_DATA AuxData;
     IO_SECURITY_CONTEXT SecurityContext;
 
     if(FilePath->Length < 6)
         return STATUS_INVALID_PARAMETER;
 
     RtlInitUnicodeString( &UniDeviceNameString, L"//DosDevices//*://" );
     UniDeviceNameString.Buffer[12] = FilePath->Buffer[0];
     InitializeObjectAttributes(&ObjectAttributes, &UniDeviceNameString, OBJ_KERNEL_HANDLE, NULL, NULL);
 
     ntStatus = IoCreateFile(&hFile,
                                 GENERIC_READ|SYNCHRONIZE,
                                 &ObjectAttributes,
                                 IoStatusBlock,
                                 NULL,
                                 FILE_ATTRIBUTE_NORMAL,
                                 FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
                                 FILE_OPEN,
                                 FILE_SYNCHRONOUS_IO_NONALERT,
                                 NULL,
                                 0,
                                 CreateFileTypeNone,
                                 NULL,
                                 IO_NO_PARAMETER_CHECKING);
     if(!NT_SUCCESS(ntStatus)) return ntStatus;
 
     ntStatus = ObReferenceObjectByHandle(hFile,
                                                FILE_READ_ACCESS, // ACCESS_MASK
                                                *IoFileObjectType,
                                                KernelMode,
                                                &pFile,
                                                0);
     NtClose(hFile);
     if(!NT_SUCCESS(ntStatus)) return ntStatus;
 
     DeviceObject = pFile->Vpb->DeviceObject;
     RealDevice = pFile->Vpb->RealDevice;
     ObDereferenceObject(pFile);
 
     InitializeObjectAttributes(&ObjectAttributes, NULL, OBJ_CASE_INSENSITIVE, 0, NULL);
 
     ntStatus = ObCreateObject(KernelMode,
                                   *IoFileObjectType,
                                   &ObjectAttributes,
                                   KernelMode,
                                   NULL,
                                   sizeof(FILE_OBJECT),
                                   0,
                                   0,
                                   &_FileObject);
     if (!NT_SUCCESS(ntStatus)) return ntStatus;
 
     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
     if(Irp == NULL)
     {
         ObDereferenceObject(_FileObject);
         return STATUS_INSUFFICIENT_RESOURCES;
     }
 
     KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
 
     RtlZeroMemory(_FileObject, sizeof(FILE_OBJECT));
     _FileObject->Type = IO_TYPE_FILE;
     _FileObject->Size = sizeof(FILE_OBJECT);
     _FileObject->DeviceObject = RealDevice;
     _FileObject->Flags = FO_SYNCHRONOUS_IO;
     RtlInitUnicodeString( &_FileObject->FileName, &FilePath->Buffer[2]);
     KeInitializeEvent(&_FileObject->Lock, SynchronizationEvent, FALSE);
     KeInitializeEvent(&_FileObject->Event, NotificationEvent, FALSE);
 
     RtlZeroMemory(&AuxData, sizeof(AUX_ACCESS_DATA));
     ntStatus = SeCreateAccessState( &AccessState,
                                          &AuxData,
                                          DesiredAccess,
                                          IoGetFileObjectGenericMapping());
     if (!NT_SUCCESS(ntStatus))
     {
         IoFreeIrp(Irp);
         ObDereferenceObject(_FileObject);
         return ntStatus;
     }
     SecurityContext.SecurityQos = NULL;
     SecurityContext.AccessState = &AccessState;
     SecurityContext.DesiredAccess = DesiredAccess;
     SecurityContext.FullCreateOptions = 0;
 
     Irp->MdlAddress = NULL;
     Irp->AssociatedIrp.SystemBuffer = EaBuffer;
     Irp->Flags = IRP_CREATE_OPERATION|IRP_SYNCHRONOUS_API;
     Irp->RequestorMode = KernelMode;
     Irp->UserIosb = IoStatusBlock;
     Irp->UserEvent = &kEvent;
     Irp->PendingReturned = FALSE;
     Irp->Cancel = FALSE;
     Irp->CancelRoutine = NULL;
     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
     Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
     Irp->Tail.Overlay.OriginalFileObject = _FileObject;
 
     IrpSp = IoGetNextIrpStackLocation(Irp);
     IrpSp->MajorFunction = IRP_MJ_CREATE;
     IrpSp->DeviceObject = DeviceObject;
     IrpSp->FileObject = _FileObject;
     IrpSp->Parameters.Create.SecurityContext = &SecurityContext;
     IrpSp->Parameters.Create.Options = (CreateDisposition << 24) | CreateOptions;
     IrpSp->Parameters.Create.FileAttributes = (USHORT)FileAttributes;
     IrpSp->Parameters.Create.ShareAccess = (USHORT)ShareAccess;
     IrpSp->Parameters.Create.EaLength = EaLength;
 
     IoSetCompletionRoutine(Irp, IoCompletionRoutine, 0, TRUE, TRUE, TRUE);
     ntStatus = IoCallDriver(DeviceObject, Irp);
     if(ntStatus == STATUS_PENDING)
         KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0);
 
     ntStatus = IoStatusBlock->Status;
 
     if(!NT_SUCCESS(ntStatus))
     {
         _FileObject->DeviceObject = NULL;
         ObDereferenceObject(_FileObject);
     }
     else
     {
         InterlockedIncrement(&_FileObject->DeviceObject->ReferenceCount);
         if (_FileObject->Vpb)
              InterlockedIncrement(&_FileObject->Vpb->ReferenceCount);
         *FileObject = _FileObject;
     }
 
     return ntStatus;
}
 
NTSTATUS
IrpClose(
     IN PFILE_OBJECT  FileObject)
{
     NTSTATUS ntStatus;
     IO_STATUS_BLOCK  IoStatusBlock;
     PIRP Irp;
     KEVENT kEvent;
     PIO_STACK_LOCATION IrpSp;
     PDEVICE_OBJECT pBaseDeviceObject = FileObject->Vpb->DeviceObject;
 
     if (FileObject->Vpb == 0 || FileObject->Vpb->DeviceObject == NULL)
         return STATUS_UNSUCCESSFUL;
 
     Irp = IoAllocateIrp(FileObject->Vpb->DeviceObject->StackSize, FALSE);
     if(Irp == NULL) return STATUS_INSUFFICIENT_RESOURCES;
 
     KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
 
     Irp->UserEvent = &kEvent;
     Irp->UserIosb = &IoStatusBlock;
     Irp->RequestorMode = KernelMode;
     Irp->Flags = IRP_CLOSE_OPERATION|IRP_SYNCHRONOUS_API;
     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
     Irp->Tail.Overlay.OriginalFileObject = FileObject;
 
     IrpSp = IoGetNextIrpStackLocation(Irp);
     IrpSp->MajorFunction = IRP_MJ_CLEANUP;
     IrpSp->FileObject = FileObject;
 
     ntStatus = IoCallDriver(pBaseDeviceObject, Irp);
     if (ntStatus == STATUS_PENDING)
         KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);
 
     ntStatus = IoStatusBlock.Status;
     if(!NT_SUCCESS(ntStatus))
     {
         IoFreeIrp(Irp);
         return ntStatus;
     }
 
     KeClearEvent(&kEvent);
     IoReuseIrp(Irp , STATUS_SUCCESS);
 
     Irp->UserEvent = &kEvent;
     Irp->UserIosb = &IoStatusBlock;
     Irp->Tail.Overlay.OriginalFileObject = FileObject;
     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
     Irp->AssociatedIrp.SystemBuffer = (PVOID)NULL;
     Irp->Flags = IRP_CLOSE_OPERATION|IRP_SYNCHRONOUS_API;
 
     IrpSp = IoGetNextIrpStackLocation(Irp);
     IrpSp->MajorFunction = IRP_MJ_CLOSE;
     IrpSp->FileObject = FileObject;
 
     if (FileObject->Vpb && !(FileObject->Flags & FO_DIRECT_DEVICE_OPEN))
     {
         InterlockedDecrement(&FileObject->Vpb->ReferenceCount);
         FileObject->Flags |= FO_FILE_OPEN_CANCELLED;
     }
 
     ntStatus = IoCallDriver(pBaseDeviceObject, Irp);
     if (ntStatus == STATUS_PENDING)
         KeWaitForSingleObject(&kEvent, Executive, KernelMode, FALSE, NULL);
 
     IoFreeIrp(Irp);
 
     ntStatus = IoStatusBlock.Status;
     return ntStatus;
}
 
NTSTATUS
IrpQueryDirectoryFile(
     IN PFILE_OBJECT  FileObject,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     OUT PVOID  FileInformation,
     IN ULONG  Length,
     IN FILE_INFORMATION_CLASS  FileInformationClass,
     IN PUNICODE_STRING  FileName  OPTIONAL)
{
     NTSTATUS ntStatus;
     PIRP Irp;
     KEVENT kEvent;
     PIO_STACK_LOCATION IrpSp;
 
     if (FileObject->Vpb == 0 || FileObject->Vpb->DeviceObject == NULL)
         return STATUS_UNSUCCESSFUL;
 
     Irp = IoAllocateIrp(FileObject->Vpb->DeviceObject->StackSize, FALSE);
     if(Irp == NULL) return STATUS_INSUFFICIENT_RESOURCES;
 
     KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
 
     RtlZeroMemory(FileInformation, Length);
     Irp->UserEvent = &kEvent;
     Irp->UserIosb = IoStatusBlock;
     Irp->UserBuffer = FileInformation;
     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
     Irp->Tail.Overlay.OriginalFileObject = FileObject;
     Irp->Overlay.AsynchronousParameters.UserApcRoutine = (PIO_APC_ROUTINE)NULL;
 
     IrpSp = IoGetNextIrpStackLocation(Irp);
     IrpSp->MajorFunction = IRP_MJ_DIRECTORY_CONTROL;
     IrpSp->MinorFunction = IRP_MN_QUERY_DIRECTORY;
     IrpSp->FileObject = FileObject;
     IrpSp->Flags = SL_RESTART_SCAN;
     IrpSp->Parameters.QueryDirectory.Length = Length;
     IrpSp->Parameters.QueryDirectory.FileName = FileName;
     IrpSp->Parameters.QueryDirectory.FileInformationClass = FileInformationClass;
 
     IoSetCompletionRoutine(Irp, IoCompletionRoutine, 0, TRUE, TRUE, TRUE);
     ntStatus = IoCallDriver(FileObject->Vpb->DeviceObject, Irp);
     if (ntStatus == STATUS_PENDING)
         KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0);
 
     return IoStatusBlock->Status;
}
 
NTSTATUS
IrpQueryInformationFile(
     IN PFILE_OBJECT  FileObject,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     OUT PVOID  FileInformation,
     IN ULONG  Length,
     IN FILE_INFORMATION_CLASS  FileInformationClass)
{
     NTSTATUS ntStatus;
     PIRP Irp;
     KEVENT kEvent;
     PIO_STACK_LOCATION IrpSp;
 
     if (FileObject->Vpb == 0 || FileObject->Vpb->DeviceObject == NULL)
         return STATUS_UNSUCCESSFUL;
 
     Irp = IoAllocateIrp(FileObject->Vpb->DeviceObject->StackSize, FALSE);
     if(Irp == NULL) return STATUS_INSUFFICIENT_RESOURCES;
 
     KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
 
     RtlZeroMemory(FileInformation, Length);
     Irp->AssociatedIrp.SystemBuffer = FileInformation;
     Irp->UserEvent = &kEvent;
     Irp->UserIosb = IoStatusBlock;
     Irp->RequestorMode = KernelMode;
     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
     Irp->Tail.Overlay.OriginalFileObject = FileObject;
 
     IrpSp = IoGetNextIrpStackLocation(Irp);
     IrpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
     IrpSp->DeviceObject = FileObject->Vpb->DeviceObject;
     IrpSp->FileObject = FileObject;
     IrpSp->Parameters.QueryFile.Length = Length;
     IrpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass;
 
     IoSetCompletionRoutine(Irp, IoCompletionRoutine, 0, TRUE, TRUE, TRUE);
     ntStatus = IoCallDriver(FileObject->Vpb->DeviceObject, Irp);
     if (ntStatus == STATUS_PENDING)
         KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0);
 
     return IoStatusBlock->Status;
}
 
NTSTATUS
IrpSetInformationFile(
     IN PFILE_OBJECT  FileObject,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     IN PVOID  FileInformation,
     IN ULONG  Length,
     IN FILE_INFORMATION_CLASS  FileInformationClass,
     IN BOOLEAN  ReplaceIfExists)
{
     NTSTATUS ntStatus;
     PIRP Irp;
     KEVENT kEvent;
     PIO_STACK_LOCATION IrpSp;
 
     if (FileObject->Vpb == 0 || FileObject->Vpb->DeviceObject == NULL)
         return STATUS_UNSUCCESSFUL;
 
     Irp = IoAllocateIrp(FileObject->Vpb->DeviceObject->StackSize, FALSE);
     if(Irp == NULL) return STATUS_INSUFFICIENT_RESOURCES;
 
     KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
 
     Irp->AssociatedIrp.SystemBuffer = FileInformation;
     Irp->UserEvent = &kEvent;
     Irp->UserIosb = IoStatusBlock;
     Irp->RequestorMode = KernelMode;
     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
     Irp->Tail.Overlay.OriginalFileObject = FileObject;
 
     IrpSp = IoGetNextIrpStackLocation(Irp);
     IrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
     IrpSp->DeviceObject = FileObject->Vpb->DeviceObject;
     IrpSp->FileObject = FileObject;
     IrpSp->Parameters.SetFile.ReplaceIfExists = ReplaceIfExists;
     IrpSp->Parameters.SetFile.FileObject = FileObject;
     IrpSp->Parameters.SetFile.AdvanceOnly = FALSE;
     IrpSp->Parameters.SetFile.Length = Length;
     IrpSp->Parameters.SetFile.FileInformationClass = FileInformationClass;
 
     IoSetCompletionRoutine(Irp, IoCompletionRoutine, 0, TRUE, TRUE, TRUE);
     ntStatus = IoCallDriver(FileObject->Vpb->DeviceObject, Irp);
     if (ntStatus == STATUS_PENDING)
         KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0);
 
     return IoStatusBlock->Status;
}
 
NTSTATUS
IrpReadFile(
     IN PFILE_OBJECT  FileObject,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     OUT PVOID  Buffer,
     IN ULONG  Length,
     IN PLARGE_INTEGER  ByteOffset  OPTIONAL)
{
     NTSTATUS ntStatus;
     PIRP Irp;
     KEVENT kEvent;
     PIO_STACK_LOCATION IrpSp;
 
     if (FileObject->Vpb == 0 || FileObject->Vpb->DeviceObject == NULL)
         return STATUS_UNSUCCESSFUL;
 
     if(ByteOffset == NULL)
     {
         if(!(FileObject->Flags & FO_SYNCHRONOUS_IO))
              return STATUS_INVALID_PARAMETER;
         ByteOffset = &FileObject->CurrentByteOffset;
     }
 
     Irp = IoAllocateIrp(FileObject->Vpb->DeviceObject->StackSize, FALSE);
     if(Irp == NULL) return STATUS_INSUFFICIENT_RESOURCES;
 
     RtlZeroMemory(Buffer, Length);
     if(FileObject->DeviceObject->Flags & DO_BUFFERED_IO)
     {
         Irp->AssociatedIrp.SystemBuffer = Buffer;
     }
     else if(FileObject->DeviceObject->Flags & DO_DIRECT_IO)
     {
         Irp->MdlAddress = IoAllocateMdl(Buffer, Length, 0, 0, 0);
         if (Irp->MdlAddress == NULL)
         {
              IoFreeIrp(Irp);
              return STATUS_INSUFFICIENT_RESOURCES;
         }
         MmBuildMdlForNonPagedPool(Irp->MdlAddress);
     }
     else
     {
         Irp->UserBuffer = Buffer;
     }
 
     KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
 
     Irp->UserEvent = &kEvent;
     Irp->UserIosb = IoStatusBlock;
     Irp->RequestorMode = KernelMode;
     Irp->Flags = IRP_READ_OPERATION;
     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
     Irp->Tail.Overlay.OriginalFileObject = FileObject;
 
     IrpSp = IoGetNextIrpStackLocation(Irp);
     IrpSp->MajorFunction = IRP_MJ_READ;
     IrpSp->MinorFunction = IRP_MN_NORMAL;
     IrpSp->DeviceObject = FileObject->Vpb->DeviceObject;
     IrpSp->FileObject = FileObject;
     IrpSp->Parameters.Read.Length = Length;
     IrpSp->Parameters.Read.ByteOffset = *ByteOffset;
 
     IoSetCompletionRoutine(Irp, IoCompletionRoutine, 0, TRUE, TRUE, TRUE);
     ntStatus = IoCallDriver(FileObject->Vpb->DeviceObject, Irp);
     if (ntStatus == STATUS_PENDING)
         KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, 0);
 
     return IoStatusBlock->Status;
}
 
NTSTATUS
IrpWriteFile(
     IN PFILE_OBJECT  FileObject,
     OUT PIO_STATUS_BLOCK  IoStatusBlock,
     IN PVOID  Buffer,
     IN ULONG  Length,
     IN PLARGE_INTEGER  ByteOffset  OPTIONAL)
{
     NTSTATUS ntStatus;
     PIRP Irp;
     KEVENT kEvent;
     PIO_STACK_LOCATION IrpSp;
 
     if (FileObject->Vpb == 0 || FileObject->Vpb->DeviceObject == NULL)
         return STATUS_UNSUCCESSFUL;
 
     if (ByteOffset == NULL)
     {
         if (!(FileObject->Flags & FO_SYNCHRONOUS_IO))
              return STATUS_INVALID_PARAMETER;
         ByteOffset = &FileObject->CurrentByteOffset;
     }
 
     Irp = IoAllocateIrp(FileObject->Vpb->DeviceObject->StackSize, FALSE);
     if (Irp == NULL) return STATUS_INSUFFICIENT_RESOURCES;
 
     if(FileObject->DeviceObject->Flags & DO_BUFFERED_IO)
     {
         Irp->AssociatedIrp.SystemBuffer = Buffer;
     }
     else
     {
         Irp->MdlAddress = IoAllocateMdl(Buffer, Length, 0, 0, 0);
         if (Irp->MdlAddress == NULL)
         {
              IoFreeIrp(Irp);
              return STATUS_INSUFFICIENT_RESOURCES;
         }
         MmBuildMdlForNonPagedPool(Irp->MdlAddress);
     }
 
     KeInitializeEvent(&kEvent, SynchronizationEvent, FALSE);
 
     Irp->UserEvent = &kEvent;
     Irp->UserIosb = IoStatusBlock;
     Irp->RequestorMode = KernelMode;
     Irp->Flags = IRP_WRITE_OPERATION;
     Irp->Tail.Overlay.Thread = PsGetCurrentThread();
     Irp->Tail.Overlay.OriginalFileObject = FileObject;
 
     IrpSp = IoGetNextIrpStackLocation(Irp);
     IrpSp->MajorFunction = IRP_MJ_WRITE;
     IrpSp->MinorFunction = IRP_MN_NORMAL;
     IrpSp->DeviceObject = FileObject->Vpb->DeviceObject;
     IrpSp->FileObject = FileObject;
     IrpSp->Parameters.Write.Length = Length;
     IrpSp->Parameters.Write.ByteOffset = *ByteOffset;
 
     IoSetCompletionRoutine(Irp, IoCompletionRoutine, NULL, TRUE, TRUE, TRUE);
     ntStatus = IoCallDriver(FileObject->Vpb->DeviceObject, Irp);
 
     if (ntStatus == STATUS_PENDING)
         KeWaitForSingleObject(&kEvent, Executive, KernelMode, TRUE, NULL);
 
     return IoStatusBlock->Status;
}