www.pudn.com > FsTPM0.rar > SpecialIOFunction.cpp
#include "FsTPM.h"
// Used to set Object's flag
#ifndef SetFlag
#define SetFlag(x,f) ((x) |= (f))
#endif
// Used to clear Object's flag
#ifndef ClearFlag
#define ClearFlag(x,f) ((x) &= ~(f))
#endif
BOOL IsSomeSpecialFile( PWCHAR WideSource, PFILE_OBJECT pFileObject, PIO_STACK_LOCATION pCurrentIrpStack)
{
if ( /*(0==pFileObject->FileName.Length) ||*/
(wcsstr(WideSource,L"SYSTEM32\\CONFIG")!=0) ||
(wcsstr(WideSource,L"NTUSER.DAT.LOG")!=0) ||
(wcsstr(WideSource,L"PAGEFILE.SYS")!=0) ||
(wcsstr(WideSource,L"NTUSER.DAT")!=0) ||
(wcsstr(WideSource,L"SECURITY.LOG")!=0) ||
(wcsstr(WideSource,L"SOFTWARE.LOG")!=0) ||
(wcsstr(WideSource,L"SYSTEM.LOG")!=0) ||
(wcsstr(WideSource,L"DEFAULT.LOG")!=0) ||
(Is_Directory_File(pCurrentIrpStack->Parameters.Create.Options))
)
{
return TRUE;
}
return FALSE;
}
VOID
FsTPMGetFileStandardInformation(
PFILE_OBJECT FileObject,
PFILE_STANDARD_INFORMATION StandardInformation,
PIO_STATUS_BLOCK IoStatusBlock,
PDEVICE_OBJECT pDeviceObject
)
//++
// Function: FsTPMGetFileStandardInformation
//
// Description:
// Get a file's standard information
//
// Arguments:
// IN FileObject - Target file object
// OUT StandardInformation - Standard information pointer
// OUT IoStatusBlock - Point out whether this request is success.
// IN pDeviceObject - the Device below me
// Return value:
// None
//
// Notice :
// This function is provided by OSR
//--
{
PIRP irp;
KEVENT event;
PIO_STACK_LOCATION ioStackLocation;
PDEVICE_OBJECT fsdDevice=pDeviceObject;
//
// Start off on the right foot - zero the information block.
//
RtlZeroMemory(StandardInformation, sizeof(FILE_STANDARD_INFORMATION));
//
// Allocate an irp for this request. This could also come from a
// private pool, for instance.
//
irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
if (!irp) {
//
// Failure!
//
return;
}
irp->AssociatedIrp.SystemBuffer = StandardInformation;
irp->UserEvent = &event;
irp->UserIosb = IoStatusBlock;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject = FileObject;
irp->RequestorMode = KernelMode;
//
// Initialize the event
//
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
//
// Set up the I/O stack location.
//
ioStackLocation = IoGetNextIrpStackLocation(irp);
ioStackLocation->MajorFunction = IRP_MJ_QUERY_INFORMATION;
ioStackLocation->DeviceObject = fsdDevice;
ioStackLocation->FileObject = FileObject;
ioStackLocation->Parameters.QueryFile.Length = sizeof(FILE_STANDARD_INFORMATION);
ioStackLocation->Parameters.QueryFile.FileInformationClass = FileStandardInformation;
//
// Set the completion routine.
//
IoSetCompletionRoutine(irp, KfcIoCompletion, 0, TRUE, TRUE, TRUE);
//
// Send it to the FSD
//
(void) IoCallDriver(fsdDevice, irp);
//
// Wait for the I/O
//
KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
//
// Done!
//
return;
}
NTSTATUS
KfcIoCompletion(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context
)
//++
// Function: KfcIoCompletion
//
// Description:
// This routine is used to handle I/O (read OR write) completion
//
// Arguments:
// DeviceObject - not used
// Irp - the I/O operation being completed
// Context - not used
//
// Return value:
// STATUS_MORE_PROCESSING_REQUIRED
//
// Notice :
// This function is provided by OSR
//
// 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.
//
{
//
// Copy the status information back into the "user" IOSB.
//
*Irp->UserIosb = Irp->IoStatus;
//
// Set the user event - wakes up the mainline code doing this.
// So that we can jump out of KeWaitForSingleObject() in my routine
//
KeSetEvent(Irp->UserEvent, 0, FALSE);
//
// Free the IRP now that we are done with it.
//
IoFreeIrp(Irp);
//
// We return STATUS_MORE_PROCESSING_REQUIRED because this "magic" return value
// tells the I/O Manager that additional processing will be done by this driver
// to the IRP - in fact, it might (as it is in this case) already BE done - and
// the IRP cannot be completed.
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
VOID
FsTPMRead(
PFILE_OBJECT FileObject,
PLARGE_INTEGER Offset,
ULONG Length,
PMDL Mdl,
PIO_STATUS_BLOCK IoStatusBlock,
PDEVICE_OBJECT pDevice
)
//++
// Function: FsTPMRead
//
// Description:
// This routine is used to read the file object to memory discribed by MDL
//
// Arguments:
// PFILE_OBJECT FileObject,
// PLARGE_INTEGER Offset,
// ULONG Length,
// PMDL Mdl,
// PIO_STATUS_BLOCK IoStatusBlock
//
// Return value:
// None
//
// Notice :
// This function is provided by OSR
//
{
PIRP irp;
KEVENT event;
PIO_STACK_LOCATION ioStackLocation;
PDEVICE_OBJECT fsdDevice=pDevice;
//
// Set up the event we'll use.
//
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
//
// Allocate and build the IRP we'll be sending to the FSD.
//
irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
if (!irp) {
//
// Allocation failed, presumably due to memory allocation failure.
//
IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
IoStatusBlock->Information = 0;
}
irp->MdlAddress = Mdl;
irp->UserEvent = &event;
irp->UserIosb = IoStatusBlock;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject= FileObject;
irp->RequestorMode = KernelMode;
//
// Indicate that this is a READ operation.
//
irp->Flags = IRP_READ_OPERATION;
//
// Set up the next I/O stack location. These are the parameters
// that will be passed to the underlying driver.
//
ioStackLocation = IoGetNextIrpStackLocation(irp);
ioStackLocation->MajorFunction = IRP_MJ_READ;
ioStackLocation->MinorFunction = 0;
ioStackLocation->DeviceObject = fsdDevice;
ioStackLocation->FileObject = FileObject;
//
// We use a completion routine to keep the I/O Manager from doing
// "cleanup" on our IRP - like freeing our MDL.
//
IoSetCompletionRoutine(irp, KfcIoCompletion, 0, TRUE, TRUE, TRUE);
ioStackLocation->Parameters.Read.Length = Length;
ioStackLocation->Parameters.Read.ByteOffset = *Offset;
//
// Send it on. Ignore the return code.
//
(void) IoCallDriver(fsdDevice, irp);
//
// Wait for the I/O to complete.
//
KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
//
// Done. Return results are in the io status block.
//
return;
}
VOID
FsTPMSetFileAllocation(
PFILE_OBJECT FileObject,
PLARGE_INTEGER AllocationSize,
PIO_STATUS_BLOCK IoStatusBlock,
PDEVICE_OBJECT pDevice
)
//++
// Function: FsTPMSetFileAllocation
//
// Description:
// This routine sets a file's ALLOCATION size to the specified value.
// Note that this DOES NOT extend the file's EOF.
//
// Arguments:
// FileObject - the file on which to set the allocation size
// AllocationSize - the new allocation size
// IoStatusBlock - the results of this operation
//
// Return value:
// None
//
// Notice :
// This function is provided by OSR
//--
{
PIRP irp;
KEVENT event;
PIO_STACK_LOCATION ioStackLocation;
PDEVICE_OBJECT fsdDevice=pDevice;
//
// Allocate an irp for this request. This could also come from a
// private pool, for instance.
//
irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
if (!irp) {
//
// Failure!
//
return;
}
irp->AssociatedIrp.SystemBuffer = AllocationSize;
irp->UserEvent = &event;
irp->UserIosb = IoStatusBlock;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject = FileObject;
irp->RequestorMode = KernelMode;
//
// Initialize the event
//
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
//
// Set up the I/O stack location.
//
ioStackLocation = IoGetNextIrpStackLocation(irp);
ioStackLocation->MajorFunction = IRP_MJ_SET_INFORMATION;
ioStackLocation->DeviceObject = fsdDevice;
ioStackLocation->FileObject = FileObject;
ioStackLocation->Parameters.SetFile.Length = sizeof(LARGE_INTEGER);
ioStackLocation->Parameters.SetFile.FileInformationClass = FileAllocationInformation;
ioStackLocation->Parameters.SetFile.FileObject = 0; // not used for allocation
ioStackLocation->Parameters.SetFile.AdvanceOnly = FALSE;
//
// Set the completion routine.
//
IoSetCompletionRoutine(irp, KfcIoCompletion, 0, TRUE, TRUE, TRUE);
//
// Send it to the FSD
//
(void) IoCallDriver(fsdDevice, irp);
//
// Wait for the I/O
//
KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
//
// Done!
//
return;
}
VOID
FsTPMWrite(
PFILE_OBJECT FileObject,
PLARGE_INTEGER Offset,
ULONG Length,
PMDL Mdl,
PIO_STATUS_BLOCK IoStatusBlock,
PDEVICE_OBJECT pDevice
)
//++
// Function: FsTPMWrite
//
// Description:
// This routine is used to write to the file object from memory discribed by MDL
//
// Arguments:
// PFILE_OBJECT FileObject,
// PLARGE_INTEGER Offset,
// ULONG Length,
// PMDL Mdl,
// PIO_STATUS_BLOCK IoStatusBlock
//
// Return value:
// None
//
// Notice :
// This function is provided by OSR
//
{
PIRP irp;
KEVENT event;
PIO_STACK_LOCATION ioStackLocation;
PDEVICE_OBJECT fsdDevice =pDevice;
//
// Set up the event we'll use.
//
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
//
// Allocate and build the IRP we'll be sending to the FSD.
//
irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
if (!irp) {
//
// Allocation failed, presumably due to memory allocation failure.
//
IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
IoStatusBlock->Information = 0;
}
irp->MdlAddress = Mdl;
irp->UserEvent = &event;
irp->UserIosb = IoStatusBlock;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject= FileObject;
irp->RequestorMode = KernelMode;
//
// Indicate that this is a WRITE operation.
//
irp->Flags = IRP_WRITE_OPERATION;
//
// Set up the next I/O stack location. These are the parameters
// that will be passed to the underlying driver.
//
ioStackLocation = IoGetNextIrpStackLocation(irp);
ioStackLocation->MajorFunction = IRP_MJ_WRITE;
ioStackLocation->MinorFunction = 0;
ioStackLocation->DeviceObject = fsdDevice;
ioStackLocation->FileObject = FileObject;
//
// We use a completion routine to keep the I/O Manager from doing
// "cleanup" on our IRP - like freeing our MDL.
//
IoSetCompletionRoutine(irp, KfcIoCompletion, 0, TRUE, TRUE, TRUE);
ioStackLocation->Parameters.Write.Length = Length;
ioStackLocation->Parameters.Write.ByteOffset = *Offset;
//
// Send it on. Ignore the return code.
//
(void) IoCallDriver(fsdDevice, irp);
//
// Wait for the I/O to complete.
//
KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
//
// Done. Return results are in the io status block.
//
return;
}
//-----------------------------------------------------------------------------
/*++
The following functions
Abstract:
This module implements routines to support synchronous API calls to
the next lower file system driver.
Revision History:
02-01-2002 : created
Note:
Thank OSR and Mr. Paul for providing some useful information
--*/
VOID FsTPMReferenceDeviceAndVpb(IN PFILE_OBJECT FileObject)
{
// NTSTATUS Status;
PDEVICE_OBJECT RealDevice;
PVPB Vpb;
//
// Copy RealDevice and Vpb into local variables to make things easier.
//
RealDevice = FileObject->DeviceObject;
Vpb = FileObject->Vpb;
//ASSERT(Vpb != NULL ? RealDevice->Vpb != NULL : RealDevice->Vpb == NULL);
//
// Increment RealDevice's reference count.
//
ExInterlockedAddUlong((unsigned long *)&RealDevice->ReferenceCount, 1, IopDatabaseLock);
if (Vpb)
{
KIRQL Irql;
ASSERT(FlagOn(Vpb->Flags, VPB_MOUNTED) && !FlagOn(Vpb->Flags, VPB_LOCKED));
//
// Increment Vpb's reference count, if one exists.
//
IoAcquireVpbSpinLock(&Irql);
Vpb->ReferenceCount++;
IoReleaseVpbSpinLock(Irql);
}
}
NTSTATUS
FsTPMQueryInformationFile (
IN PVCB Vcb,
IN PFILE_OBJECT FileObject,
IN FILE_INFORMATION_CLASS FileInformationClass,
OUT PVOID FileInformation,
IN ULONG Length,
OUT PULONG ResultLength
)
{
PDEVICE_OBJECT DeviceObject = Vcb->NextLowerDevice;
PFAST_IO_DISPATCH FastIoDispatch = DeviceObject->DriverObject->FastIoDispatch;
NTSTATUS Status;
KEVENT Event;
IO_STATUS_BLOCK IoStatus;
PIRP Irp;
PIO_STACK_LOCATION NextIrpSp;
//
// Try to do this request through the FastIo if possible.
//
if (FastIoDispatch &&
(FileInformationClass == FileBasicInformation && FastIoDispatch->FastIoQueryBasicInfo) ||
(FileInformationClass == FileStandardInformation && FastIoDispatch->FastIoQueryStandardInfo))
{
//
// Call some FastIo routine and remember its return value.
//
BOOLEAN Done;
if (FileInformationClass == FileBasicInformation)
{
Done = FastIoDispatch->FastIoQueryBasicInfo( FileObject,TRUE,(PFILE_BASIC_INFORMATION)FileInformation,&IoStatus,DeviceObject );
}
else
{
Done = FastIoDispatch->FastIoQueryStandardInfo( FileObject,TRUE,(PFILE_STANDARD_INFORMATION)FileInformation,&IoStatus,DeviceObject );
}
//
// If we are done return to the caller with request's status.
//
if (Done)
{
*ResultLength = IoStatus.Information;
return IoStatus.Status;
}
}
//
// Now we must go through the standard IRP path so
// initialize event on which we will occasionaly wait.
//
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
//
// Allocate the IRP with appropriate number of stack locations.
//
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Set basic fields in Irp like an OriginalFileObject, Thread and so on.
// Also Flags are set to make this request synchronous and buffered.
//
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->RequestorMode = KernelMode;
Irp->UserIosb = &IoStatus;
Irp->UserEvent = &Event;
SetFlag(Irp->Flags, IRP_SYNCHRONOUS_API | IRP_BUFFERED_IO);
//
// Set basic fields in the next stack location like a MajorFunction
// and FileObject.
//
NextIrpSp = IoGetNextIrpStackLocation(Irp);
NextIrpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
NextIrpSp->FileObject = FileObject;
//
// Set caller's parameters for this request like Length, Buffer
// and FileInformationClass.
//
NextIrpSp->Parameters.QueryFile.Length = Length;
NextIrpSp->Parameters.QueryFile.FileInformationClass = FileInformationClass;
Irp->AssociatedIrp.SystemBuffer = FileInformation;
//
// Before we call the FSD to process this request we must set
// completion routine which will be responsible to free the Irp
// and to do some little postprocessing.
//
IoSetCompletionRoutine( Irp,FsTPMSynchronousApiCompletion,NULL,TRUE,TRUE,TRUE );
//
// Call the File System Driver to do the task requested by caller.
//
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
(VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
//
// Return to our caller with request's status.
//
*ResultLength = IoStatus.Information;
return Status;
}
//
//
//
NTSTATUS
FsTPMSetInformationFile (
IN PVCB Vcb,
IN PFILE_OBJECT FileObject,
IN FILE_INFORMATION_CLASS FileInformationClass,
IN PVOID FileInformation,
IN ULONG Length
)
{
PDEVICE_OBJECT DeviceObject = Vcb->NextLowerDevice;
NTSTATUS Status;
KEVENT Event;
IO_STATUS_BLOCK IoStatus;
PIRP Irp;
PIO_STACK_LOCATION NextIrpSp;
//
// Initialize event on which we will occasionaly wait.
//
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
//
// Allocate the IRP with appropriate number of stack locations.
//
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Set basic fields in Irp like an OriginalFileObject, Thread and so on.
// Also Flags are set to make this request synchronous and buffered.
//
Irp->Tail.Overlay.OriginalFileObject = FileObject;
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->RequestorMode = KernelMode;
Irp->UserIosb = &IoStatus;
Irp->UserEvent = &Event;
SetFlag(Irp->Flags, IRP_SYNCHRONOUS_API | IRP_BUFFERED_IO);
//
// Set basic fields in the next stack location like a MajorFunction
// and FileObject.
//
NextIrpSp = IoGetNextIrpStackLocation(Irp);
NextIrpSp->MajorFunction = IRP_MJ_SET_INFORMATION;
NextIrpSp->FileObject = FileObject;
//
// Set caller's parameters for this request like Length, Buffer
// and FileInformationClass.
//
NextIrpSp->Parameters.SetFile.Length = Length;
NextIrpSp->Parameters.SetFile.FileInformationClass = FileInformationClass;
Irp->AssociatedIrp.SystemBuffer = FileInformation;
//
// Do some preprocessing for Rename and Link requests.
//
ASSERT((FileInformationClass <= FileMaximumInformation) &&
(FileInformationClass != FileModeInformation) &&
(FileInformationClass != FileObjectIdInformation) &&
(FileInformationClass != FileMoveClusterInformation));
if (FileInformationClass == FileRenameInformation ||
FileInformationClass == FileLinkInformation)
{
PFILE_RENAME_INFORMATION RenameInfo = (PFILE_RENAME_INFORMATION)FileInformation;
ASSERT(RenameInfo->FileNameLength != 0 && RenameInfo->RootDirectory == NULL);
NextIrpSp->Parameters.SetFile.ReplaceIfExists = RenameInfo->ReplaceIfExists;
}
//
// Before we call the FSD to process this request we must set
// completion routine which will be responsible to free the Irp
// and to do some little postprocessing.
//
IoSetCompletionRoutine( Irp,FsTPMSynchronousApiCompletion,NULL,TRUE,TRUE,TRUE );
//
// Call the File System Driver to do the task requested by caller.
//
Status = IoCallDriver(DeviceObject, Irp);
if (Status == STATUS_PENDING)
{
(VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
//
// Return to our caller with request's status.
//
return Status;
}
//
//
//
NTSTATUS
FsTPMSynchronousApiCompletion (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
{
//ASSERT(DeviceObject == NULL && Context == NULL);
//
// If there is an AuxiliaryBuffer we have to free it.
//
if (Irp->Tail.Overlay.AuxiliaryBuffer != NULL)
{
ExFreePool(Irp->Tail.Overlay.AuxiliaryBuffer);
}
//
// If there is a Mdl associated we have to deal with it
//
if (Irp->MdlAddress)
{
PMDL Mdl;
KdPrint(("AGFS: Buffered requests should not have an MDL!\n"));
KdBreakPoint();
//
//
//
Mdl = Irp->MdlAddress;
while (Mdl != NULL)
{
MmUnlockPages(Mdl);
Mdl = Mdl->Next;
}
IoFreeMdl(Irp->MdlAddress);
}
//
// We must copy the IoStatus to UserIosb and set
// the user event so the caller wakes up.
//
*Irp->UserIosb = Irp->IoStatus;
ASSERT(Irp->UserEvent != NULL);
KeSetEvent(Irp->UserEvent, EVENT_INCREMENT, FALSE);
//
// Finally free the Irp.
//
IoFreeIrp(Irp);
//
// Prevent the IoCompleteRequest to do anything with
// this already freed Irp.
//
return STATUS_MORE_PROCESSING_REQUIRED;
}
#define try_return(X) X; goto try_exit
NTSTATUS
FsTPMCreateFile (
IN PVCB Vcb,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN PLARGE_INTEGER AllocationSize OPTIONAL,
IN ULONG FileAttributes,
IN ULONG ShareAccess,
IN ULONG Disposition,
IN ULONG CreateOptions,
IN PVOID EaBuffer OPTIONAL,
IN ULONG EaLength,
IN ULONG Options,
OUT ULONG *Information,
OUT PFILE_OBJECT FileObject,
OUT HANDLE *FileHandle OPTIONAL
)
{
PIRP Irp = NULL;
PFILE_OBJECT NewFileObject = NULL;
PDEVICE_OBJECT RealDevice = Vcb->RealDevice;
PDEVICE_OBJECT DeviceObject = Vcb->NextLowerDevice;
// PVPB Vpb;
IO_SECURITY_CONTEXT SecurityContext;
ACCESS_STATE AccessState;
PIO_STACK_LOCATION NextIrpSp;
IO_STATUS_BLOCK IoStatus;
OBJECT_ATTRIBUTES ObjAttr;
NTSTATUS Status;
KEVENT Event;
LARGE_INTEGER AllocSize;
BOOLEAN CreatedAccessState = FALSE;
// <<<<<<<<<<<<<<<<<<<<<<>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
// I have no document to introduce AUXDATA
// Smith, Joel said: Note the pAuxData variable.
// Obviously, a 1k nonpaged buffer is overkill, but I haven't
// yet bothered to try to figure out what SeCreateAccessState
// puts in here.
// But I have seen another articles which said AUX_DATA just used to
// describe that the AUX device, you can see afximpl.h and
// http://www.sources.ru/cpp/mfc/t3552.htm .
//
ULONG *pAuxData=(ULONG*)ExAllocatePool(NonPagedPool, 1024);
memset(pAuxData, 0, 1024);
__try
{
//
// Build AccessState for this create request.
//
Status = SeCreateAccessState( &AccessState,pAuxData,DesiredAccess,IoGetFileObjectGenericMapping() );
if (!NT_SUCCESS(Status))
{
try_return(Status);
}
CreatedAccessState = TRUE;
//
// Initialize event on which we will occasionaly wait.
//
KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
//
// Allocate an IRP with appropriate number of stack locations.
//
Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
if (!Irp)
{
try_return(Status = STATUS_INSUFFICIENT_RESOURCES);
}
//
// Fill in basic Irp fields like a Thread, RequestorMode and Flags.
//
Irp->Tail.Overlay.Thread = PsGetCurrentThread();
Irp->RequestorMode = KernelMode;
SetFlag(Irp->Flags, IRP_CREATE_OPERATION | IRP_SYNCHRONOUS_API);
//
// Fill in the SecurityContext for this create request.
//
SecurityContext.SecurityQos = (PSECURITY_QUALITY_OF_SERVICE)ObjectAttributes->SecurityQualityOfService;
SecurityContext.AccessState = &AccessState;
SecurityContext.DesiredAccess = DesiredAccess;
SecurityContext.FullCreateOptions = CreateOptions;
//
// Fill in basic fields in the next stack location.
//
NextIrpSp = IoGetNextIrpStackLocation(Irp);
NextIrpSp->Control = 0;
NextIrpSp->MajorFunction = IRP_MJ_CREATE;
NextIrpSp->Flags = (UCHAR)Options;
if (!FlagOn(ObjectAttributes->Attributes, OBJ_CASE_INSENSITIVE))
{
SetFlag(NextIrpSp->Flags, SL_CASE_SENSITIVE);
}
//
// Fill in the AllocationSize and EaBuffer.
//
AllocSize.QuadPart = AllocationSize ? AllocationSize->QuadPart : 0;
Irp->Overlay.AllocationSize.QuadPart = AllocSize.QuadPart;
Irp->AssociatedIrp.SystemBuffer = EaBuffer;
//
// Fill in request parameters in next stack location.
//
NextIrpSp->Parameters.Create.Options = (CreateOptions & 0xFFFFFF) | (Disposition << 24);
NextIrpSp->Parameters.Create.FileAttributes = (USHORT)FileAttributes;
NextIrpSp->Parameters.Create.ShareAccess = (USHORT)ShareAccess;
NextIrpSp->Parameters.Create.SecurityContext = &SecurityContext;
NextIrpSp->Parameters.Create.EaLength = EaLength;
//
// Fill in other fields in Irp.
//
Irp->UserIosb = &IoStatus;
Irp->UserEvent = &Event;
Irp->MdlAddress = NULL;
Irp->PendingReturned = FALSE;
Irp->Cancel = FALSE;
Irp->CancelRoutine = NULL;
Irp->Tail.Overlay.AuxiliaryBuffer = NULL;
//
// Create new file object.
//
InitializeObjectAttributes(&ObjAttr, NULL,ObjectAttributes->Attributes, 0, NULL);
Status = ObCreateObject( KernelMode, *IoFileObjectType,&ObjAttr,KernelMode,0,sizeof(FILE_OBJECT),0,0,(void**)&NewFileObject );
if (!NT_SUCCESS(Status))
{
try_return(Status);
}
//
// Zero the file object and initialize type and size.
//
RtlZeroMemory(NewFileObject, sizeof(FILE_OBJECT));
NewFileObject->Type = IO_TYPE_FILE;
NewFileObject->Size = sizeof(FILE_OBJECT);
//
// Fill in the RelatedFileObject as a RootDirectory.
//
NewFileObject->RelatedFileObject = (PFILE_OBJECT)ObjectAttributes->RootDirectory;
//
// Initialize some more things when the file is for synchronous access.
//
if (FlagOn(CreateOptions, FILE_SYNCHRONOUS_IO_ALERT | FILE_SYNCHRONOUS_IO_NONALERT))
{
SetFlag(NewFileObject->Flags, FO_SYNCHRONOUS_IO);
if (FlagOn(CreateOptions, FILE_SYNCHRONOUS_IO_ALERT))
{
SetFlag(NewFileObject->Flags, FO_ALERTABLE_IO);
}
KeInitializeEvent(&NewFileObject->Lock, SynchronizationEvent, FALSE);
NewFileObject->Waiters = 0;
NewFileObject->CurrentByteOffset.QuadPart = 0;
}
//
// Set some file object flags with respect to CreateOptions.
//
if (FlagOn(CreateOptions, FILE_NO_INTERMEDIATE_BUFFERING))
{
SetFlag(NewFileObject->Flags, FO_NO_INTERMEDIATE_BUFFERING);
}
if (FlagOn(CreateOptions, FILE_WRITE_THROUGH))
{
SetFlag(NewFileObject->Flags, FO_WRITE_THROUGH);
}
if (FlagOn(CreateOptions, FILE_SEQUENTIAL_ONLY))
{
SetFlag(NewFileObject->Flags, FO_SEQUENTIAL_ONLY);
}
if (!FlagOn(ObjectAttributes->Attributes, OBJ_CASE_INSENSITIVE))
{
SetFlag(NewFileObject->Flags, FO_OPENED_CASE_SENSITIVE);
}
//
// Initialize the DeviceObject field in file object.
//
NewFileObject->DeviceObject = RealDevice;
//
// If the caller requests no handle we must insert the
// file object at this time.
//
if (FileHandle == NULL)
{
HANDLE Handle;
//
// Insert the file object to the Object Manager
// requesting one additional reference.
//
Status = ObInsertObject( NewFileObject,NULL,DesiredAccess,1,(PVOID*)&NewFileObject,&Handle );
if (!NT_SUCCESS(Status))
{
try_return(Status);
}
//
// Close the handle (one reference remains).
//
Status = NtClose(Handle);
ASSERT(NT_SUCCESS(Status));
ClearFlag(NewFileObject->Flags, FO_HANDLE_CREATED);
}
//
// Associate the NewFileObject with the Irp
//
Irp->Tail.Overlay.OriginalFileObject = NewFileObject;
NextIrpSp->FileObject = NewFileObject;
//
// If the ObjectAttributes contains some name we must
// make a copy for the file object.
//
if (ObjectAttributes->ObjectName->Length)
{
PUNICODE_STRING FileName = ObjectAttributes->ObjectName;
if (FileName->Length < 0x38)
{
NewFileObject->FileName.MaximumLength = 0x38;
}
else if (FileName->Length < 0x78)
{
NewFileObject->FileName.MaximumLength = 0x78;
}
else if (FileName->Length < 0xF8)
{
NewFileObject->FileName.MaximumLength = 0xF8;
}
else
{
NewFileObject->FileName.MaximumLength = FileName->Length;
}
NewFileObject->FileName.Buffer =(unsigned short *)ExAllocatePool(NonPagedPool, NewFileObject->FileName.MaximumLength);
if (!NewFileObject->FileName.Buffer)
{
try_return(Status = STATUS_INSUFFICIENT_RESOURCES);
}
}
NewFileObject->Vpb=Vcb->pVpb;
RtlCopyUnicodeString(&NewFileObject->FileName, ObjectAttributes->ObjectName);
KeInitializeEvent(&NewFileObject->Event, NotificationEvent, FALSE);
//
// Before we call the FSD to process this request we must set
// completion routine which will be responsible to free the Irp
// and to do some little postprocessing.
//
IoSetCompletionRoutine( Irp,FsTPMSynchronousApiCompletion,NULL,TRUE,TRUE,TRUE );
//
// Call the File System Driver to do the task requested by caller.
//
Status = IoCallDriver(Vcb->pVpb->DeviceObject, Irp);
Irp = NULL;
if (Status == STATUS_PENDING)
{
(VOID)KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
Status = IoStatus.Status;
}
if (!NT_SUCCESS(Status))
{
try_return(Status);
}
ASSERT(Status != STATUS_REPARSE);
//
// Return desired FileObject and Information.
//
FileObject = NewFileObject;
*Information = IoStatus.Information;
//
// If the caller requests handle now is the right time
// to insert the file object into Object Manager.
//
if (FileHandle != NULL)
{
Status = ObInsertObject( NewFileObject,NULL,DesiredAccess,0,NULL,FileHandle );
ASSERT(NT_SUCCESS(Status));
SetFlag(NewFileObject->Flags, FO_HANDLE_CREATED);
}
try_exit:NOTHING;
}
__finally
{
//
// Unwind neccessary things
//
// ASSERT(!AbnormalTermination()); //<<<<<<<<<<<<FileName.Length)
{
ExFreePool(NewFileObject->FileName.Buffer);
NewFileObject->FileName.Length = 0;
}
NewFileObject->DeviceObject = NULL;
// ASSERT(ObGetObjectPointerCount(NewFileObject) == 1);
ObDereferenceObject(NewFileObject);
}
}
else
{
FsTPMReferenceDeviceAndVpb(NewFileObject);
}
ExFreePool(pAuxData);
}
return Status;
}
//
// 本函数用于创建目录,可以有如下形式的参数: C:\ , C:\WINDOWS\ , C:\WINDOWS\A.TXT ,注意 完整的目录应最后至少有一个"\ "
// 若其后还跟有文件名,本函数可以忽略文件名
//
NTSTATUS
FsTPMCreateDirectory(
const WCHAR *pDir
)
{
FILE_OBJECT DirectoryFileObject;
HANDLE DirectoryHandle;
NTSTATUS ntStatus;
UNICODE_STRING Uni_Dir;
OBJECT_ATTRIBUTES DirectoryAttributes;
int Layer=-1,Len=FsTPMwcslen(pDir),pos,TmpLayer;
ULONG ThrowInf; // We don't want to see the value of the returned informatiom
UNICODE_STRING UDir={0};
// So throw it.
while (Pos=Len) || (L'\\'==pDir[++pos] && TmpLayer==0)))
if (L'\\'==pDir[pos])
--TmpLayer;
if (pos>=Len)
break;
ASSERT((pos>=0 && pos<=Len));
pos++;
Uni_Dir.Buffer=(PWCHAR)ExAllocatePool(PagedPool,(pos+1)*sizeof(WCHAR));
ASSERT((Uni_Dir.Buffer!=NULL));
Uni_Dir.MaximumLength=Uni_Dir.Length=(pos+1)*sizeof(WCHAR);
RtlCopyMemory(Uni_Dir.Buffer,pDir,(pos+1)*sizeof(WCHAR));
Uni_Dir.Buffer[pos]=0;
RtlInitUnicodeString(&UDir,&(Uni_Dir.Buffer[2]));
// Then we should initialize the file object's attributes
InitializeObjectAttributes(
&DirectoryAttributes,
&UDir,
OBJ_CASE_INSENSITIVE,
NULL, NULL
);
ntStatus=FsTPMCreateFile(&(((PHOOK_EXTENSION)(DriveHookDevices[pDir[0]-L'A']->DeviceExtension))->Vcb),
FILE_READ_DATA|SYNCHRONIZE|FILE_WRITE_DATA,
&DirectoryAttributes,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN_IF ,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE|FILE_NO_INTERMEDIATE_BUFFERING,
NULL,
0,
FILE_SYNCHRONOUS_IO_NONALERT|FILE_DIRECTORY_FILE|FILE_NO_INTERMEDIATE_BUFFERING,
&ThrowInf,
&DirectoryFileObject,
&DirectoryHandle
);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Create %S Failed! Reason:",Uni_Dir.Buffer));
ErrorString(ntStatus);
ExFreePool(Uni_Dir.Buffer);
return ntStatus;
}
NtClose(DirectoryHandle);
ExFreePool(Uni_Dir.Buffer);
}
return STATUS_SUCCESS;
}
//
// 注意:pAnsiString 要求在函数调用前已经分配好空间
//
NTSTATUS
GetFileFullNameByObjectA(
IN PFILE_OBJECT FileObject,
IN PHOOK_EXTENSION hookExt,
IN OUT PCHAR pAnsiString,
IN int StringLength
)
{
CHAR CUFileName[512]={0};
CHAR Temp[512]={0};
int ret;
PFILE_OBJECT RelateObject;
ASSERT(pAnsiString!=NULL);
ret=_snprintf(CUFileName,511,"%S",FileObject->FileName.Buffer);
if (ret<0)
{
return (!STATUS_SUCCESS);
}
RelateObject=FileObject->RelatedFileObject;
if ('\\'!=CUFileName[0] && NULL!=RelateObject &&
NULL!=RelateObject->FileName.Buffer && 0!=RelateObject->FileName.Length)
{
if (RelateObject->FileName.Buffer[RelateObject->FileName.Length/2-1]==L'\\' )
{
_snprintf(Temp,511,"%S%s",RelateObject->FileName.Buffer,CUFileName);
copy_inA(CUFileName,512,Temp);
}
else
{
_snprintf(Temp,511,"%S\\%s",RelateObject->FileName.Buffer,CUFileName);
copy_inA(CUFileName,512,Temp);
}
}
if ('\\'!=CUFileName[0])
{
_snprintf(Temp,511,"X:\\%s",CUFileName);
copy_inA(CUFileName,512,Temp);
}
else
{
_snprintf(Temp,511,"X:%s",CUFileName);
copy_inA(CUFileName,512,Temp);
}
ASSERT((CUFileName[2]=='\\' && CUFileName[3]!='\\'));
CUFileName[0]=hookExt->LogicalDrive;
ret=_snprintf(pAnsiString,StringLength,"%s",CUFileName);
if (ret<0)
return (!STATUS_SUCCESS);
else
return (STATUS_SUCCESS);
}
//
// 注意:pWString 要求在函数调用前已经分配好空间
//
NTSTATUS
GetFileFullNameByObjectW(
IN PFILE_OBJECT FileObject,
IN PHOOK_EXTENSION hookExt,
IN OUT WCHAR * pWString,
IN int StringLength
)
{
WCHAR Temp[256];
WCHAR CUFileName[256]={0};
int ret=_snwprintf(CUFileName,255,L"%s",FileObject->FileName.Buffer);
PFILE_OBJECT RelateObject;
ASSERT(pWString!=NULL);
if (ret<0)
{
return (!STATUS_SUCCESS);
}
RelateObject=FileObject->RelatedFileObject;
if (L'\\'!=CUFileName[0] && NULL!=RelateObject &&
NULL!=RelateObject->FileName.Buffer && 0!=RelateObject->FileName.Length)
{
if (RelateObject->FileName.Buffer[RelateObject->FileName.Length/2-1]==L'\\' )
{
_snwprintf(Temp,255,L"%s%s",RelateObject->FileName.Buffer,CUFileName);
copy_inW(CUFileName,255,Temp);
}
else
{
_snwprintf(Temp,255,L"%s\\%s",RelateObject->FileName.Buffer,CUFileName);
copy_inW(CUFileName,255,Temp);
}
}
if (L'\\'!=CUFileName[0])
{
_snwprintf(Temp,255,L"X:\\%s",CUFileName);
copy_inW(CUFileName,255,Temp);
}
else
{
_snwprintf(Temp,255,L"X:%s",CUFileName);
copy_inW(CUFileName,255,Temp);
}
ASSERT((CUFileName[2]==L'\\' && CUFileName[3]!=L'\\'));
CUFileName[0]=(WCHAR)hookExt->LogicalDrive;
ret=_snwprintf(pWString,StringLength-1,L"%s",CUFileName);
if (ret<0)
return (!STATUS_SUCCESS);
else
return (STATUS_SUCCESS);
}
BOOL
Is_Exist_File(
PHOOK_EXTENSION pHookExt,
PFILE_OBJECT pFileObject
)
{
WCHAR WTarget[512]={0};
UNICODE_STRING CUTarget;
PFILE_OBJECT pTargetFileObject=NULL;
HANDLE TargetFileHandle;
FILE_OBJECT TargetFileObject;
VCB TargetVCB;
OBJECT_ATTRIBUTES TargetAttributes;
ULONG ThrowInf; // We don't want to see the value of the returned informatiom
// So throw it.
NTSTATUS ntStatus;
RtlInitUnicodeString(&CUTarget,WTarget);
CUTarget.MaximumLength=1024;
_snwprintf(WTarget,511,L"X:%s",pFileObject->FileName.Buffer);
WTarget[0]=(WCHAR)pHookExt->LogicalDrive;
// Build VCB. here , the next lower device and real device are the same
TargetVCB=pHookExt->Vcb;
// Then we should initialize the file object's attributes
InitializeObjectAttributes(
&TargetAttributes,
&CUTarget,
OBJ_CASE_INSENSITIVE,
NULL, NULL
);
ntStatus=FsTPMCreateFile(&TargetVCB,
FILE_READ_DATA|SYNCHRONIZE|FILE_WRITE_DATA,
&TargetAttributes,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN ,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0,
FILE_SYNCHRONOUS_IO_NONALERT,
&ThrowInf,
&TargetFileObject,
&TargetFileHandle
);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Create Target File Failed!\n"));
ZwClose(TargetFileHandle);
return FALSE;
}
ZwClose(TargetFileHandle);
ObDereferenceObject( &TargetFileObject );
return TRUE;
}
BOOL
Is_Directory_File(
ULONG Options
)
{
if (Options & FILE_DIRECTORY_FILE)
return TRUE;
else
return FALSE;
}
//
//TargetFileName like C:\A.TXT , SourceFileName is so
//
NTSTATUS
FsTPMCopyFileByName(
IN WCHAR* TargetFileName,
IN WCHAR* SourceFileName,
IN PFILE_OBJECT pSourceFileObject
)
{
// We make the string like this "\??\B:\*.*"
WCHAR UTarget[256]=L"";
UNICODE_STRING CUTarget;
WCHAR USource[256]=L"";
UNICODE_STRING CUSource;
PFILE_OBJECT pTargetFileObject=NULL;
HANDLE TargetFileHandle=NULL,SourceFileHandle=NULL;
FILE_OBJECT TargetFileObject,SourceFileObject;
VCB TargetVCB,SourceVCB;
OBJECT_ATTRIBUTES TargetAttributes,SourceAttributes;
ULONG ThrowInf; // We don't want to see the value of the returned informatiom
// So throw it.
NTSTATUS ntStatus;
_snwprintf(UTarget,255,L"%s",TargetFileName);
RtlInitUnicodeString(&CUTarget,&UTarget[2]);
CUTarget.MaximumLength=512;
_snwprintf(USource,255,L"%s",SourceFileName);
RtlInitUnicodeString(&CUSource,&USource[2]);
CUSource.MaximumLength=512;
// We should make sure the path's name is like this : "C:\*\*.*"
ASSERT( (TargetFileName[0]>=L'A' && TargetFileName[0]<=L'Z')&&
(SourceFileName[0]>=L'A' && SourceFileName[0]<=L'Z'));
ntStatus=FsTPMCreateDirectory(UTarget);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Create Directory Fail!\n"));
return ntStatus;
}
FsTPM_DbgPrint(("Enter Copy File now!!!\n"));
// Build VCB. here , the next lower device and real device are the same
TargetVCB=((PHOOK_EXTENSION)(DriveHookDevices[TargetFileName[0]-L'A']->DeviceExtension))->Vcb;
SourceVCB=((PHOOK_EXTENSION)(DriveHookDevices[SourceFileName[0]-L'A']->DeviceExtension))->Vcb;
// Then we should initialize the file object's attributes
InitializeObjectAttributes(
&TargetAttributes,
&CUTarget,
OBJ_CASE_INSENSITIVE,
NULL, NULL
);
ntStatus=FsTPMCreateFile(&TargetVCB,
FILE_READ_DATA|SYNCHRONIZE|FILE_WRITE_DATA,
&TargetAttributes,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN_IF ,
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0,
FILE_SYNCHRONOUS_IO_NONALERT,
&ThrowInf,
&TargetFileObject,
&TargetFileHandle
);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Create Target File Failed!"));
ErrorString(ntStatus);
return ntStatus;
}
ntStatus = ObReferenceObjectByHandle( TargetFileHandle, FILE_READ_DATA|FILE_WRITE_DATA,
NULL, KernelMode, (void**)&pTargetFileObject, NULL );
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Get Target File Object Fail :Reason: "));
ErrorString(ntStatus);
return ntStatus;
}
ASSERT(pTargetFileObject!=NULL);
if (NULL==pSourceFileObject)
{
InitializeObjectAttributes(
&SourceAttributes,
&CUSource,
OBJ_CASE_INSENSITIVE,
NULL, NULL
);
ntStatus=FsTPMCreateFile(&SourceVCB,
FILE_READ_DATA|SYNCHRONIZE,
&SourceAttributes,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_OPEN_IF ,
FILE_SYNCHRONOUS_IO_ALERT,
NULL,
0,
FILE_SYNCHRONOUS_IO_ALERT,
&ThrowInf,
&SourceFileObject,
&SourceFileHandle
);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Create Source File Failed!"));
ErrorString(ntStatus);
return ntStatus;
}
ntStatus = ObReferenceObjectByHandle( SourceFileHandle, FILE_READ_DATA,
NULL, KernelMode, (void**)&pSourceFileObject, NULL );
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Get Source File Object Fail :Reason: "));
ErrorString(ntStatus);
}
ASSERT(pSourceFileObject!=NULL);
}
else
{
// FsTPM_DbgPrint(("Source File Object Count = %d \n",ObGetObjectPointerCount(pSourceFileObject)));
ntStatus = ObReferenceObjectByPointer( pSourceFileObject, FILE_READ_DATA,
NULL,KernelMode );
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Inc File Object Count Error: "));
ErrorString(ntStatus);
return ntStatus;
}
}
ntStatus=FsTPMCopyFile(pTargetFileObject,pSourceFileObject,SourceVCB.NextLowerDevice,TargetVCB.NextLowerDevice);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Copy File Failed!"));
ErrorString(ntStatus);
return ntStatus;
}
else
{
FsTPM_DbgPrint((("Copy File Success! \n")));
}
// We should close the handle
ObDereferenceObject(pTargetFileObject);
ObDereferenceObject(pSourceFileObject);
// FsTPM_DbgPrint(("After Dereference Source File Object Count = %d \n",ObGetObjectPointerCount(pSourceFileObject)));
FsTPM_DbgPrint((("Now Close Source File !\n")));
if (NULL!=SourceFileHandle)
{
ntStatus=ZwClose(SourceFileHandle);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Close Source File Failed! "));
ErrorString(ntStatus);
return ntStatus;
}
}
FsTPM_DbgPrint((("Now Close Source File !\n")));
ntStatus=ZwClose(TargetFileHandle);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Close Target File Failed!"));
ErrorString(ntStatus);
return ntStatus;
}
return STATUS_SUCCESS;
}
NTSTATUS
FsTPMCopyFile(
PFILE_OBJECT TargetFileObject,
PFILE_OBJECT SourceFileObject,
PDEVICE_OBJECT pSourceDeviceObject,
PDEVICE_OBJECT pTargetDeviceObject
)
//++
// Function: FsTPMCopyFile
//
// Description:
// Copy file
//
// Arguments:
// TargetFileObject - Target file object
// SourceFileObject - Source file object
//
// Return value:
// STATUS_SUCCESS if successful,
// STATUS_UNSUCCESSFUL otherwise
//
// Notice :
// This function is provided by OSR
//--
{
PVOID buffer;
PMDL mdl;
IO_STATUS_BLOCK iosb;
FILE_STANDARD_INFORMATION standardInformation;
LARGE_INTEGER currentOffset;
LONGLONG bytesToTransfer;
//
// The algorithm used by this routine is straight-forward: read 64k chunks from the
// source file and write it to the target file, until the entire file itself has been copied.
//
buffer = ExAllocatePoolWithTag(NonPagedPool,
MAX_TRANSFER_SIZE,
'BcfK');
if (!buffer) {
//
// Allocation must have failed.
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Build an MDL describing the buffer. We'll use THAT to do the
// I/O (rather than a direct buffer address.)
//
mdl = IoAllocateMdl(buffer, MAX_TRANSFER_SIZE, FALSE, TRUE, 0);
MmBuildMdlForNonPagedPool(mdl);
//
// Set up the current offset information
//
currentOffset.QuadPart = 0;
//
// Get the size of the input file.
//
FsTPMGetFileStandardInformation(SourceFileObject, &standardInformation, &iosb,pSourceDeviceObject);
if (!NT_SUCCESS(iosb.Status)) {
//
// This is a failure condition.
//
return (iosb.Status);
}
//
// Set the allocation size of the output file.
//
FsTPMSetFileAllocation(TargetFileObject,
&standardInformation.AllocationSize,
&iosb,pTargetDeviceObject);
if (!NT_SUCCESS(iosb.Status)) {
//
// Failure...
//
return (iosb.Status);
}
//
// Save away the information about the # of bytes to transfer.
//
bytesToTransfer = standardInformation.EndOfFile.QuadPart;
//
// Now copy the source to the target until we run out...
//
while (bytesToTransfer) {
ULONG nextTransferSize;
//
// The # of bytes to copy in the next operation is based upon the maximum of
// the balance IN the file, or KFC_MAX_TRANSFER_SIZE
//
nextTransferSize = (bytesToTransfer < MAX_TRANSFER_SIZE) ?
(ULONG) bytesToTransfer : MAX_TRANSFER_SIZE;
FsTPMRead(SourceFileObject, ¤tOffset, nextTransferSize, mdl, &iosb,pSourceDeviceObject);
if (!NT_SUCCESS(iosb.Status)) {
//
// An error condition occurred.
//
return (iosb.Status);
}
FsTPMWrite(TargetFileObject, ¤tOffset, nextTransferSize, mdl, &iosb,pTargetDeviceObject);
if (!NT_SUCCESS(iosb.Status)) {
//
// An error condition occurred.
//
return (iosb.Status);
}
//
// Now, update the offset/bytes to transfer information
//
currentOffset.QuadPart += nextTransferSize;
bytesToTransfer -= nextTransferSize;
}
//
// At this point, we're done with the copy operation. Return success
//
return (STATUS_SUCCESS);
}
// Notice you should be sure that the file is shared.
NTSTATUS
FsTPMCreateFileObject(
IN PWCHAR TargetFileName,
OUT PFILE_OBJECT* ppFileObject
)
{
//WCHAR *UTarget=NULL;
//UTarget=(WCHAR*)ExAllocatePool(NonPagedPool,512);
WCHAR UTarget[256];
UNICODE_STRING CUTarget;
PFILE_OBJECT pTargetFileObject=NULL;
HANDLE TargetFileHandle;
FILE_OBJECT TargetFileObject;
VCB TargetVCB;
OBJECT_ATTRIBUTES TargetAttributes;
ULONG ThrowInf; // We don't want to see the value of the returned informatiom
// So throw it.
NTSTATUS ntStatus;
_snwprintf(UTarget,256,L"\\??\\%s",TargetFileName);
RtlInitUnicodeString(&CUTarget,UTarget);
CUTarget.MaximumLength=512;
// We should make sure the path's name is like this : "C:\*\*.*"
ASSERT( (TargetFileName[0]>=L'A' && TargetFileName[0]<=L'Z'));
ntStatus=FsTPMCreateDirectory(TargetFileName);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Create Directory Fail!\n"));
ErrorString(ntStatus);
return ntStatus;
}
FsTPM_DbgPrint(("Enter Create File Object now!!!\n"));
// Build VCB. here , the next lower device and real device are the same
TargetVCB=((PHOOK_EXTENSION)(DriveHookDevices[TargetFileName[0]-'A']->DeviceExtension))->Vcb;
// Then we should initialize the file object's attributes
InitializeObjectAttributes(
&TargetAttributes,
&CUTarget,
OBJ_CASE_INSENSITIVE,
NULL, NULL
);
// ntStatus=ZwCreateFile(&TargetFileHandle,
// FILE_READ_DATA|SYNCHRONIZE|FILE_WRITE_DATA|DELETE,
// &TargetAttributes,
// &temp,
// 0,
// FILE_ATTRIBUTE_NORMAL,
// FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
// FILE_OPEN_IF ,
// FILE_SYNCHRONOUS_IO_ALERT,
// NULL,
// 0
// );
//
ntStatus=FsTPMCreateFile(&TargetVCB,
FILE_READ_DATA|SYNCHRONIZE|FILE_WRITE_DATA|DELETE,
&TargetAttributes,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
FILE_OPEN_IF ,
FILE_SYNCHRONOUS_IO_ALERT,
NULL,
0,
FILE_SYNCHRONOUS_IO_ALERT,
&ThrowInf,
&TargetFileObject,
&TargetFileHandle
);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(("Create Target File Failed!"));
ErrorString(ntStatus);
return ntStatus;
}
ntStatus = ObReferenceObjectByHandle( TargetFileHandle, FILE_READ_DATA|FILE_WRITE_DATA,
NULL, KernelMode, (void**)&pTargetFileObject, NULL );
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint((("Get Target File Object Fail\n")));
ErrorString(ntStatus);
return ntStatus;
}
ASSERT(pTargetFileObject!=NULL);
*ppFileObject=pTargetFileObject;
return STATUS_SUCCESS;
}
VOID
FsTPMWriteIRP(
PFILE_OBJECT FileObject,
PDEVICE_OBJECT pDevice,
PIRP pOrgIrp,
PIO_STACK_LOCATION pOrgIoStk,
PIO_STATUS_BLOCK IoStatusBlock,
PMDL mdl
)
//++
// Function: FsTPMWriteIRP
//
// Description:
// This routine is used to write to the file object from memory discribed by MDL
//
// Arguments:
//PFILE_OBJECT FileObject,
//PDEVICE_OBJECT pDevice,
//PIRP pOrgIrp,
//PIO_STACK_LOCATION pOrgIoStk
//PIO_STATUS_BLOCK IoStatusBlock,
//
// Return value:
// None
{
PIRP irp;
KEVENT event;
PIO_STACK_LOCATION ioStackLocation;
PDEVICE_OBJECT fsdDevice =pDevice;
//
// Set up the event we'll use.
//
KeInitializeEvent(&event, SynchronizationEvent, FALSE);
//
// Allocate and build the IRP we'll be sending to the FSD.
//
irp = IoAllocateIrp(fsdDevice->StackSize, FALSE);
if (!irp) {
//
// Allocation failed, presumably due to memory allocation failure.
//
IoStatusBlock->Status = STATUS_INSUFFICIENT_RESOURCES;
IoStatusBlock->Information = 0;
return ;
}
irp->AssociatedIrp.SystemBuffer = pOrgIrp->AssociatedIrp.SystemBuffer;
irp->MdlAddress = pOrgIrp->MdlAddress;
irp->UserBuffer=pOrgIrp->UserBuffer;
irp->UserEvent = &event;
irp->UserIosb = IoStatusBlock;
irp->Tail.Overlay.Thread = PsGetCurrentThread();
irp->Tail.Overlay.OriginalFileObject= FileObject;
irp->RequestorMode = KernelMode;
//
// Indicate that this is a WRITE operation.
//
irp->Flags = IRP_WRITE_OPERATION;
//
// Set up the next I/O stack location. These are the parameters
// that will be passed to the underlying driver.
//
ioStackLocation = IoGetNextIrpStackLocation(irp);
ioStackLocation->MajorFunction = pOrgIoStk->MajorFunction;
ioStackLocation->MinorFunction = pOrgIoStk->MinorFunction;
ioStackLocation->DeviceObject = fsdDevice;
ioStackLocation->FileObject = FileObject;
//
// We use a completion routine to keep the I/O Manager from doing
// "cleanup" on our IRP - like freeing our MDL.
//
IoSetCompletionRoutine(irp, KfcIoCompletion, 0, TRUE, TRUE, TRUE);
ioStackLocation->Parameters.Write.Length = pOrgIoStk->Parameters.Write.Length;
ioStackLocation->Parameters.Write.ByteOffset = pOrgIoStk->Parameters.Write.ByteOffset;
ioStackLocation->Parameters.Write.Key = pOrgIoStk->Parameters.Write.Key;
//
// Send it on. Ignore the return code.
//
(void) IoCallDriver(fsdDevice, irp);
//
// Wait for the I/O to complete.
//
KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);
//
// Done. Return results are in the io status block.
//
return;
}
NTSTATUS
GetFileFullNameByQuery(
OUT PUNICODE_STRING SourceFileName,
IN PHOOK_EXTENSION pHookExt ,
IN PFILE_OBJECT FileObject
)
{
VCB Vcb;
ULONG ResultLen;
NTSTATUS ntStatus;
WCHAR USName[256];
_snwprintf(USName,256,L"A:");
UNICODE_STRING CUSourceName;
RtlInitUnicodeString(&CUSourceName,USName);
CUSourceName.MaximumLength=512;
Vcb=pHookExt->Vcb;
PFILE_NAME_INFORMATION fileNameInfo;
if (0==FileObject->FileName.Length) // 我不知道为什么会有这样的情况
return STATUS_UNSUCCESSFUL;
//调查"家底",确认其真实文件名
fileNameInfo = (PFILE_NAME_INFORMATION)ExAllocatePool( NonPagedPool, MAXPATHLEN*sizeof(WCHAR));
if (NULL==fileNameInfo)
{
FsTPM_DbgPrint((("Memory Allocate Fail!\n")));
if (fileNameInfo!=NULL)
ExFreePool(fileNameInfo);
return STATUS_UNSUCCESSFUL;
}
ntStatus=FsTPMQueryInformationFile(&Vcb,FileObject,FileNameInformation,fileNameInfo,(MAXPATHLEN-5)*sizeof(WCHAR),&ResultLen);
if (!NT_SUCCESS(ntStatus))
{
FsTPM_DbgPrint(((" Query Name Information of file Fail\n")));
ErrorString(ntStatus);
if (fileNameInfo!=NULL)
ExFreePool(fileNameInfo);
return ntStatus;
}
fileNameInfo->FileName[fileNameInfo->FileNameLength/2]=0;
_snwprintf(CUSourceName.Buffer+wcslen(CUSourceName.Buffer),256-wcslen(CUSourceName.Buffer),L"%s",fileNameInfo->FileName);
CUSourceName.Buffer[0]=(WCHAR)(pHookExt->LogicalDrive);
CUSourceName.Length=wcslen(CUSourceName.Buffer)*sizeof(WCHAR);
RtlCopyUnicodeString( SourceFileName, &(UNICODE_STRING)CUSourceName );
if (fileNameInfo!=NULL)
ExFreePool(fileNameInfo);
return STATUS_SUCCESS;
}
VOID CreateFileSizeZero(PUNICODE_STRING pUniFile,BOOL isdir)
{
// Then we should initialize the file object's attributes
UNICODE_STRING uFile;
FILE_OBJECT fileobject;
HANDLE fileHandle;
ULONG ThrowInf;
ULONG op1;
ULONG op2;
NTSTATUS ntStatus;
OBJECT_ATTRIBUTES FileAttrib;
RtlInitUnicodeString(&uFile,&pUniFile->Buffer[2]);
InitializeObjectAttributes(
&FileAttrib,
&uFile,
OBJ_CASE_INSENSITIVE,
NULL, NULL
);
if (isdir)
{
op1=FILE_SYNCHRONOUS_IO_NONALERT|FILE_NO_INTERMEDIATE_BUFFERING|FILE_DIRECTORY_FILE;
op2=FILE_SYNCHRONOUS_IO_NONALERT|FILE_NO_INTERMEDIATE_BUFFERING|FILE_DIRECTORY_FILE;
}
else
{
op1=FILE_SYNCHRONOUS_IO_NONALERT|FILE_NO_INTERMEDIATE_BUFFERING;
op2=FILE_SYNCHRONOUS_IO_NONALERT|FILE_NO_INTERMEDIATE_BUFFERING;
}
ntStatus=FsTPMCreateFile(&(((PHOOK_EXTENSION)(DriveHookDevices[pUniFile->Buffer[0]-L'A']->DeviceExtension))->Vcb),
FILE_READ_DATA|SYNCHRONIZE|FILE_WRITE_DATA,
&FileAttrib,
0,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ|FILE_SHARE_WRITE,
FILE_CREATE ,
op1,
NULL,
0,
op2,
&ThrowInf,
&fileobject,
&fileHandle
);
ZwClose(fileHandle);
}
//----------------------------------------------------------------------
//
// FsTPMGetProcess
//
// Uses undocumented data structure offsets to obtain the name of the
// currently executing process.
//
//----------------------------------------------------------------------
PCHAR
FsTPMGetProcess(
PCHAR ProcessName
)
{
PEPROCESS curproc;
char *nameptr;
// ULONG i;
//
// We only do this if we determined the process name offset
//
if( ProcessNameOffset ) {
//
// Get a pointer to the current process block
//
curproc = PsGetCurrentProcess();
//
// Dig into it to extract the name. Make sure to leave enough room
// in the buffer for the appended process ID.
//
nameptr = (PCHAR) curproc + ProcessNameOffset;
strncpy( ProcessName, nameptr, NT_PROCNAMELEN-1 );
ProcessName[NT_PROCNAMELEN-1] = 0;
// sprintf( ProcessName + strlen(ProcessName), ":%d", PsGetCurrentProcessId());
} else {
strcpy( ProcessName, "???" );
}
return ProcessName;
}
//----------------------------------------------------------------------
//
// FsTPMGetProcessNameOffset
//
// In an effort to remain version-independent, rather than using a
// hard-coded into the KPEB (Kernel Process Environment Block), we
// scan the KPEB looking for the name, which should match that
// of the system process. This is because we are in the system process'
// context in DriverEntry, where this is called.
//
//----------------------------------------------------------------------
ULONG
FsTPMGetProcessNameOffset(
VOID
)
{
PEPROCESS curproc;
int i;
curproc = PsGetCurrentProcess();
//
// Scan for 12KB, hoping the KPEB never grows that big!
//
for( i = 0; i < 3*PAGE_SIZE; i++ ) {
if( !strncmp( SYSNAME, (PCHAR) curproc + i, strlen(SYSNAME) )) {
return i;
}
}
//
// Name not found - oh, well
//
return 0;
}