FileMon.c

来源:互联网 发布:君子哀而生之乎 编辑:程序博客网 时间:2024/05/18 08:39

http://blog.csdn.net/xiongwjw/article/category/1081656
//====================================================================== // // Filemon.c // // Sysinternals - www.sysinternals.com // Copyright (C) 1996-2001 Mark Russinovich and Bryce Cogswell // // Passthrough file system filter device driver. // // Notes: The reason that we use NonPagedPool even though the driver // only accesses allocated buffer at PASSIVE_LEVEL, is that touching // a paged pool buffer can generate a page fault, and if the paging // file is on a drive that filemon is monitoring filemon would be // reentered to handle the page fault. We want to avoid that and so // we only use nonpaged pool. // //====================================================================== #include "ntddk.h" #include "stdarg.h" #include "stdio.h" #include "..\exe\ioctlcmd.h" #include "filemon.h"   //---------------------------------------------------------------------- //           F O R W A R D   D E C L A R A T I O N S //----------------------------------------------------------------------  // // These are prototypes for Filemon's Fast I/O hooks. The originals // prototypes can be found in NTDDK.H // BOOLEAN FilemonFastIoCheckifPossible(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN BOOLEAN Wait,     IN ULONG LockKey,     IN BOOLEAN CheckForReadOperation,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoRead(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN BOOLEAN Wait,     IN ULONG LockKey,     OUT PVOID Buffer,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoWrite(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN BOOLEAN Wait,     IN ULONG LockKey,     IN PVOID Buffer,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoQueryBasicInfo(     IN PFILE_OBJECT FileObject,     IN BOOLEAN Wait,     OUT PFILE_BASIC_INFORMATION Buffer,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoQueryStandardInfo(     IN PFILE_OBJECT FileObject,     IN BOOLEAN Wait,     OUT PFILE_STANDARD_INFORMATION Buffer,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoLock(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN PLARGE_INTEGER Length,     PEPROCESS ProcessId,     ULONG Key,     BOOLEAN FailImmediately,     BOOLEAN ExclusiveLock,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoUnlockSingle(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN PLARGE_INTEGER Length,     PEPROCESS ProcessId,     ULONG Key,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoUnlockAll(     IN PFILE_OBJECT FileObject,     PEPROCESS ProcessId,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoUnlockAllByKey(     IN PFILE_OBJECT FileObject,     PEPROCESS ProcessId, ULONG Key,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoDeviceControl(     IN PFILE_OBJECT FileObject,     IN BOOLEAN Wait,     IN PVOID InputBuffer,     IN ULONG InputBufferLength,     OUT PVOID OutbufBuffer,     IN ULONG OutputBufferLength,     IN ULONG IoControlCode,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); VOID FilemonFastIoAcquireFile(     PFILE_OBJECT FileObject ); VOID FilemonFastIoReleaseFile(     PFILE_OBJECT FileObject ); VOID FilemonFastIoDetachDevice(     PDEVICE_OBJECT SourceDevice,     PDEVICE_OBJECT TargetDevice );  // // These are new NT 4.0 Fast I/O calls // BOOLEAN FilemonFastIoQueryNetworkOpenInfo(     IN PFILE_OBJECT FileObject,     IN BOOLEAN Wait,     OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer,     OUT struct _IO_STATUS_BLOCK *IoStatus,     IN PDEVICE_OBJECT DeviceObject ); NTSTATUS FilemonFastIoAcquireForModWrite(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER EndingOffset,     OUT struct _ERESOURCE **ResourceToRelease,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoMdlRead(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN ULONG LockKey,     OUT PMDL *MdlChain,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoMdlReadComplete(     IN PFILE_OBJECT FileObject,     IN PMDL MdlChain,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoPrepareMdlWrite(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN ULONG LockKey,     OUT PMDL *MdlChain,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoMdlWriteComplete(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN PMDL MdlChain,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoReadCompressed(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN ULONG LockKey,     OUT PVOID Buffer,     OUT PMDL *MdlChain,     OUT PIO_STATUS_BLOCK IoStatus,     OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo,     IN ULONG CompressedDataInfoLength,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoWriteCompressed(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN ULONG LockKey,     IN PVOID Buffer,     OUT PMDL *MdlChain,     OUT PIO_STATUS_BLOCK IoStatus,     IN struct _COMPRESSED_DATA_INFO *CompressedDataInfo,     IN ULONG CompressedDataInfoLength,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoMdlReadCompleteCompressed(     IN PFILE_OBJECT FileObject,     IN PMDL MdlChain,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoMdlWriteCompleteCompressed(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN PMDL MdlChain,     IN PDEVICE_OBJECT DeviceObject ); BOOLEAN FilemonFastIoQueryOpen(     IN struct _IRP *Irp,     OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation,     IN PDEVICE_OBJECT DeviceObject ); NTSTATUS FilemonFastIoReleaseForModWrite(     IN PFILE_OBJECT FileObject,     IN struct _ERESOURCE *ResourceToRelease,     IN PDEVICE_OBJECT DeviceObject ); NTSTATUS FilemonFastIoAcquireForCcFlush(     IN PFILE_OBJECT FileObject,     IN PDEVICE_OBJECT DeviceObject ); NTSTATUS FilemonFastIoReleaseForCcFlush(     IN PFILE_OBJECT FileObject,     IN PDEVICE_OBJECT DeviceObject );  BOOLEAN ApplyFilters(     PCHAR Text );  // // Unload routine (debug builds only) // VOID FilemonUnload(     IN PDRIVER_OBJECT DriverObject );  //---------------------------------------------------------------------- //                       G L O B A L S //----------------------------------------------------------------------  // // This is our Driver Object // PDRIVER_OBJECT      FilemonDriver;  // // Indicates if the GUI wants activity to be logged // BOOLEAN             FilterOn = FALSE;  // // Global filter (sent to us by the GUI) // FILTER              FilterDef;  // // This lock protects access to the filter array // ERESOURCE           FilterResource;  // // Array of process and path filters // ULONG               NumIncludeFilters = 0; PCHAR               IncludeFilters[MAXFILTERS]; ULONG               NumExcludeFilters = 0; PCHAR               ExcludeFilters[MAXFILTERS];  // // Once a load is initiated, this flag prevents the processing of // further IRPs. This is required because an unload can only take // place if there are any IRP's for which an IoCompletion has // been registered that has not actually completed. // BOOLEAN             UnloadInProgress = FALSE;  // // This is the offset into a KPEB of the current process name. This is determined // dynamically by scanning the process block belonging to the GUI for the name // of the system process, in who's context we execute in DriverEntry // ULONG               ProcessNameOffset;  // // This variable keeps track of the outstanding IRPs (ones for which // a completion routine has been registered, but that have not yet // passed through the completion routine), which is used in // the unload determination logic. The CountMutex protects data // races on updating the count. // #if DBG ULONG               OutstandingIRPCount = 0; #endif // DBG KSPIN_LOCK          CountMutex;  // // Table of our hook devices for each drive letter. This makes it // easy to look up the device object that was created to hook a // particular drive. // PDEVICE_OBJECT      DriveHookDevices[26];  // // Current bitmask of hooked drives // ULONG               CurrentDriveSet = 0;  // // The special file system hook devices // PDEVICE_OBJECT      NamedPipeHookDevice = NULL; PDEVICE_OBJECT      MailSlotHookDevice = NULL;  // // Hash table for keeping names around. This is necessary because // at any time the name information in the fileobjects that we // see can be deallocated and reused. If we want to print accurate // names, we need to keep them around ourselves. // PHASH_ENTRY            HashTable[NUMHASH];  // // Reader/Writer lock to protect hash table. // ERESOURCE            HashResource;  // // The current output buffer // PLOG_BUF            CurrentLog = NULL;  // // Each IRP is given a sequence number. This allows the return status // of an IRP, which is obtained in the completion routine, to be // associated with the IRPs parameters that were extracted in the Dispatch // routine. // ULONG               Sequence = 0;  // // This mutex protects the output buffer // FAST_MUTEX          LogMutex;  // // Filemon keeps track of the number of distinct output buffers that // have been allocated, but not yet uploaded to the GUI, and caps // the amount of memory (which is in non-paged pool) it takes at // 1MB. // ULONG               NumLog = 0; ULONG               MaxLog = (1024 * 1024) / LOGBUFSIZE;  // // Full path name lookaside for dispatch entry // NPAGED_LOOKASIDE_LIST  FullPathLookaside;  // // We use this string for a path name when we're out of resources // CHAR InsufficientResources[] = "<INSUFFICIENT MEMORY>";  // // These are the text representations of the classes of IRP_MJ_SET/GET_INFORMATION // calls // CHAR *FileInformation[] = {     "",     "FileDirectoryInformation",     "FileFullDirectoryInformation",     "FileBothDirectoryInformation",     "FileBasicInformation",     "FileStandardInformation",     "FileInternalInformation",     "FileEaInformation",     "FileAccessInformation",     "FileNameInformation",     "FileRenameInformation",     "FileLinkInformation",     "FileNamesInformation",     "FileDispositionInformation",     "FilePositionInformation",     "FileFullEaInformation",     "FileModeInformation",     "FileAlignmentInformation",     "FileAllInformation",     "FileAllocationInformation",     "FileEndOfFileInformation",     "FileAlternateNameInformation",     "FileStreamInformation",     "FilePipeInformation",     "FilePipeLocalInformation",     "FilePipeRemoteInformation",     "FileMailslotQueryInformation",     "FileMailslotSetInformation",     "FileCompressionInformation",     "FileCopyOnWriteInformation",     "FileCompletionInformation",     "FileMoveClusterInformation",     "FileOleClassIdInformation",     "FileOleStateBitsInformation",     "FileNetworkOpenInformation",     "FileObjectIdInformation",     "FileOleAllInformation",     "FileOleDirectoryInformation",     "FileContentIndexInformation",     "FileInheritContentIndexInformation",     "FileOleInformation",     "FileMaximumInformation", };   // // These are textual representations of the IRP_MJ_SET/GET_VOLUME_INFORMATION // classes // CHAR *VolumeInformation[] = {     "",     "FileFsVolumeInformation",     "FileFsLabelInformation",     "FileFsSizeInformation",     "FileFsDeviceInformation",     "FileFsAttributeInformation",     "FileFsQuotaQueryInformation",     "FileFsQuotaSetInformation",     "FileFsControlQueryInformation",     "FileFsControlSetInformation",     "FileFsMaximumInformation", };   // // These are Win2K Plug-and-Play minor IRP codes // CHAR *PnpMinorCode[] = {     "IRP_MN_START_DEVICE",     "IRP_MN_QUERY_REMOVE_DEVICE",     "IRP_MN_REMOVE_DEVICE",     "IRP_MN_CANCEL_REMOVE_DEVICE",     "IRP_MN_STOP_DEVICE",     "IRP_MN_QUERY_STOP_DEVICE",     "IRP_MN_CANCEL_STOP_DEVICE",     "IRP_MN_QUERY_DEVICE_RELATIONS",     "IRP_MN_QUERY_INTERFACE",     "IRP_MN_QUERY_CAPABILITIES",     "IRP_MN_QUERY_RESOURCES",     "IRP_MN_QUERY_RESOURCE_REQUIREMENTS",     "IRP_MN_QUERY_DEVICE_TEXT",     "IRP_MN_FILTER_RESOURCE_REQUIREMENTS",     "IRP_MN_READ_CONFIG",     "IRP_MN_WRITE_CONFIG",     "IRP_MN_EJECT",     "IRP_MN_SET_LOCK",     "IRP_MN_QUERY_ID",     "IRP_MN_QUERY_PNP_DEVICE_STATE",     "IRP_MN_QUERY_BUS_INFORMATION",     "IRP_MN_DEVICE_USAGE_NOTIFICATION",     "IRP_MN_SURPRISE_REMOVAL",     "IRP_MN_QUERY_LEGACY_BUS_INFORMATION", };  #define MAX_NTFS_METADATA_FILE 11 CHAR *NtfsMetadataFileNames[] = {     "$Mft",     "$MftMirr",     "$LogFile",     "$Volume",     "$AttrDef",     "$Root",     "$Bitmap",     "$Boot",     "$BadClus",     "$Secure",     "$UpCase",     "$Extend" };    // // This Filemon's Fast I/O dispatch table. Note that NT assumes that // file system drivers support some Fast I/O calls, so this table must // be present for an file system filter driver // FAST_IO_DISPATCH    FastIOHook = {     sizeof(FAST_IO_DISPATCH),     FilemonFastIoCheckifPossible,     FilemonFastIoRead,     FilemonFastIoWrite,     FilemonFastIoQueryBasicInfo,     FilemonFastIoQueryStandardInfo,     FilemonFastIoLock,     FilemonFastIoUnlockSingle,     FilemonFastIoUnlockAll,     FilemonFastIoUnlockAllByKey,     FilemonFastIoDeviceControl,     FilemonFastIoAcquireFile,     FilemonFastIoReleaseFile,     FilemonFastIoDetachDevice,      //     // new for NT 4.0     //     FilemonFastIoQueryNetworkOpenInfo,     FilemonFastIoAcquireForModWrite,     FilemonFastIoMdlRead,     FilemonFastIoMdlReadComplete,     FilemonFastIoPrepareMdlWrite,     FilemonFastIoMdlWriteComplete,     FilemonFastIoReadCompressed,     FilemonFastIoWriteCompressed,     FilemonFastIoMdlReadCompleteCompressed,     FilemonFastIoMdlWriteCompleteCompressed,     FilemonFastIoQueryOpen,     FilemonFastIoReleaseForModWrite,     FilemonFastIoAcquireForCcFlush,     FilemonFastIoReleaseForCcFlush };  //---------------------------------------------------------------------- //      P A T T E R N   M A T C H I N G   R O U T I N E S //----------------------------------------------------------------------   //---------------------------------------------------------------------- // // MatchOkay // // Only thing left after compare is more mask. This routine makes // sure that its a valid wild card ending so that its really a match. // //---------------------------------------------------------------------- BOOLEAN MatchOkay(     PCHAR Pattern ) {     //     // If pattern isn't empty, it must be a wildcard     //     if( *Pattern && *Pattern != '*' )     {          return FALSE;     }      //     // Matched     //     return TRUE; }   //---------------------------------------------------------------------- // // MatchWithPattern // // Performs nifty wildcard comparison. // //---------------------------------------------------------------------- BOOLEAN MatchWithPattern(     PCHAR Pattern,     PCHAR Name ) {     char matchchar;      //     // End of pattern?     //     if( !*Pattern )     {          return FALSE;     }      //     // If we hit a wild card, do recursion     //     if( *Pattern == '*' )     {          Pattern++;         while( *Name && *Pattern )         {              matchchar = *Name;             if( matchchar >= 'a' &&                     matchchar <= 'z' )             {                  matchchar -= 'a' - 'A';             }              //             // See if this substring matches             //             if( *Pattern == matchchar )             {                  if( MatchWithPattern( Pattern + 1, Name + 1 ))                 {                      return TRUE;                 }             }              //             // Try the next substring             //             Name++;         }          //         // See if match condition was met         //         return MatchOkay( Pattern );     }      //     // Do straight compare until we hit a wild card     //     while( *Name && *Pattern != '*' )     {          matchchar = *Name;         if( matchchar >= 'a' &&                 matchchar <= 'z' )         {              matchchar -= 'a' - 'A';         }          if( *Pattern == matchchar )         {             Pattern++;             Name++;          }         else         {              return FALSE;         }     }      //     // If not done, recurse     //     if( *Name )     {          return MatchWithPattern( Pattern, Name );     }      //     // Make sure its a match     //     return MatchOkay( Pattern ); }  //---------------------------------------------------------------------- //            B U F F E R   M A N A G E M E N T //----------------------------------------------------------------------  //---------------------------------------------------------------------- // // FilemonFreeLog // // Frees all the data output buffers that we have currently allocated. // //---------------------------------------------------------------------- VOID FilemonFreeLog(     VOID ) {     PLOG_BUF  prev;      //     // Just traverse the list of allocated output buffers     //     while( CurrentLog )     {         prev = CurrentLog->Next;         ExFreePool( CurrentLog );         CurrentLog = prev;     } }   //---------------------------------------------------------------------- // // FilemonAllocateLog // // Called when the current buffer has filled up. This allocates a new // buffer and stick it at the head (newest) entry of our buffer list. // //---------------------------------------------------------------------- void FilemonAllocateLog(     VOID ) {     PLOG_BUF prev = CurrentLog, newLog;      //     // If we've already allocated the allowed number of buffers, just     // reuse the current one. This will result in output records being     // lost, but it takes ALOT of file system activity to cause this.     //     if( MaxLog == NumLog )     {          DbgPrint(("Filemon ***** Dropping records at sequence number %d\n", Sequence ));         CurrentLog->Len = 0;         return;     }      DbgPrint(("FilemonAllocateLog: num: %d max: %d\n", NumLog, MaxLog ));      //     // If the output buffer we currently are using is empty, just     // use it.     //     if( !CurrentLog->Len )     {          return;     }      //     // Allocate a new output buffer     //     newLog = ExAllocatePool( NonPagedPool, sizeof(*CurrentLog) );     if( newLog )     {          //         // Allocation was successful so add the buffer to the list         // of allocated buffers and increment the buffer count.         //         CurrentLog       = newLog;         CurrentLog->Len  = 0;         CurrentLog->Next = prev;         NumLog++;      }     else     {          //         // The allocation failed - just reuse the current buffer         //         CurrentLog->Len = 0;     } }   //---------------------------------------------------------------------- // // FilemonGetOldestLog // // Traverse the list of allocated buffers to find the last one, which // will be the oldest (as we want to return the oldest data to the GUI // first). // //---------------------------------------------------------------------- PLOG_BUF FilemonGetOldestLog(     VOID ) {     PLOG_BUF  ptr = CurrentLog, prev = NULL;      //     // Traverse the list     //     while( ptr->Next )     {          ptr = (prev = ptr)->Next;     }      //     // Remove the buffer from the list     //     if( prev )     {          prev->Next = NULL;         NumLog--;     }     return ptr; }   //---------------------------------------------------------------------- // // FilemonResetLog // // When a GUI instance has close communication (exited), but the driver // can't unload due to oustdanding IRPs, all the output buffers except // one are all deallocated so that the memory footprint is shrunk as much // as possible. // //---------------------------------------------------------------------- VOID FilemonResetLog(     VOID ) {     PLOG_BUF  current, next;      ExAcquireFastMutex( &LogMutex );      //     // Traverse the list of output buffers     //     current = CurrentLog->Next;     while( current )     {          //         // Free the buffer         //         next = current->Next;         ExFreePool( current );         current = next;     }      //     // Move the output pointer in the buffer that's being kept     // the start of the buffer.     //     NumLog = 1;     CurrentLog->Len = 0;     CurrentLog->Next = NULL;     ExReleaseFastMutex( &LogMutex ); }   //---------------------------------------------------------------------- // // LogRecord // // This "printfs" a string into an output buffer. // //---------------------------------------------------------------------- BOOLEAN LogRecord(     BOOLEAN ProcessFilters,     PULONG SeqNum,     PLARGE_INTEGER dateTime,     PLARGE_INTEGER perfTime,     const CHAR *format,     ... ) {     PENTRY             Entry;     int                len;     ULONG              recordSequence;     va_list            arg_ptr;     static CHAR        text[MAXPATHLEN];     BOOLEAN            passedFilters = FALSE;      //     // If no GUI is there to receive the output or if no filtering is desired, don't bother     //     if( !FilterOn )     {          return FALSE;     }      //     // Lock the output buffer and Log.     //     ExAcquireFastMutex( &LogMutex );      //     // Send text out as debug output  This is x86 specific.     // #define A (&format)     DbgPrint(( (char *)format, A[1], A[2], A[3], A[4], A[5], A[6] ));     DbgPrint(( "\n" )); #undef A      //     // Vsprintf to determine the length of the buffer     //     va_start( arg_ptr, format );     len = vsprintf( text, format, arg_ptr );     va_end( arg_ptr );      //     // ULONG align for Alpha     //     len += 4;     len &=  0xFFFFFFFC;      //     // Only log it if it passes the filters. Note that IRP completion     // passes a false for ProcessFilters because if we've logged     // the initial action, we have to go ahead and log the completion.     //     passedFilters = !ProcessFilters || ApplyFilters( text );     if( passedFilters )     {          //         // Assign a sequence number if we weren't passed one         //         if( !SeqNum || (SeqNum && *SeqNum == (ULONG) - 1))         {              recordSequence = InterlockedIncrement( &Sequence );             if( SeqNum ) *SeqNum = recordSequence;          }         else         {              recordSequence = *SeqNum;         }          //         // If the current output buffer is near capacity, move to a new         // output buffer         //         if( CurrentLog->Len + len + sizeof(ENTRY) + 1 >= LOGBUFSIZE )         {              FilemonAllocateLog();         }          //         // Log the entry         //         Entry = (void *)(CurrentLog->Data + CurrentLog->Len);         Entry->seq = recordSequence;         Entry->datetime.QuadPart = 0;         Entry->perftime.QuadPart = 0;         if( dateTime ) Entry->datetime = *dateTime;         if( perfTime ) Entry->perftime = *perfTime;         memcpy( Entry->text, text, len );          //         // Log the length of the string, plus 1 for the terminating         // NULL         //         CurrentLog->Len += ((ULONG) (Entry->text - (PCHAR) Entry )) + len;     }      //     // Release the output buffer lock     //     ExReleaseFastMutex( &LogMutex );     return passedFilters; }  //---------------------------------------------------------------------- //       H A S H   T A B L E   M A N A G E M E N T //----------------------------------------------------------------------  //---------------------------------------------------------------------- // // FilemonHashCleanup // // Called when we are unloading to free any memory that we have // in our possession. // //---------------------------------------------------------------------- VOID FilemonHashCleanup(     VOID ) {     PHASH_ENTRY        hashEntry, nextEntry;     ULONG            i;      KeEnterCriticalRegion();     ExAcquireResourceExclusiveLite( &HashResource, TRUE );      //     // Free the hash table entries     //     for( i = 0; i < NUMHASH; i++ )     {          hashEntry = HashTable[i];          while( hashEntry )         {             nextEntry = hashEntry->Next;             ExFreePool( hashEntry );             hashEntry = nextEntry;         }          HashTable[i] = NULL;     }     ExReleaseResourceLite( &HashResource );     KeLeaveCriticalRegion(); }   //---------------------------------------------------------------------- // // FilemonFreeHashEntry // // When we see a file close, we can free the string we had associated // with the fileobject being closed since we know it won't be used // again. // //---------------------------------------------------------------------- VOID FilemonFreeHashEntry(     PFILE_OBJECT fileObject ) {     PHASH_ENTRY        hashEntry, prevEntry;      KeEnterCriticalRegion();     ExAcquireResourceExclusiveLite( &HashResource, TRUE );      //     // Look-up the entry     //     hashEntry = HashTable[ HASHOBJECT( fileObject ) ];     prevEntry = NULL;      while( hashEntry && hashEntry->FileObject != fileObject )     {          prevEntry = hashEntry;         hashEntry = hashEntry->Next;     }      //     // If we fall of the hash list without finding what we're looking     // for, just return.     //     if( !hashEntry )     {          ExReleaseResourceLite( &HashResource );         KeLeaveCriticalRegion();         return;     }      //     // Got it! Remove it from the list     //     if( prevEntry )     {          prevEntry->Next = hashEntry->Next;      }     else     {          HashTable[ HASHOBJECT( fileObject )] = hashEntry->Next;     }      //     // Free the entry's memory     //     ExFreePool( hashEntry );      ExReleaseResourceLite( &HashResource );     KeLeaveCriticalRegion(); }  //---------------------------------------------------------------------- //       P A T H  A N D  P R O C E S S  N A M E  R O U T I N E S //----------------------------------------------------------------------   //---------------------------------------------------------------------- // // FilemonFreeFilters // // Fress storage we allocated for filter strings. // //---------------------------------------------------------------------- VOID FilemonFreeFilters(     VOID ) {     ULONG   i;      for( i = 0; i < NumIncludeFilters; i++ )     {          ExFreePool( IncludeFilters[i] );     }     for( i = 0; i < NumExcludeFilters; i++ )     {          ExFreePool( ExcludeFilters[i] );     }     NumIncludeFilters = 0;     NumExcludeFilters = 0; }   //---------------------------------------------------------------------- // // MakeFilterArray // // Takes a filter string and splits into components (a component // is seperated with a ';') // //---------------------------------------------------------------------- VOID MakeFilterArray(     PCHAR FilterString,     PCHAR FilterArray[],     PULONG NumFilters ) {     PCHAR filterStart;     ULONG filterLength;     CHAR  saveChar;      //     // Scan through the process filters     //     filterStart = FilterString;     while( *filterStart )     {          filterLength = 0;         while( filterStart[filterLength] &&                 filterStart[filterLength] != ';' )         {              filterLength++;         }          //         // Ignore zero-length components         //         if( filterLength )         {              //             // Conservatively allocate so that we can prepend and append             // wildcards             //             FilterArray[ *NumFilters ] =                 ExAllocatePool( PagedPool, filterLength + 1 + 2 * sizeof('*') );              //             // Only fill this in if there's enough memory             //             if( FilterArray[ *NumFilters] )             {                  saveChar = *(filterStart + filterLength );                 *(filterStart + filterLength) = 0;                 sprintf( FilterArray[ *NumFilters ], "%s%s%s",                          *filterStart == '*' ? "" : "*",                          filterStart,                          *(filterStart + filterLength - 1 ) == '*' ? "" : "*" );                 *(filterStart + filterLength) = saveChar;                 (*NumFilters)++;             }         }          //         // Are we done?         //         if( !filterStart[filterLength] ) break;          //         // Move to the next component (skip over ';')         //         filterStart += filterLength + 1;     } }   //---------------------------------------------------------------------- // // FilemonUpdateFilters // // Takes a new filter specification and updates the filter // arrays with them. // //---------------------------------------------------------------------- VOID FilemonUpdateFilters(     VOID ) {     //     // Free old filters (if any)     //     KeEnterCriticalRegion();     ExAcquireResourceExclusiveLite( &FilterResource, TRUE );     FilemonFreeFilters();      //     // Create new filter arrays     //     MakeFilterArray( FilterDef.includefilter,                      IncludeFilters, &NumIncludeFilters );     MakeFilterArray( FilterDef.excludefilter,                      ExcludeFilters, &NumExcludeFilters );     ExReleaseResourceLite( &FilterResource );     KeLeaveCriticalRegion(); }   //---------------------------------------------------------------------- // // ApplyFilters // // If the name matches the exclusion mask, we do not log it. Else if // it doesn't match the inclusion mask we do not log it. // //---------------------------------------------------------------------- BOOLEAN ApplyFilters(     PCHAR Text ) {     ULONG i;      //     // If no GUI or no filename return FALSE     //     if( !Text ) return FALSE;      //     // If it matches the exclusion string, do not log it     //     KeEnterCriticalRegion();     ExAcquireResourceSharedLite( &FilterResource, TRUE );      for( i = 0; i < NumExcludeFilters; i++ )     {          if( MatchWithPattern( ExcludeFilters[i], Text ) )         {              ExReleaseResourceLite( &FilterResource );             KeLeaveCriticalRegion();             return FALSE;         }     }      //     // If it matches an include filter then log it     //     for( i = 0; i < NumIncludeFilters; i++ )     {          if( MatchWithPattern( IncludeFilters[i], Text ))         {              ExReleaseResourceLite( &FilterResource );             KeLeaveCriticalRegion();             return TRUE;         }     }      //     // It didn't match any include filters so don't log     //     ExReleaseResourceLite( &FilterResource );     KeLeaveCriticalRegion();     return FALSE; }   //---------------------------------------------------------------------- // // FilemonQueryFileComplete // // This routine is used to handle I/O completion for our self-generated // IRP that is used to query a file's name or number. // //---------------------------------------------------------------------- NTSTATUS FilemonQueryFileComplete(     PDEVICE_OBJECT DeviceObject,     PIRP Irp,     PVOID Context ) {     //     // Copy the status information back into the "user" IOSB.     //     *Irp->UserIosb = Irp->IoStatus;     if( !NT_SUCCESS(Irp->IoStatus.Status) )     {          DbgPrint(("   ERROR ON IRP: %x\n", Irp->IoStatus.Status ));     }      //     // Set the user event - wakes up the mainline code doing this.     //     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; }   //---------------------------------------------------------------------- // // FilemonQueryFile // // This function retrieves the "standard" information for the // underlying file system, asking for the filename in particular. // //---------------------------------------------------------------------- BOOLEAN FilemonQueryFile(     PDEVICE_OBJECT DeviceObject,     PFILE_OBJECT FileObject,     FILE_INFORMATION_CLASS FileInformationClass,     PVOID FileQueryBuffer,     ULONG FileQueryBufferLength ) {     PIRP irp;     KEVENT event;     IO_STATUS_BLOCK IoStatusBlock;     PIO_STACK_LOCATION ioStackLocation;      DbgPrint(("Getting file name for %x\n", FileObject));      //     // Initialize the event     //     KeInitializeEvent(&event, SynchronizationEvent, FALSE);      //     // Allocate an irp for this request.  This could also come from a     // private pool, for instance.     //     irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);     if(!irp)     {          //         // Failure!         //         return FALSE;     }      //     // Build the IRP's main body     //     irp->AssociatedIrp.SystemBuffer = FileQueryBuffer;     irp->UserEvent = &event;     irp->UserIosb = &IoStatusBlock;     irp->Tail.Overlay.Thread = PsGetCurrentThread();     irp->Tail.Overlay.OriginalFileObject = FileObject;     irp->RequestorMode = KernelMode;     irp->Flags = 0;      //     // Set up the I/O stack location.     //     ioStackLocation = IoGetNextIrpStackLocation(irp);     ioStackLocation->MajorFunction = IRP_MJ_QUERY_INFORMATION;     ioStackLocation->DeviceObject = DeviceObject;     ioStackLocation->FileObject = FileObject;     ioStackLocation->Parameters.QueryFile.Length = FileQueryBufferLength;     ioStackLocation->Parameters.QueryFile.FileInformationClass = FileInformationClass;      //     // Set the completion routine.     //     IoSetCompletionRoutine(irp, FilemonQueryFileComplete, 0, TRUE, TRUE, TRUE);      //     // Send it to the FSD     //     (void) IoCallDriver(DeviceObject, irp);      //     // Wait for the I/O     //     KeWaitForSingleObject(&event, Executive, KernelMode, TRUE, 0);      //     // Done! Note that since our completion routine frees the IRP we cannot     // touch the IRP now.     //     return NT_SUCCESS( IoStatusBlock.Status ); }   //---------------------------------------------------------------------- // // FilemonGetFullPath // // Takes a fileobject and filename and returns a canonical path, // nicely formatted, in fullpathname. // //---------------------------------------------------------------------- VOID FilemonGetFullPath(     BOOLEAN createPath,     PFILE_OBJECT fileObject,     PHOOK_EXTENSION hookExt,     PCHAR fullPathName ) {     ULONG               pathLen, prefixLen, slashes;     PCHAR               pathOffset, ptr;     BOOLEAN             gotPath;     PFILE_OBJECT        relatedFileObject;     PHASH_ENTRY         hashEntry, newEntry;     ANSI_STRING         fileName;     ANSI_STRING         relatedName;     PFILE_NAME_INFORMATION fileNameInfo;     FILE_INTERNAL_INFORMATION fileInternalInfo;     UNICODE_STRING      fullUniName;     ULONGLONG           mftIndex;      //     // Only do this if a GUI is active and filtering is on     //     if( fullPathName ) fullPathName[0] = 0;     if( !FilterOn || !hookExt || !hookExt->Hooked || !fullPathName)     {          return;     }      //     // Lookup the object in the hash table to see if a name     // has already been generated for it     //     KeEnterCriticalRegion();     ExAcquireResourceSharedLite( &HashResource, TRUE );      hashEntry = HashTable[ HASHOBJECT( fileObject ) ];     while( hashEntry && hashEntry->FileObject != fileObject )     {          hashEntry = hashEntry->Next;     }      //     // Did we find an entry?     //     if( hashEntry )     {          //         // Yes, so get the name from the entry.         //         strcpy( fullPathName, hashEntry->FullPathName );         ExReleaseResourceLite( &HashResource );         KeLeaveCriticalRegion();         return;     }      ExReleaseResourceLite( &HashResource );     KeLeaveCriticalRegion();      //     // We didn't find the name in the hash table so let's either ask     // the file system for it or construct it from the file objects.     //      //     // Calculate prefix length     //     switch( hookExt->Type )     {     case NPFS:         prefixLen = NAMED_PIPE_PREFIX_LENGTH;         break;     case MSFS:         prefixLen = MAIL_SLOT_PREFIX_LENGTH;         break;     default:         if( !fileObject ||                 fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM )         {              prefixLen = 0;          }         else         {              prefixLen = 2; // "C:"         }         break;     }      //     // If there's no file object, we can't even ask for a name.     //     if( !fileObject )     {          if( hookExt->Type == NPFS )      strcpy( fullPathName, NAMED_PIPE_PREFIX );         else if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );         else                             sprintf( fullPathName, "%C:", hookExt->LogicalDrive );         return;     }      //     // Initialize variables     //     fileName.Buffer = NULL;     relatedName.Buffer = NULL;     gotPath = FALSE;      //     // Check for special case first: NTFS volume and a file object     // with no name. It might be a metadata file that we "know" the name of. This     // special case also stops us from querying NTFS for the name of a metadata     // file on versions of NTFS prior to Whistler, which is a good thing since     // that causes hangs and crashes. On Whistler metadata files have file names.     //     if( !fileObject->FileName.Buffer && hookExt->FsAttributes &&             !memcmp( hookExt->FsAttributes->FileSystemName, L"NTFS", sizeof(L"NTFS") - sizeof(WCHAR)))     {          //         // The only file that is opened without a name is a volume         //         if( createPath )         {              sprintf( fullPathName, "%C:", hookExt->LogicalDrive );              //             // Return right here without inserting this into the hash table, since this might             // be the cleanup path of a metadata file and we can retrieve the metada's index             // at a later point.             //             return;          }         else if( FilemonQueryFile( hookExt->FileSystem, fileObject, FileInternalInformation,                                    &fileInternalInfo, sizeof( fileInternalInfo )))         {              //             // Use the name in the metadata name index             //             mftIndex = fileInternalInfo.IndexNumber.QuadPart & ~0xF0000000;             if( mftIndex <= MAX_NTFS_METADATA_FILE )             {                  sprintf( fullPathName, "%C:\\%s", hookExt->LogicalDrive, NtfsMetadataFileNames[ mftIndex ] );                 gotPath = TRUE;             }         }     }      //     // If we are not in the create path, we can ask the file system for the name. If we     // are in the create path, we can't ask the file system for the name of the file object, since     // the file system driver hasn't even seen the file object yet.     //     if( !gotPath && !createPath )     {          //         // Ask the file system for the name of the file, which its required to be         // able to provide for the Win32 filename query function. We could use the         // undocumented ObQueryNameString, but then we'd have to worry about         // re-entrancy issues, since that call generates the IRP that we create         // manually here. Since we send the IRP to the FSD below us, we don't need         // to worry about seeing the IRP in our dispatch entry point. This can fail         // in some cases, so we fall back on constructing the name ourselves if         // we have to.         //         fileNameInfo = (PFILE_NAME_INFORMATION) ExAllocatePool( NonPagedPool,                        MAXPATHLEN * sizeof(WCHAR) );          if( fileNameInfo &&                 FilemonQueryFile(hookExt->FileSystem, fileObject, FileNameInformation,                                  fileNameInfo, (MAXPATHLEN - prefixLen - 1)*sizeof(WCHAR) ))         {              fullUniName.Length = (SHORT) fileNameInfo->FileNameLength;             fullUniName.Buffer = fileNameInfo->FileName;             if( NT_SUCCESS( RtlUnicodeStringToAnsiString( &fileName, &fullUniName, TRUE )))             {                  fullPathName[ fileName.Length + prefixLen ] = 0;                  if( hookExt->Type == NPFS )                 {                      strcpy( fullPathName, NAMED_PIPE_PREFIX );                  }                 else if( hookExt->Type == MSFS )                 {                      strcpy( fullPathName, MAIL_SLOT_PREFIX );                  }                 else if( fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM )                 {                      sprintf( fullPathName, "%C:", hookExt->LogicalDrive );                  }                 else                 {                      //                     // No prefix for network devices                     //                 }                  memcpy( &fullPathName[prefixLen], fileName.Buffer, fileName.Length );                 gotPath = TRUE;                 RtlFreeAnsiString( &fileName );                 fileName.Buffer = NULL;             }         }         if( fileNameInfo ) ExFreePool( fileNameInfo );     }      //     // If we don't have a name yet then we are in the create path, or we failed     // when we asked the file system for the name. In that case we'll go ahead     // and construct the name based on file object names.     //     if( !gotPath )     {          //         // If there is no file name at this point, just return "DEVICE" to indicate         // raw access to a device         //         if( !fileObject->FileName.Buffer )         {              if( hookExt->Type == NPFS )      strcpy( fullPathName, NAMED_PIPE_PREFIX );             else if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );             else                             sprintf( fullPathName, "%C:", hookExt->LogicalDrive );             return;         }          //         // Create the full path name. First, calculate the length taking into         // account space for seperators and the leading prefix         //         if( !NT_SUCCESS( RtlUnicodeStringToAnsiString( &fileName, &fileObject->FileName, TRUE )))         {              if( hookExt->Type == NPFS )      sprintf( fullPathName, "%s: <Out of Memory>", NAMED_PIPE_PREFIX );             else if( hookExt->Type == MSFS ) sprintf( fullPathName, "%s: <Out of Memory>", MAIL_SLOT_PREFIX );             else                             sprintf( fullPathName, "%C: <Out of Memory>", hookExt->LogicalDrive );             return;         }          pathLen = fileName.Length + prefixLen;         relatedFileObject = fileObject->RelatedFileObject;          //         // Only look at related file object if this is a relative name         //         if( fileObject->FileName.Buffer[0] != L'\\' &&                 relatedFileObject && relatedFileObject->FileName.Length )         {              if( !NT_SUCCESS( RtlUnicodeStringToAnsiString( &relatedName, &relatedFileObject->FileName, TRUE )))             {                  if( hookExt->Type == NPFS )      sprintf( fullPathName, "%s: <Out of Memory>", NAMED_PIPE_PREFIX );                 else if( hookExt->Type == MSFS ) sprintf( fullPathName, "%s: <Out of Memory>", MAIL_SLOT_PREFIX );                 else                             sprintf( fullPathName, "%C: <Out of Memory>", hookExt->LogicalDrive );                 RtlFreeAnsiString( &fileName );                 return;             }             pathLen += relatedName.Length + 1;         }          //         // Add the drive letter first at the front of the name         //         if( hookExt->Type == NPFS )      strcpy( fullPathName, NAMED_PIPE_PREFIX );         else if( hookExt->Type == MSFS ) strcpy( fullPathName, MAIL_SLOT_PREFIX );         else if( fileObject->DeviceObject->DeviceType != FILE_DEVICE_NETWORK_FILE_SYSTEM )         {              sprintf( fullPathName, "%C:", hookExt->LogicalDrive );         }          //         // If the name is too long, quit now         //         if( pathLen >= MAXPATHLEN )         {              strcat( fullPathName, " <Name Too Long>" );          }         else         {              //             // Now we can build the path name             //             fullPathName[ pathLen ] = 0;              pathOffset = fullPathName + pathLen - fileName.Length;             memcpy( pathOffset, fileName.Buffer, fileName.Length + 1 );              if( fileObject->FileName.Buffer[0] != L'\\' &&                     relatedFileObject && relatedFileObject->FileName.Length )             {                  //                 // Copy the component, adding a slash separator                 //                 *(pathOffset - 1) = '\\';                 pathOffset -= relatedName.Length + 1;                  memcpy( pathOffset, relatedName.Buffer, relatedName.Length );                  //                 // If we've got to slashes at the front zap one                 //                 if( pathLen > 3 && fullPathName[2] == '\\' && fullPathName[3] == '\\' )                 {                      strcpy( fullPathName + 2, fullPathName + 3 );                 }             }         }     }     if( fileName.Buffer ) RtlFreeAnsiString( &fileName );     if( relatedName.Buffer ) RtlFreeAnsiString( &relatedName );      //     // Network redirector names already specify a share name that we     // have to strip:     //     //     \X:\computer\share\realpath     //     // And we want to present:     //     //     X:\realpath     //     // to the user.     //     if( fileObject->DeviceObject->DeviceType == FILE_DEVICE_NETWORK_FILE_SYSTEM &&             strlen( fullPathName ) >= strlen("\\X:\\") )     {          //         // If this is Win2k the name is specified like this:         //         //    \;X:0\computer\share\realpath         //         // so we have to handle that case as well         //         if( fullPathName[1] == ';' )         {              //             // Win2K-style name. Grab the drive letter             // and skip over the share             //             fullPathName[0] = fullPathName[2];             fullPathName[1] = ':';             fullPathName[2] = '\\';              //             // The third slash after the drive is the             // start of the real path (we start scanning             // at the ':' since we don't want to make assumptions             // about the length of the number).             //             slashes = 0;             ptr = &fullPathName[3];             while( *ptr && slashes != 3 )             {                  if( *ptr == '\\' ) slashes++;                 ptr++;             }             strcpy( &fullPathName[3], ptr );          }         else if( fullPathName[2] == ':' )         {              //             // NT 4-style name. Skip the share name             //             fullPathName[0] = fullPathName[1];             fullPathName[1] = ':';             fullPathName[2] = '\\';              //             // The second slash after the drive's slash (x:\)             // is the start of the real path             //             slashes = 0;             ptr = &fullPathName[3];             while( *ptr && slashes != 3 )             {                  if( *ptr == '\\' ) slashes++;                 ptr++;             }             strcpy( &fullPathName[3], ptr );          }         else         {              //             // Its a UNC path, so add a leading slash             //             RtlMoveMemory( &fullPathName[1], fullPathName, strlen( fullPathName ) + 1);             fullPathName[0] = '\\';         }     }      //     // Allocate a hash entry     //     newEntry = ExAllocatePool( NonPagedPool,                                sizeof(HASH_ENTRY ) + strlen( fullPathName ) + 1);      //     // If no memory for a new entry, oh well.     //     if( newEntry )     {          //         // Fill in the new entry         //         newEntry->FileObject = fileObject;         strcpy( newEntry->FullPathName, fullPathName );          //         // Put it in the hash table         //         KeEnterCriticalRegion();         ExAcquireResourceExclusiveLite( &HashResource, TRUE );          newEntry->Next = HashTable[ HASHOBJECT(fileObject) ];         HashTable[ HASHOBJECT(fileObject) ] = newEntry;          ExReleaseResourceLite( &HashResource );         KeLeaveCriticalRegion();     } }   //---------------------------------------------------------------------- // // FilemonGetProcessNameOffset // // 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 FilemonGetProcessNameOffset(     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; }   //---------------------------------------------------------------------- // // FilemonGetProcess // // Uses undocumented data structure offsets to obtain the name of the // currently executing process. // //---------------------------------------------------------------------- PCHAR FilemonGetProcess(     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; #if defined(_IA64_)         sprintf( ProcessName + strlen(ProcessName), ":%I64d", PsGetCurrentProcessId()); #else         sprintf( ProcessName + strlen(ProcessName), ":%d", PsGetCurrentProcessId()); #endif      }     else     {          strcpy( ProcessName, "???" );     }     return ProcessName; }   //---------------------------------------------------------------------- //          H O O K / U N H O O K   R O U T I N E S //----------------------------------------------------------------------  #if DBG //---------------------------------------------------------------------- // // UnloadDetach // // Detaches from all devices for an unload // //---------------------------------------------------------------------- VOID UnloadDetach(     VOID ) {     ULONG           drive, i;     PDEVICE_OBJECT  device;     PHOOK_EXTENSION hookExt;      //     // Detach from file system devices     //     for( drive = 0; drive < 26; drive++ )     {          if( DriveHookDevices[drive] )         {              device = DriveHookDevices[drive];             hookExt = device->DeviceExtension;             IoDetachDevice( hookExt->FileSystem );             IoDeleteDevice( device );              for( i = 0; i < 26; i++ )             {                  if( DriveHookDevices[i] == device )                 {                      DriveHookDevices[i] = NULL;                 }             }         }     }      //     // Detach from special devices     //     if( NamedPipeHookDevice )     {          IoDetachDevice( NamedPipeHookDevice );         IoDeleteDevice( NamedPipeHookDevice );     }     if( MailSlotHookDevice )     {          IoDetachDevice( MailSlotHookDevice );         IoDeleteDevice( MailSlotHookDevice );     } } #endif // DBG  //---------------------------------------------------------------------- // // HookSpecialFs // // Hook the named pipe or mail slot file system. // //---------------------------------------------------------------------- BOOLEAN HookSpecialFs(     IN PDRIVER_OBJECT DriverObject,     FILE_SYSTEM_TYPE FsType ) {     IO_STATUS_BLOCK     ioStatus;     HANDLE              ntFileHandle;     OBJECT_ATTRIBUTES   objectAttributes;     PDEVICE_OBJECT      fileSysDevice;     PDEVICE_OBJECT      topAttachDevice;     PDEVICE_OBJECT      hookDevice;     UNICODE_STRING      fileNameUnicodeString;     WCHAR               npfsFilename[] = L"\\Device\\NamedPipe";     WCHAR               msfsFilename[] = L"\\Device\\MailSlot";     NTSTATUS            ntStatus;     ULONG               i;     PFILE_OBJECT        fileObject;     PHOOK_EXTENSION     hookExtension;      //     // If we've already hooked it, just return success     //     if( FsType == NPFS && NamedPipeHookDevice ) return TRUE;     if( FsType == MSFS && MailSlotHookDevice ) return TRUE;      //     // We have to figure out what device to hook - first open the volume's     // root directory     //     if( FsType == NPFS ) RtlInitUnicodeString( &fileNameUnicodeString, npfsFilename );     else                 RtlInitUnicodeString( &fileNameUnicodeString, msfsFilename );     InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString,                                 OBJ_CASE_INSENSITIVE, NULL, NULL );     ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE | FILE_ANY_ACCESS,                              &objectAttributes, &ioStatus, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,                              FILE_OPEN,                              FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE,                              NULL, 0 );     if( !NT_SUCCESS( ntStatus ) )     {          DbgPrint(("Filemon: Could not open %s\n", FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));          return FALSE;     }      DbgPrint(("Filemon:  opened the root directory!!! handle: %x\n", ntFileHandle));      //     // Got the file handle, so now look-up the file-object it refers to     //     ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA,                                           NULL, KernelMode, &fileObject, NULL );     if( !NT_SUCCESS( ntStatus ))     {          DbgPrint(("Filemon: Could not get fileobject from %s handle: %x\n",                   FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));         ZwClose( ntFileHandle );          return FALSE;     }      //     // Next, find out what device is associated with the file object by getting its related     // device object     //     fileSysDevice = IoGetRelatedDeviceObject( fileObject );      if( ! fileSysDevice )     {          DbgPrint(("Filemon: Could not get related device object for %s: %x\n",                   FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));          ObDereferenceObject( fileObject );         ZwClose( ntFileHandle );          return FALSE;     }      //     // The file system's device hasn't been hooked already, so make a hooking device     //  object that will be attached to it.     //     ntStatus = IoCreateDevice( DriverObject,                                sizeof(HOOK_EXTENSION),                                NULL,                                fileSysDevice->DeviceType,                                0,                                FALSE,                                &hookDevice );     if( !NT_SUCCESS(ntStatus) )     {          DbgPrint(("Filemon: failed to create associated device %s: %x\n",                   FsType == NPFS ? "NPFS" : "MSFS", ntStatus ));          ObDereferenceObject( fileObject );         ZwClose( ntFileHandle );          return FALSE;     }      //     // Clear the device's init flag as per NT DDK KB article on creating device     // objects from a dispatch routine     //     hookDevice->Flags &= ~DO_DEVICE_INITIALIZING;      //     // Finally, attach to the device. The second we're successfully attached, we may     // start receiving IRPs targetted at the device we've hooked.     //     topAttachDevice = IoAttachDeviceToDeviceStack( hookDevice, fileSysDevice );     if( !topAttachDevice )     {          //         // Couldn' attach for some reason         //         DbgPrint(("Filemon: Connect with Filesystem failed: %s (%x) =>%x\n",                   FsType == NPFS ? "NPFS" : "MSFS", fileSysDevice, ntStatus ));          //         // Derefence the object and get out         //         ObDereferenceObject( fileObject );         ZwClose( ntFileHandle );          return FALSE;      }     else     {          DbgPrint(("Filemon: Successfully connected to Filesystem device %s\n",                   FsType == NPFS ? "NPFS" : "MSFS" ));     }      //     // Setup the device extensions. The drive letter and file system object are stored     // in the extension.     //     hookExtension = hookDevice->DeviceExtension;     hookExtension->LogicalDrive = '\\';     hookExtension->FileSystem   = topAttachDevice;     hookExtension->Hooked       = TRUE;     hookExtension->Type = FsType;      //     // Close the file and update the hooked drive list by entering a     // pointer to the hook device object in it.     //     ObDereferenceObject( fileObject );     ZwClose( ntFileHandle );      if( FsType == NPFS ) NamedPipeHookDevice = hookDevice;     else                 MailSlotHookDevice  = hookDevice;      return TRUE; }   //---------------------------------------------------------------------- // // UnhookSpecialFs // // Unhook the named pipe file or mail slot system. // //---------------------------------------------------------------------- VOID UnhookSpecialFs(     FILE_SYSTEM_TYPE FsType ) {     PHOOK_EXTENSION   hookExt;      if( FsType == NPFS && NamedPipeHookDevice )     {          hookExt = NamedPipeHookDevice->DeviceExtension;         hookExt->Hooked = FALSE;         NamedPipeHookDevice = NULL;      }     else if( FsType == MSFS && MailSlotHookDevice )     {          hookExt = MailSlotHookDevice->DeviceExtension;         hookExt->Hooked = FALSE;         MailSlotHookDevice = NULL;     } }   //---------------------------------------------------------------------- // // HookDrive // // Hook the drive specified by determining which device object to // attach to. The algorithm used here is similar to the one used // internally by NT to determine which device object a file system request // is directed at. // //---------------------------------------------------------------------- BOOLEAN HookDrive(     IN ULONG Drive,     IN PDRIVER_OBJECT DriverObject ) {     IO_STATUS_BLOCK     ioStatus;     HANDLE              ntFileHandle;     OBJECT_ATTRIBUTES   objectAttributes;     PDEVICE_OBJECT      fileSysDevice;     PDEVICE_OBJECT      hookDevice;     UNICODE_STRING      fileNameUnicodeString;     PFILE_FS_ATTRIBUTE_INFORMATION fileFsAttributes;     ULONG               fileFsAttributesSize;     WCHAR               filename[] = L"\\DosDevices\\A:\\";     NTSTATUS            ntStatus;     ULONG               i;     PFILE_OBJECT        fileObject;     PHOOK_EXTENSION     hookExtension;      //     // Is it a legal drive letter?     //     if( Drive >= 26 )     {          return FALSE;     }      //     // Has this drive already been hooked?     //     if( DriveHookDevices[Drive] == NULL )     {          //         // Frob the name to make it refer to the drive specified in the input         // parameter.         //         filename[12] = (CHAR) ('A' + Drive);          //         // We have to figure out what device to hook - first open the volume's         // root directory         //         RtlInitUnicodeString( &fileNameUnicodeString, filename );         InitializeObjectAttributes( &objectAttributes, &fileNameUnicodeString,                                     OBJ_CASE_INSENSITIVE, NULL, NULL );         ntStatus = ZwCreateFile( &ntFileHandle, SYNCHRONIZE | FILE_ANY_ACCESS,                                  &objectAttributes, &ioStatus, NULL, 0, FILE_SHARE_READ | FILE_SHARE_WRITE,                                  FILE_OPEN,                                  FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE,                                  NULL, 0 );         if( !NT_SUCCESS( ntStatus ) )         {              DbgPrint(("Filemon: Could not open drive %c: %x\n", 'A' + Drive, ntStatus ));             return FALSE;         }          DbgPrint(("Filemon:  opened the root directory!!! handle: %x\n", ntFileHandle));          //         // Got the file handle, so now look-up the file-object it refers to         //         ntStatus = ObReferenceObjectByHandle( ntFileHandle, FILE_READ_DATA,                                               NULL, KernelMode, &fileObject, NULL );         if( !NT_SUCCESS( ntStatus ))         {              DbgPrint(("Filemon: Could not get fileobject from handle: %c\n", 'A' + Drive ));             ZwClose( ntFileHandle );             return FALSE;         }          //         // Next, find out what device is associated with the file object by getting its related         // device object         //         fileSysDevice = IoGetRelatedDeviceObject( fileObject );          if( ! fileSysDevice )         {              DbgPrint(("Filemon: Could not get related device object: %c\n", 'A' + Drive ));             ObDereferenceObject( fileObject );             ZwClose( ntFileHandle );             return FALSE;         }          //         // Check the device list to see if we've already attached to this particular device.         // This can happen when more than one drive letter is being handled by the same network         // redirecter         //         for( i = 0; i < 26; i++ )         {              if( DriveHookDevices[i] == fileSysDevice )             {                  //                 // If we're already watching it, associate this drive letter                 // with the others that are handled by the same network driver. This                 // enables us to intelligently update the hooking menus when the user                 // specifies that one of the group should not be watched -we mark all                 // of the related drives as unwatched as well                 //                 ObDereferenceObject( fileObject );                 ZwClose( ntFileHandle );                 DriveHookDevices[ Drive ] = fileSysDevice;                 return TRUE;             }         }          //         // The file system's device hasn't been hooked already, so make a hooking device         //  object that will be attached to it.         //         ntStatus = IoCreateDevice( DriverObject,                                    sizeof(HOOK_EXTENSION),                                    NULL,                                    fileSysDevice->DeviceType,                                    0,                                    FALSE,                                    &hookDevice );         if( !NT_SUCCESS(ntStatus) )         {              DbgPrint(("Filemon: failed to create associated device: %c\n", 'A' + Drive ));              ObDereferenceObject( fileObject );             ZwClose( ntFileHandle );              return FALSE;         }          //         // Clear the device's init flag as per NT DDK KB article on creating device         // objects from a dispatch routine         //         hookDevice->Flags &= ~DO_DEVICE_INITIALIZING;          //         // Setup the device extensions. The drive letter and file system object are stored         // in the extension.         //         hookExtension = hookDevice->DeviceExtension;         hookExtension->LogicalDrive = 'A' + Drive;         hookExtension->FileSystem   = fileSysDevice;         hookExtension->Hooked       = TRUE;         hookExtension->Type         = STANDARD;          //         // Finally, attach to the device. The second we're successfully attached, we may         // start receiving IRPs targetted at the device we've hooked.         //         ntStatus = IoAttachDeviceByPointer( hookDevice, fileSysDevice );         if( !NT_SUCCESS(ntStatus) )         {              //             // Couldn' attach for some reason             //             DbgPrint(("Filemon: Connect with Filesystem failed: %c (%x) =>%x\n",                       'A' + Drive, fileSysDevice, ntStatus ));              //             // Derefence the object and get out             //             ObDereferenceObject( fileObject );             ZwClose( ntFileHandle );              return FALSE;          }         else         {              //             // Make a new drive group for the device,l if it does not have one             // already             //             DbgPrint(("Filemon: Successfully connected to Filesystem device %c\n", 'A' + Drive ));         }          //         // Determine if this is a NTFS drive         //         fileFsAttributesSize = sizeof( FILE_FS_ATTRIBUTE_INFORMATION) + MAXPATHLEN;         hookExtension->FsAttributes = (PFILE_FS_ATTRIBUTE_INFORMATION) ExAllocatePool( NonPagedPool,                                       fileFsAttributesSize );         if( hookExtension->FsAttributes &&                 !NT_SUCCESS( IoQueryVolumeInformation( fileObject, FileFsAttributeInformation,                              fileFsAttributesSize, hookExtension->FsAttributes,                              &fileFsAttributesSize )))         {              //             // On failure, we just don't have attributes for this file system             //             ExFreePool( hookExtension->FsAttributes );             hookExtension->FsAttributes = NULL;         }          //         // Close the file and update the hooked drive list by entering a         // pointer to the hook device object in it.         //         ObDereferenceObject( fileObject );          ZwClose( ntFileHandle );          DriveHookDevices[Drive] = hookDevice;      }     else     {          hookExtension = DriveHookDevices[Drive]->DeviceExtension;         hookExtension->Hooked = TRUE;     }     return TRUE; }   //---------------------------------------------------------------------- // // UnhookDrive // // Unhook a previously hooked drive. // //---------------------------------------------------------------------- VOID UnhookDrive(     IN ULONG Drive ) {     PHOOK_EXTENSION hookExt;      //     // If the drive has been hooked, unhook it and delete the hook     // device object     //     if( DriveHookDevices[Drive] )     {          hookExt = DriveHookDevices[Drive]->DeviceExtension;         hookExt->Hooked = FALSE;     } }   //---------------------------------------------------------------------- // // HookDriveSet // // Hook/Unhook a set of drives specified by user. Return the set // that is currently hooked. // //---------------------------------------------------------------------- ULONG HookDriveSet(     IN ULONG DriveSet,     IN PDRIVER_OBJECT DriverObject ) {     PHOOK_EXTENSION hookExt;     ULONG           drive, i;     ULONG           bit;      //     // Scan the drive table, looking for hits on the DriveSet bitmask     //     for ( drive = 0; drive < 26; ++drive )     {          bit = 1 << drive;          //         // Are we supposed to hook this drive?         //         if( (bit & DriveSet) &&                 !(bit & CurrentDriveSet) )         {              //             // Try to hook drive             //             if( !HookDrive( drive, DriverObject ) )             {                  //                 // Remove from drive set if can't be hooked                 //                 DriveSet &= ~bit;              }             else             {                  //                 // hook drives in same drive group                 //                 for( i = 0; i < 26; i++ )                 {                      if( DriveHookDevices[i] == DriveHookDevices[ drive ] )                     {                          DriveSet |= ( 1 << i );                     }                 }             }          }         else if( !(bit & DriveSet) &&                  (bit & CurrentDriveSet) )         {              //             // Unhook this drive and all in the group             //             for( i = 0; i < 26; i++ )             {                  if( DriveHookDevices[i] == DriveHookDevices[ drive ] )                 {                      UnhookDrive( i );                     DriveSet &= ~(1 << i);                 }             }         }     }      //     // Return set of drives currently hooked     //     CurrentDriveSet = DriveSet;     return DriveSet; }  //---------------------------------------------------------------------- // // ControlCodeString // // Takes a control code and sees if we know what it is. // //---------------------------------------------------------------------- PCHAR ControlCodeString(     PIO_STACK_LOCATION IrpSp,     ULONG ControlCode,     PCHAR Buffer,     PCHAR Other ) {     Other[0] = 0;     switch( ControlCode )     {      case FSCTL_REQUEST_OPLOCK_LEVEL_1:         strcpy( Buffer, "FSCTL_REQUEST_OPLOCK_LEVEL_1" );         break;     case FSCTL_REQUEST_OPLOCK_LEVEL_2:         strcpy( Buffer, "FSCTL_REQUEST_OPLOCK_LEVEL_2" );         break;     case FSCTL_REQUEST_BATCH_OPLOCK:         strcpy( Buffer, "FSCTL_REQUEST_BATCH_OPLOCK" );         break;     case FSCTL_OPLOCK_BREAK_ACKNOWLEDGE:         strcpy( Buffer, "FSCTL_OPLOCK_BREAK_ACKNOWLEDGE" );         break;     case FSCTL_OPBATCH_ACK_CLOSE_PENDING:         strcpy( Buffer, "FSCTL_OPBATCH_ACK_CLOSE_PENDING" );         break;     case FSCTL_OPLOCK_BREAK_NOTIFY:         strcpy( Buffer, "FSCTL_OPLOCK_BREAK_NOTIFY" );         break;     case FSCTL_LOCK_VOLUME:         strcpy( Buffer, "FSCTL_LOCK_VOLUME" );         break;     case FSCTL_UNLOCK_VOLUME:         strcpy( Buffer, "FSCTL_UNLOCK_VOLUME" );         break;     case FSCTL_DISMOUNT_VOLUME:         strcpy( Buffer, "FSCTL_DISMOUNT_VOLUME" );         break;     case FSCTL_IS_VOLUME_MOUNTED:         strcpy( Buffer, "FSCTL_IS_VOLUME_MOUNTED" );         break;     case FSCTL_IS_PATHNAME_VALID:         strcpy( Buffer, "FSCTL_IS_PATHNAME_VALID" );         break;     case FSCTL_MARK_VOLUME_DIRTY:         strcpy( Buffer, "FSCTL_MARK_VOLUME_DIRTY" );         break;     case FSCTL_QUERY_RETRIEVAL_POINTERS:         strcpy( Buffer, "FSCTL_QUERY_RETRIEVAL_POINTERS" );         break;     case FSCTL_GET_COMPRESSION:         strcpy( Buffer, "FSCTL_GET_COMPRESSION" );         break;     case FSCTL_SET_COMPRESSION:         strcpy( Buffer, "FSCTL_SET_COMPRESSION" );         break;     case FSCTL_OPLOCK_BREAK_ACK_NO_2:         strcpy( Buffer, "FSCTL_OPLOCK_BREAK_ACK_NO_2" );         break;     case FSCTL_QUERY_FAT_BPB:         strcpy( Buffer, "FSCTL_QUERY_FAT_BPB" );         break;     case FSCTL_REQUEST_FILTER_OPLOCK:         strcpy( Buffer, "FSCTL_REQUEST_FILTER_OPLOCK" );         break;     case FSCTL_FILESYSTEM_GET_STATISTICS:         strcpy( Buffer, "FSCTL_FILESYSTEM_GET_STATISTICS" );         break;     case FSCTL_GET_NTFS_VOLUME_DATA:         strcpy( Buffer, "FSCTL_GET_NTFS_VOLUME_DATA" );         break;     case FSCTL_GET_NTFS_FILE_RECORD:         strcpy( Buffer, "FSCTL_GET_NTFS_FILE_RECORD" );         break;     case FSCTL_GET_VOLUME_BITMAP:         strcpy( Buffer, "FSCTL_GET_VOLUME_BITMAP" );         break;     case FSCTL_GET_RETRIEVAL_POINTERS:         strcpy( Buffer, "FSCTL_GET_RETRIEVAL_POINTERS" );         break;     case FSCTL_MOVE_FILE:         strcpy( Buffer, "FSCTL_MOVE_FILE" );         break;     case FSCTL_IS_VOLUME_DIRTY:         strcpy( Buffer, "FSCTL_IS_VOLUME_DIRTY" );         break;     case FSCTL_ALLOW_EXTENDED_DASD_IO:         strcpy( Buffer, "FSCTL_ALLOW_EXTENDED_DASD_IO" );         break;         //         // *** new to Win2K (NT 5.0)         //     case FSCTL_READ_PROPERTY_DATA:         strcpy( Buffer, "FSCTL_READ_PROPERTY_DATA" );         break;     case FSCTL_WRITE_PROPERTY_DATA:         strcpy( Buffer, "FSCTL_WRITE_PROPERTY_DATA" );         break;     case FSCTL_FIND_FILES_BY_SID:         strcpy( Buffer, "FSCTL_FIND_FILES_BY_SID" );         break;     case FSCTL_DUMP_PROPERTY_DATA:         strcpy( Buffer, "FSCTL_DUMP_PROPERTY_DATA" );         break;     case FSCTL_SET_OBJECT_ID:         strcpy( Buffer, "FSCTL_SET_OBJECT_ID" );         break;     case FSCTL_GET_OBJECT_ID:         strcpy( Buffer, "FSCTL_GET_OBJECT_ID" );         break;     case FSCTL_DELETE_OBJECT_ID:         strcpy( Buffer, "FSCTL_DELETE_OBJECT_ID" );         break;     case FSCTL_SET_REPARSE_POINT:         strcpy( Buffer, "FSCTL_SET_REPARSE_POINT" );         break;     case FSCTL_GET_REPARSE_POINT:         strcpy( Buffer, "FSCTL_GET_REPARSE_POINT" );         break;     case FSCTL_DELETE_REPARSE_POINT:         strcpy( Buffer, "FSCTL_DELETE_REPARSE_POINT" );         break;     case FSCTL_ENUM_USN_DATA:         strcpy( Buffer, "FSCTL_ENUM_USN_DATA" );         break;     case FSCTL_SECURITY_ID_CHECK:         strcpy( Buffer, "FSCTL_SECURITY_ID_CHECK" );         break;     case FSCTL_READ_USN_JOURNAL:         strcpy( Buffer, "FSCTL_READ_USN_JOURNAL" );         break;     case FSCTL_SET_OBJECT_ID_EXTENDED:         strcpy( Buffer, "FSCTL_SET_OBJECT_ID_EXTENDED" );         break;     case FSCTL_CREATE_OR_GET_OBJECT_ID:         strcpy( Buffer, "FSCTL_CREATE_OR_GET_OBJECT_ID" );         break;     case FSCTL_SET_SPARSE:         strcpy( Buffer, "FSCTL_SET_SPARSE" );         break;     case FSCTL_SET_ZERO_DATA:         strcpy( Buffer, "FSCTL_SET_ZERO_DATA" );         break;     case FSCTL_QUERY_ALLOCATED_RANGES:         strcpy( Buffer, "FSCTL_QUERY_ALLOCATED_RANGES" );         break;     case FSCTL_ENABLE_UPGRADE:         strcpy( Buffer, "FSCTL_ENABLE_UPGRADE" );         break;     case FSCTL_SET_ENCRYPTION:         strcpy( Buffer, "FSCTL_SET_ENCRYPTION" );         break;     case FSCTL_ENCRYPTION_FSCTL_IO:         strcpy( Buffer, "FSCTL_ENCRYPTION_FSCTL_IO" );         break;     case FSCTL_WRITE_RAW_ENCRYPTED:         strcpy( Buffer, "FSCTL_WRITE_RAW_ENCRYPTED" );         break;     case FSCTL_READ_RAW_ENCRYPTED:         strcpy( Buffer, "FSCTL_READ_RAW_ENCRYPTED" );         break;     case FSCTL_CREATE_USN_JOURNAL:         strcpy( Buffer, "FSCTL_CREATE_USN_JOURNAL" );         break;     case FSCTL_READ_FILE_USN_DATA:         strcpy( Buffer, "FSCTL_READ_FILE_USN_DATA" );         break;     case FSCTL_WRITE_USN_CLOSE_RECORD:         strcpy( Buffer, "FSCTL_WRITE_USN_CLOSE_RECORD" );         break;     case FSCTL_EXTEND_VOLUME:         strcpy( Buffer, "FSCTL_EXTEND_VOLUME" );         break;         //         // Named pipe file system controls         // (these are all undocumented)         //     case FSCTL_PIPE_DISCONNECT:         strcpy( Buffer, "FSCTL_PIPE_DISCONNECT" );         break;     case FSCTL_PIPE_ASSIGN_EVENT:         strcpy( Buffer, "FSCTL_PIPE_ASSIGN_EVENT" );         break;     case FSCTL_PIPE_QUERY_EVENT:         strcpy( Buffer, "FSCTL_PIPE_QUERY_EVENT" );         break;     case FSCTL_PIPE_LISTEN:         strcpy( Buffer, "FSCTL_PIPE_LISTEN" );         break;     case FSCTL_PIPE_IMPERSONATE:         strcpy( Buffer, "FSCTL_PIPE_IMPERSONATE" );         break;     case FSCTL_PIPE_WAIT:         strcpy( Buffer, "FSCTL_PIPE_WAIT" );         break;     case FSCTL_PIPE_QUERY_CLIENT_PROCESS:         strcpy( Buffer, "FSCTL_QUERY_CLIENT_PROCESS" );         break;     case FSCTL_PIPE_SET_CLIENT_PROCESS:         strcpy( Buffer, "FSCTL_PIPE_SET_CLIENT_PROCESS");         break;     case FSCTL_PIPE_PEEK:         strcpy( Buffer, "FSCTL_PIPE_PEEK" );         break;     case FSCTL_PIPE_INTERNAL_READ:         strcpy( Buffer, "FSCTL_PIPE_INTERNAL_READ" );         sprintf( Other, "ReadLen: %d",                  IrpSp->Parameters.DeviceIoControl.InputBufferLength );         break;     case FSCTL_PIPE_INTERNAL_WRITE:         strcpy( Buffer, "FSCTL_PIPE_INTERNAL_WRITE" );         sprintf( Other, "WriteLen: %d",                  IrpSp->Parameters.DeviceIoControl.InputBufferLength );         break;     case FSCTL_PIPE_TRANSCEIVE:         strcpy( Buffer, "FSCTL_PIPE_TRANSCEIVE" );         sprintf( Other, "WriteLen: %d ReadLen: %d",                  IrpSp->Parameters.DeviceIoControl.InputBufferLength,                  IrpSp->Parameters.DeviceIoControl.OutputBufferLength );         break;     case FSCTL_PIPE_INTERNAL_TRANSCEIVE:         strcpy( Buffer, "FSCTL_PIPE_INTERNAL_TRANSCEIVE" );         sprintf( Other, "WriteLen: %d ReadLen: %d",                  IrpSp->Parameters.DeviceIoControl.InputBufferLength,                  IrpSp->Parameters.DeviceIoControl.OutputBufferLength );         break;         //         // Mail slot file system controls         // (these are all undocumented)         //     case FSCTL_MAILSLOT_PEEK:         strcpy( Buffer, "FSCTL_MAILSLOT_PEEK" );         break;          //         // Undocumented network redirector controls         //     case FSCTL_NETWORK_GET_CONNECTION_INFO:         strcpy( Buffer, "FSCTL_NETWORK_GET_CONNECTION_INFO" );         break;     case FSCTL_NETWORK_ENUMERATE_CONNECTIONS:         strcpy( Buffer, "FSCTL_NETWORK_ENUMERATE_CONNECTIONS");         break;     case FSCTL_NETWORK_DELETE_CONNECTION:         strcpy( Buffer, "FSCTL_NETWORK_DELETE_CONNECTION" );         break;     case FSCTL_NETWORK_SET_CONFIGURATION_INFO:         strcpy( Buffer, "FSCTL_NETWORK_SET_CONFIGURATION_INFO" );         break;     case FSCTL_NETWORK_GET_CONFIGURATION_INFO:         strcpy( Buffer, "FSCTL_NETWORK_GET_CONFIGURATION_INFO" );         break;     case FSCTL_NETWORK_GET_STATISTICS:         strcpy( Buffer, "FSCTL_NETWORK_GET_STATISTICS" );         break;     case FSCTL_NETWORK_SET_DOMAIN_NAME:         strcpy( Buffer, "FSCTL_NETWORK_SET_DOMAIN_NAME" );         break;     case FSCTL_NETWORK_REMOTE_BOOT_INIT_SCRT:         strcpy( Buffer, "FSCTL_NETWORK_REMOTE_BOOT_INIT_SCRT" );         break;     default:          sprintf( Buffer, "IOCTL: 0x%X", ControlCode );         break;     }     return Buffer; }   //---------------------------------------------------------------------- // // ErrorString // // Returns string representing the passed error condition. // //---------------------------------------------------------------------- PCHAR ErrorString(     NTSTATUS RetStat,     PCHAR Buffer ) {     switch( RetStat )     {      case STATUS_SUCCESS:         strcpy( Buffer, "SUCCESS" );         break;     case STATUS_CRC_ERROR:         strcpy( Buffer, "CRC ERROR" );         break;     case STATUS_NOT_IMPLEMENTED:         strcpy( Buffer, "NOT IMPLEMENTED" );         break;     case STATUS_EAS_NOT_SUPPORTED:         strcpy( Buffer, "EAS NOT SUPPORTED" );         break;     case STATUS_EA_TOO_LARGE:         strcpy( Buffer, "EA TOO LARGE");         break;     case STATUS_NONEXISTENT_EA_ENTRY:         strcpy( Buffer, "NONEXISTENT EA ENTRY");         break;     case STATUS_BAD_NETWORK_NAME:         strcpy( Buffer, "BAD NETWORK NAME" );         break;     case STATUS_NOTIFY_ENUM_DIR:         strcpy( Buffer, "NOTIFY ENUM DIR" );         break;     case STATUS_FILE_CORRUPT_ERROR:         strcpy( Buffer, "FILE CORRUPT" );         break;     case STATUS_DISK_CORRUPT_ERROR:         strcpy( Buffer, "DISK CORRUPT" );         break;     case STATUS_RANGE_NOT_LOCKED:         strcpy( Buffer, "RANGE NOT LOCKED" );         break;     case STATUS_FILE_CLOSED:         strcpy( Buffer, "FILE CLOSED" );         break;     case STATUS_IN_PAGE_ERROR:         strcpy( Buffer, "IN PAGE ERROR" );         break;     case STATUS_CANCELLED:         strcpy( Buffer, "CANCELLED" );         break;     case STATUS_QUOTA_EXCEEDED:         strcpy( Buffer, "QUOTA EXCEEDED" );         break;     case STATUS_NOT_SUPPORTED:         strcpy( Buffer, "NOT SUPPORTED" );         break;     case STATUS_NO_MORE_FILES:         strcpy( Buffer, "NO MORE FILES" );         break;     case STATUS_BUFFER_TOO_SMALL:         strcpy( Buffer, "BUFFER TOO SMALL" );         break;     case STATUS_OBJECT_NAME_INVALID:         strcpy( Buffer, "NAME INVALID" );         break;     case STATUS_OBJECT_NAME_NOT_FOUND:         strcpy( Buffer, "FILE NOT FOUND" );         break;     case STATUS_NOT_A_DIRECTORY:         strcpy( Buffer, "NOT A DIRECTORY" );         break;     case STATUS_NO_SUCH_FILE:         strcpy( Buffer, "NO SUCH FILE" );         break;     case STATUS_OBJECT_NAME_COLLISION:         strcpy( Buffer, "NAME COLLISION" );         break;     case STATUS_NONEXISTENT_SECTOR:         strcpy( Buffer, "NONEXISTENT SECTOR" );         break;     case STATUS_BAD_NETWORK_PATH:         strcpy( Buffer, "BAD NETWORK PATH" );         break;     case STATUS_OBJECT_PATH_NOT_FOUND:         strcpy( Buffer, "PATH NOT FOUND" );         break;     case STATUS_NO_SUCH_DEVICE:         strcpy( Buffer, "INVALID PARAMETER" );         break;     case STATUS_END_OF_FILE:         strcpy( Buffer, "END OF FILE" );         break;     case STATUS_NOTIFY_CLEANUP:         strcpy( Buffer, "NOTIFY CLEANUP" );         break;     case STATUS_BUFFER_OVERFLOW:         strcpy( Buffer, "BUFFER OVERFLOW" );         break;     case STATUS_NO_MORE_ENTRIES:         strcpy( Buffer, "NO MORE ENTRIES" );         break;     case STATUS_ACCESS_DENIED:         strcpy( Buffer, "ACCESS DENIED" );         break;     case STATUS_SHARING_VIOLATION:         strcpy( Buffer, "SHARING VIOLATION" );         break;     case STATUS_INVALID_PARAMETER:         strcpy( Buffer, "INVALID PARAMETER" );         break;     case STATUS_OPLOCK_BREAK_IN_PROGRESS:         strcpy( Buffer, "OPLOCK BREAK" );         break;     case STATUS_OPLOCK_NOT_GRANTED:         strcpy( Buffer, "OPLOCK NOT GRANTED" );         break;     case STATUS_FILE_LOCK_CONFLICT:         strcpy( Buffer, "FILE LOCK CONFLICT" );         break;     case STATUS_PENDING:         strcpy( Buffer, "PENDING" );         break;     case STATUS_REPARSE:         strcpy( Buffer, "REPARSE" );         break;     case STATUS_MORE_ENTRIES:         strcpy( Buffer, "MORE" );         break;     case STATUS_DELETE_PENDING:         strcpy( Buffer, "DELETE PEND" );         break;     case STATUS_CANNOT_DELETE:         strcpy( Buffer, "CANNOT DELETE" );         break;     case STATUS_LOCK_NOT_GRANTED:         strcpy( Buffer, "NOT GRANTED" );         break;     case STATUS_FILE_IS_A_DIRECTORY:         strcpy( Buffer, "IS DIRECTORY" );         break;     case STATUS_ALREADY_COMMITTED:         strcpy( Buffer, "ALREADY COMMITTED" );         break;     case STATUS_INVALID_EA_FLAG:         strcpy( Buffer, "INVALID EA FLAG" );         break;     case STATUS_INVALID_INFO_CLASS:         strcpy( Buffer, "INVALID INFO CLASS" );         break;     case STATUS_INVALID_HANDLE:         strcpy( Buffer, "INVALID HANDLE" );         break;     case STATUS_INVALID_DEVICE_REQUEST:         strcpy( Buffer, "INVALID DEVICE REQUEST" );         break;     case STATUS_WRONG_VOLUME:         strcpy( Buffer, "WRONG VOLUME" );         break;     case STATUS_UNEXPECTED_NETWORK_ERROR:         strcpy( Buffer, "NETWORK ERROR" );         break;     case STATUS_DFS_UNAVAILABLE:         strcpy( Buffer, "DFS UNAVAILABLE" );         break;     case STATUS_LOG_FILE_FULL:         strcpy( Buffer, "LOG FILE FULL" );         break;     case STATUS_INVALID_DEVICE_STATE:         strcpy( Buffer, "INVALID DEVICE STATE" );         break;     case STATUS_NO_MEDIA_IN_DEVICE:         strcpy( Buffer, "NO MEDIA");         break;     case STATUS_DISK_FULL:         strcpy( Buffer, "DISK FULL");         break;     case STATUS_DIRECTORY_NOT_EMPTY:         strcpy( Buffer, "NOT EMPTY");         break;          //         // Named pipe errors         //     case STATUS_INSTANCE_NOT_AVAILABLE:         strcpy( Buffer, "INSTANCE NOT AVAILABLE" );         break;     case STATUS_PIPE_NOT_AVAILABLE:         strcpy( Buffer, "PIPE NOT AVAILABLE" );         break;     case STATUS_INVALID_PIPE_STATE:         strcpy( Buffer, "INVALID PIPE STATE" );         break;     case STATUS_PIPE_BUSY:         strcpy( Buffer, "PIPE BUSY" );         break;     case STATUS_PIPE_DISCONNECTED:         strcpy( Buffer, "PIPE DISCONNECTED" );         break;     case STATUS_PIPE_CLOSING:         strcpy( Buffer, "PIPE CLOSING" );         break;     case STATUS_PIPE_CONNECTED:         strcpy( Buffer, "PIPE CONNECTED" );         break;     case STATUS_PIPE_LISTENING:         strcpy( Buffer, "PIPE LISTENING" );         break;     case STATUS_INVALID_READ_MODE:         strcpy( Buffer, "INVALID READ MODE" );         break;     case STATUS_PIPE_EMPTY:         strcpy( Buffer, "PIPE EMPTY" );         break;     case STATUS_PIPE_BROKEN:         strcpy( Buffer, "PIPE BROKEN" );         break;     case STATUS_IO_TIMEOUT:         strcpy( Buffer, "IO TIMEOUT" );         break;     default:         sprintf( Buffer, "* 0x%X", RetStat );         break;     }      return Buffer; }  //---------------------------------------------------------------------- // // CreateOptionsString // // Takes the options mask and returns a string that represents // the settings. // //---------------------------------------------------------------------- PCHAR CreateOptionsString(     ULONG Options,     PCHAR Buffer ) {     ULONG  disposition;      Buffer[0] = 0;     disposition = (Options >> 24) & 0xFF;      switch( disposition )     {     case FILE_SUPERSEDE:         strcat( Buffer, "Supersede " );         break;     case FILE_CREATE:         strcat( Buffer, "Create " );         break;     case FILE_OPEN_IF:         strcat( Buffer, "OpenIf " );         break;     case FILE_OPEN:         strcat( Buffer, "Open " );         break;     case FILE_OVERWRITE:         strcat( Buffer, "Overwrite " );         break;     case FILE_OVERWRITE_IF:         strcat( Buffer, "OverwriteIf " );         break;     }      if( Options & FILE_DIRECTORY_FILE )         strcat( Buffer, "Directory " );     if( Options & FILE_WRITE_THROUGH )         strcat( Buffer, "WriteThrough " );     if( Options & FILE_SEQUENTIAL_ONLY )         strcat( Buffer, "Sequential " );     if( Options & FILE_NO_INTERMEDIATE_BUFFERING )         strcat( Buffer, "NoBuffer" );     if( Options & FILE_OPEN_BY_FILE_ID )         strcat( Buffer, "ByID");     return Buffer; }  //---------------------------------------------------------------------- // // CreateAttributesString // // Take attributes and return a string that represents them. // //---------------------------------------------------------------------- PCHAR CreateAttributesString(     USHORT Attributes,     PCHAR Buffer ) {     Buffer[0] = 0;     if( !Attributes )     {         strcat( Buffer, "Any" );         return Buffer;     }     if( Attributes & FILE_ATTRIBUTE_COMPRESSED) strcat( Buffer, "C" );     if( Attributes & FILE_ATTRIBUTE_TEMPORARY) strcat( Buffer, "T" );     if( Attributes & FILE_ATTRIBUTE_DIRECTORY) strcat( Buffer, "D" );     if( Attributes & FILE_ATTRIBUTE_READONLY) strcat( Buffer, "R" );     if( Attributes & FILE_ATTRIBUTE_HIDDEN )  strcat( Buffer, "H" );     if( Attributes & FILE_ATTRIBUTE_SYSTEM )  strcat( Buffer, "S" );     if( Attributes & FILE_ATTRIBUTE_ARCHIVE ) strcat( Buffer, "A" );     if( Attributes & FILE_ATTRIBUTE_NORMAL )  strcat( Buffer, "N" );     return Buffer; }   //---------------------------------------------------------------------- //                F A S T I O   R O U T I N E S // // NOTE: There is no need for us to worry about accessing fastio // parameters within try/except because the I/O manager has either // probed the validity of the arguments or calls within its own // try/except block (it doesn't trust us anyway :-) ). // //----------------------------------------------------------------------  //---------------------------------------------------------------------- // // FilemonFastIoCheckIfPossible // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoCheckifPossible(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN BOOLEAN Wait,     IN ULONG LockKey,     IN BOOLEAN CheckForReadOperation,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN         retval = FALSE;     PHOOK_EXTENSION hookExt;     CHAR            *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER   timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER   dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoCheckIfPossible ) )     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoCheckIfPossible(                      FileObject, FileOffset, Length,                      Wait, LockKey, CheckForReadOperation, IoStatus, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked )         {              TIMESTAMPSTOP();              LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_CHECK_IF_POSSIBLE\t%s\t%s Offset: %d Length: %d\t%s",                        FilemonGetProcess( name ), fullPathName,                        CheckForReadOperation ? "Read:" : "Write:",                        FileOffset->LowPart, Length,                        retval ? "SUCCESS" : "FAILURE" );         }         FREEPATHNAME();     }      return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoRead // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoRead(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN BOOLEAN Wait,     IN ULONG LockKey,     OUT PVOID Buffer,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoRead ) )     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoRead(                      FileObject, FileOffset, Length,                      Wait, LockKey, Buffer, IoStatus, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_READ\t%s\tOffset: %d Length: %ld\t%s",                        FilemonGetProcess( name ), fullPathName,                        FileOffset->LowPart, Length,                        retval ? ErrorString( IoStatus->Status, errorBuf) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoWrite // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoWrite(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN BOOLEAN Wait,     IN ULONG LockKey,     IN PVOID Buffer,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN              retval = FALSE;     PHOOK_EXTENSION      hookExt;     CHAR                 *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER        timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER        dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoWrite ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoWrite(                      FileObject, FileOffset, Length, Wait, LockKey,                      Buffer, IoStatus, hookExt->FileSystem );          if( FilterDef.logwrites && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_WRITE\t%s\tOffset: %d Length: %d\t%s",                        FilemonGetProcess( name ), fullPathName,                        FileOffset->LowPart, Length,                        retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoQueryBasicinfo // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoQueryBasicInfo(     IN PFILE_OBJECT FileObject,     IN BOOLEAN Wait,     OUT PFILE_BASIC_INFORMATION Buffer,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     CHAR                attributeString[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoQueryBasicInfo ) )     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoQueryBasicInfo(                      FileObject, Wait, Buffer, IoStatus, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked )         {              TIMESTAMPSTOP();             if( retval )             {                 LogRecord( TRUE, NULL,                            &dateTime, &timeResult,                            "%s\tFASTIO_QUERY_BASIC_INFO\t%s\tAttributes: %s\t%s",                            FilemonGetProcess( name ), fullPathName,                            NT_SUCCESS(IoStatus->Status) ?                            CreateAttributesString((USHORT)((PFILE_BASIC_INFORMATION) Buffer)->FileAttributes,                                                   attributeString ) :                            "Error",                            retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );              }             else             {                 LogRecord( TRUE, NULL,                            &dateTime, &timeResult,                            "%s\tFASTIO_QUERY_BASIC_INFO\t%s\t\t%s",                            FilemonGetProcess( name ), fullPathName, retval ? "SUCCESS" : "FAILURE" );             }         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoQueryStandardInfo // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoQueryStandardInfo(     IN PFILE_OBJECT FileObject,     IN BOOLEAN Wait,     OUT PFILE_STANDARD_INFORMATION Buffer,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoQueryStandardInfo ) )     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoQueryStandardInfo(                      FileObject, Wait, Buffer, IoStatus, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked )         {              TIMESTAMPSTOP();             if( retval )             {                 LogRecord( TRUE, NULL,                            &dateTime, &timeResult,                            "%s\tFASTIO_QUERY_STANDARD_INFO\t%s\tSize: %d\t%s",                            FilemonGetProcess( name ), fullPathName,                            ((PFILE_STANDARD_INFORMATION) Buffer)->EndOfFile.LowPart,                            retval ? "SUCCESS" : "FAILURE" );             }             else             {                 LogRecord( TRUE, NULL,                            &dateTime, &timeResult,                            "%s\tFASTIO_QUERY_STANDARD_INFO\t%s\t\t%s",                            FilemonGetProcess( name ), fullPathName,                            retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );             }         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoLock // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoLock(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN PLARGE_INTEGER Length,     PEPROCESS ProcessId,     ULONG Key,     BOOLEAN FailImmediately,     BOOLEAN ExclusiveLock,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoLock ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoLock(                      FileObject, FileOffset, Length, ProcessId, Key, FailImmediately,                      ExclusiveLock, IoStatus, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_LOCK\t%s\tExcl: %s Offset: %d Length: %d\t%s",                        FilemonGetProcess( name ), fullPathName,                        ExclusiveLock ? "Yes" : "No", FileOffset ? FileOffset->LowPart : 0,                        Length ? Length->LowPart : 0, retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoUnlockSingle // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoUnlockSingle(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN PLARGE_INTEGER Length,     PEPROCESS ProcessId,     ULONG Key,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoUnlockSingle ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoUnlockSingle(                      FileObject, FileOffset, Length, ProcessId, Key,                      IoStatus, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_UNLOCK\t%s\tOffset: %d Length: %d\t%s",                        FilemonGetProcess( name ), fullPathName,                        FileOffset ? FileOffset->LowPart : 0, Length ? Length->LowPart : 0,                        retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoUnlockAll // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoUnlockAll(     IN PFILE_OBJECT FileObject,     PEPROCESS ProcessId,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT(hookExt, FastIoUnlockAll ) )     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoUnlockAll(                      FileObject, ProcessId, IoStatus, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_UNLOCK_ALL\t%s\t\t%s",                        FilemonGetProcess( name ), fullPathName,                        retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoUnlockAllByKey // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoUnlockAllByKey(     IN PFILE_OBJECT FileObject,     PEPROCESS ProcessId,     ULONG Key,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoUnlockAllByKey ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoUnlockAllByKey(                      FileObject, ProcessId, Key, IoStatus, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_UNLOCK_ALL_BY_KEY\t%s\t\t%s",                        FilemonGetProcess( name ), fullPathName,                        retval ? ErrorString( IoStatus->Status, errorBuf) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoQueryNetworkOpenInfo // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoQueryNetworkOpenInfo(     IN PFILE_OBJECT FileObject,     IN BOOLEAN Wait,     OUT struct _FILE_NETWORK_OPEN_INFORMATION *Buffer,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoQueryNetworkOpenInfo ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoQueryNetworkOpenInfo(                      FileObject, Wait, Buffer, IoStatus, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_QUERY_NETWORK_OPEN_INFO\t%s\t\t%s",                        FilemonGetProcess( name ), fullPathName,                        retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoAcquireForModWrite // //---------------------------------------------------------------------- NTSTATUS FilemonFastIoAcquireForModWrite(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER EndingOffset,     OUT struct _ERESOURCE **ResourceToRelease,     IN PDEVICE_OBJECT DeviceObject ) {     NTSTATUS            retval = STATUS_NOT_IMPLEMENTED;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, errval[ERRORLEN], name[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, AcquireForModWrite ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->AcquireForModWrite(                      FileObject, EndingOffset, ResourceToRelease, hookExt->FileSystem );          if( FilterDef.logwrites && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_ACQUIRE_FOR_MOD_WRITE\t%s\tEndOffset: %d\t%s",                        FilemonGetProcess( name ), fullPathName, EndingOffset,                        ErrorString( retval, errval ) );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoMdlRead // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoMdlRead(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN ULONG LockKey,     OUT PMDL *MdlChain,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, MdlRead ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->MdlRead(                      FileObject, FileOffset, Length, LockKey, MdlChain,                      IoStatus, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_MDL_READ\t%s\tOffset: %d Length: %d\t%s",                        FilemonGetProcess( name ), fullPathName,                        FileOffset->LowPart, Length,                        retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoMdlReadComplete // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoMdlReadComplete(     IN PFILE_OBJECT FileObject,     IN PMDL MdlChain,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, MdlReadComplete ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = (BOOLEAN) hookExt->FileSystem->DriverObject->FastIoDispatch->MdlReadComplete( FileObject,                  MdlChain, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked)         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_MDL_READ_COMPLETE\t%s\t\t%s",                        FilemonGetProcess( name ), fullPathName, "OK" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoPrepareMdlWrite // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoPrepareMdlWrite(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN ULONG LockKey,     OUT PMDL *MdlChain,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;     IoStatus->Status      = STATUS_NOT_IMPLEMENTED;     IoStatus->Information = 0;      if( FASTIOPRESENT( hookExt, PrepareMdlWrite ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->PrepareMdlWrite(                      FileObject, FileOffset, Length, LockKey, MdlChain, IoStatus,                      hookExt->FileSystem );          if( FilterDef.logwrites && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_PREPARE_MDL_WRITE\t%s\tOffset: %d Length: %d\t%s",                        FilemonGetProcess( name ), fullPathName,                        FileOffset->LowPart, Length,                        retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoMdlWriteComplete // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoMdlWriteComplete(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN PMDL MdlChain,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, MdlWriteComplete ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->MdlWriteComplete(                      FileObject, FileOffset, MdlChain, hookExt->FileSystem );          if( FilterDef.logwrites && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_MDL_WRITE_COMPLETE\t%s\tOffset: %d\tOK",                        FilemonGetProcess( name ), fullPathName, FileOffset->LowPart );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoReadCompressed // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoReadCompressed(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN ULONG LockKey,     OUT PVOID Buffer,     OUT PMDL *MdlChain,     OUT PIO_STATUS_BLOCK IoStatus,     OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo,     IN ULONG CompressedDataInfoLength,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoReadCompressed ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoReadCompressed(                      FileObject, FileOffset, Length, LockKey, Buffer, MdlChain, IoStatus,                      CompressedDataInfo, CompressedDataInfoLength, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked)         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_READ_COMPRESSED\t%s\tOffset: %d Length: %d\t%s",                        FilemonGetProcess( name ), fullPathName,                        FileOffset->LowPart, Length,                        retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoWriteCompressed // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoWriteCompressed(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN ULONG Length,     IN ULONG LockKey,     OUT PVOID Buffer,     OUT PMDL *MdlChain,     OUT PIO_STATUS_BLOCK IoStatus,     OUT struct _COMPRESSED_DATA_INFO *CompressedDataInfo,     IN ULONG CompressedDataInfoLength,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN], errorBuf[ERRORLEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoWriteCompressed ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoWriteCompressed(                      FileObject, FileOffset, Length, LockKey, Buffer, MdlChain, IoStatus,                      CompressedDataInfo, CompressedDataInfoLength, hookExt->FileSystem );          if( FilterDef.logwrites && hookExt->Hooked )         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_WRITE_COMPRESSED\t%s\tOffset: %d Length: %d\t%s",                        FilemonGetProcess( name ), fullPathName,                        FileOffset->LowPart, Length,                        retval ? ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoMdlReadCompleteCompressed // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoMdlReadCompleteCompressed(     IN PFILE_OBJECT FileObject,     IN PMDL MdlChain,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, MdlReadCompleteCompressed ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->MdlReadCompleteCompressed(                      FileObject, MdlChain, hookExt->FileSystem );          if( FilterDef.logreads && hookExt->Hooked)         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_MDL_READ_COMPLETE_COMPRESSED\t%s\t\t%s",                        FilemonGetProcess( name ), fullPathName, "OK" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoMdlWriteCompleteCompressed // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoMdlWriteCompleteCompressed(     IN PFILE_OBJECT FileObject,     IN PLARGE_INTEGER FileOffset,     IN PMDL MdlChain,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, MdlWriteCompleteCompressed ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->MdlWriteCompleteCompressed(                      FileObject, FileOffset, MdlChain, hookExt->FileSystem );          if( FilterDef.logwrites && hookExt->Hooked)         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_MDL_WRITE_COMPLETE_COMPRESSED\t%s\tOffset: %d\t%s",                        FilemonGetProcess( name ), fullPathName, FileOffset->LowPart, "OK" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoQueryOpen // // This call actually passes an IRP! // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoQueryOpen(     IN PIRP Irp,     OUT PFILE_NETWORK_OPEN_INFORMATION NetworkInformation,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     PHOOK_EXTENSION     hookExt;     PFILE_OBJECT        FileObject;     CHAR                *fullPathName, name[PROCNAMELEN];     PIO_STACK_LOCATION  currentIrpStack;     PIO_STACK_LOCATION  nextIrpStack;     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return FALSE;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, FastIoQueryOpen ))     {          currentIrpStack = IoGetCurrentIrpStackLocation(Irp);         nextIrpStack    = IoGetNextIrpStackLocation(Irp);         FileObject      = currentIrpStack->FileObject;          //         // copy parameters down to next level in the stack         //         *nextIrpStack = *currentIrpStack;         nextIrpStack->DeviceObject = hookExt->FileSystem;         IoSetNextIrpStackLocation( Irp );          //         // Get path and timestamp         //         GETPATHNAME(TRUE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoQueryOpen(                      Irp, NetworkInformation, hookExt->FileSystem );          //         // Reset the stack location because pre-NT 5.0 checked builds complain         //         Irp->CurrentLocation++;         Irp->Tail.Overlay.CurrentStackLocation++;          if( FilterDef.logreads && hookExt->Hooked)         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_QUERY_OPEN\t%s\t\t%s",                        FilemonGetProcess( name ), fullPathName, retval ? "SUCCESS" : "FAILURE" );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoReleaseForModWrite // //---------------------------------------------------------------------- NTSTATUS FilemonFastIoReleaseForModWrite(     IN PFILE_OBJECT FileObject,     IN struct _ERESOURCE *ResourceToRelease,     IN PDEVICE_OBJECT DeviceObject ) {     NTSTATUS            retval = STATUS_NOT_IMPLEMENTED;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, errval[ERRORLEN], name[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return STATUS_NOT_IMPLEMENTED;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, ReleaseForModWrite ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->ReleaseForModWrite(                      FileObject,  ResourceToRelease, hookExt->FileSystem );          if( FilterDef.logwrites && hookExt->Hooked)         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_RELEASE_FOR_MOD_WRITE\t%s\t\t%s",                        FilemonGetProcess( name ), fullPathName, ErrorString( retval, errval ));         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoAcquireForCcFlush // //---------------------------------------------------------------------- NTSTATUS FilemonFastIoAcquireForCcFlush(     IN PFILE_OBJECT FileObject,     IN PDEVICE_OBJECT DeviceObject ) {     NTSTATUS            retval = STATUS_NOT_IMPLEMENTED;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, errval[ERRORLEN], name[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return STATUS_NOT_IMPLEMENTED;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, AcquireForCcFlush ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->AcquireForCcFlush(                      FileObject, hookExt->FileSystem );         if( FilterDef.logwrites && hookExt->Hooked)         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_ACQUIRE_FOR_CC_FLUSH\t%s\t\t%s",                        FilemonGetProcess( name ), fullPathName, ErrorString( retval, errval));         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoReleaseForCcFlush // //---------------------------------------------------------------------- NTSTATUS FilemonFastIoReleaseForCcFlush(     IN PFILE_OBJECT FileObject,     IN PDEVICE_OBJECT DeviceObject ) {     NTSTATUS            retval = STATUS_NOT_IMPLEMENTED;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, errval[ERRORLEN], name[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      if( !DeviceObject ) return STATUS_NOT_IMPLEMENTED;      hookExt = DeviceObject->DeviceExtension;      if( FASTIOPRESENT( hookExt, ReleaseForCcFlush ))     {          GETPATHNAME(FALSE);         TIMESTAMPSTART();          retval = hookExt->FileSystem->DriverObject->FastIoDispatch->ReleaseForCcFlush(                      FileObject, hookExt->FileSystem );          if( FilterDef.logwrites && hookExt->Hooked)         {              TIMESTAMPSTOP();             LogRecord( TRUE, NULL,                        &dateTime, &timeResult,                        "%s\tFASTIO_RELEASE_FOR_CC_FLUSH\t%s\t\t%s",                        FilemonGetProcess( name ), fullPathName, ErrorString( retval, errval) );         }         FREEPATHNAME();     }     return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoDeviceControl // //---------------------------------------------------------------------- BOOLEAN FilemonFastIoDeviceControl(     IN PFILE_OBJECT FileObject,     IN BOOLEAN Wait,     IN PVOID InputBuffer,     IN ULONG InputBufferLength,     OUT PVOID OutputBuffer,     IN ULONG OutputBufferLength,     IN ULONG IoControlCode,     OUT PIO_STATUS_BLOCK IoStatus,     IN PDEVICE_OBJECT DeviceObject ) {     BOOLEAN             retval = FALSE;     BOOLEAN             logMutexReleased;     PHOOK_EXTENSION     hookExt;     PLOG_BUF            oldLog, savedCurrentLog;     CHAR                fullPathName[MAXPATHLEN], name[PROCNAMELEN], errorBuf[ERRORLEN];     KIRQL               oldirql;     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      hookExt = DeviceObject->DeviceExtension;     if( hookExt->Type == GUIINTERFACE )     {          //         // Its a message from our GUI!         //         IoStatus->Status      = STATUS_SUCCESS; // Assume success         IoStatus->Information = 0;      // Assume nothing returned          switch ( IoControlCode )         {          case IOCTL_FILEMON_VERSION:              //             // Version #             //             if( OutputBufferLength >= sizeof(ULONG))             {                  *(ULONG *)OutputBuffer = FILEMONVERSION;                 IoStatus->Information = sizeof(ULONG);              }             else             {                  IoStatus->Status = STATUS_BUFFER_TOO_SMALL;             }             break;          case IOCTL_FILEMON_SETDRIVES:              //             // Hook and/or unhook drives             //             DbgPrint (("Filemon: set drives\n"));              if( InputBufferLength >= sizeof(ULONG) &&                     OutputBufferLength >= sizeof(ULONG))             {                  *(ULONG *)OutputBuffer = HookDriveSet( *(ULONG *)InputBuffer, DeviceObject->DriverObject );                 IoStatus->Information = sizeof(ULONG);              }             else             {                  IoStatus->Status = STATUS_BUFFER_TOO_SMALL;             }             break;          case IOCTL_FILEMON_HOOKSPECIAL:              if( InputBufferLength >= sizeof(FILE_SYSTEM_TYPE ))             {                  if( !HookSpecialFs( DeviceObject->DriverObject, *(PFILE_SYSTEM_TYPE) InputBuffer ))                 {                      IoStatus->Status = STATUS_UNSUCCESSFUL;                 }             }             else             {                  IoStatus->Status = STATUS_BUFFER_TOO_SMALL;             }             break;          case IOCTL_FILEMON_UNHOOKSPECIAL:              if( InputBufferLength >= sizeof(FILE_SYSTEM_TYPE ))             {                  UnhookSpecialFs( *(PFILE_SYSTEM_TYPE) InputBuffer );              }             else             {                  IoStatus->Status = STATUS_BUFFER_TOO_SMALL;             }             break;          case IOCTL_FILEMON_STOPFILTER:              //             // Turn off logging             //             DbgPrint(("Filemon: stop logging\n"));             FilterOn = FALSE;             break;          case IOCTL_FILEMON_STARTFILTER:              //             // Turn on logging             //             DbgPrint(("Filemon: start logging\n"));             FilterOn = TRUE;             break;          case IOCTL_FILEMON_SETFILTER:              //             // Gui is updating the filter functions             //             DbgPrint(("Filemon: set filter\n"));              if( InputBufferLength >= sizeof(FILTER) )             {                  FilterDef = *(PFILTER) InputBuffer;                 FilemonUpdateFilters();              }             else             {                  IoStatus->Status = STATUS_BUFFER_TOO_SMALL;             }             break;          case IOCTL_FILEMON_UNLOADQUERY: #if DBG             //             // Is it possible to unload?             //             KeAcquireSpinLock( &CountMutex, &oldirql );             IoStatus->Information = OutstandingIRPCount;              //             // Any outstanding Irps?             //             if( !OutstandingIRPCount )             {                  //                 // Nope, so don't process anymore                 //                 UnloadInProgress = TRUE;                  KeReleaseSpinLock( &CountMutex, oldirql );                  //                 // Stop capturing drives                 //                 HookDriveSet( 0, DeviceObject->DriverObject );                 UnhookSpecialFs( NPFS );                 UnhookSpecialFs( MSFS );                  //                 // Detach from all devices                 //                 UnloadDetach();              }             else             {                  KeReleaseSpinLock( &CountMutex, oldirql );             } #else // DBG             IoStatus->Information = 1; #endif // DBG             break;          case IOCTL_FILEMON_ZEROSTATS:              //             // Reset all output buffers             //             DbgPrint (("Filemon: zero stats\n"));              ExAcquireFastMutex( &LogMutex );              while( CurrentLog->Next )             {                  //                 // Free all but the first output buffer                 //                 oldLog = CurrentLog->Next;                 CurrentLog->Next = oldLog->Next;                  ExFreePool( oldLog );                 NumLog--;             }              //             // Set the output pointer to the start of the output buffer             //             CurrentLog->Len = 0;             Sequence = 0;              ExReleaseFastMutex( &LogMutex );             break;          case IOCTL_FILEMON_GETSTATS:              //             // Copy the oldest output buffer to the caller             //             DbgPrint (("Filemon: get stats\n"));              //             // If the output buffer is too large to fit into the caller's buffer             //             if( LOGBUFSIZE > OutputBufferLength )             {                  IoStatus->Status = STATUS_BUFFER_TOO_SMALL;                 return FALSE;             }              //             // Probe the output buffer             //             try             {                  ProbeForWrite( OutputBuffer,                                OutputBufferLength,                                sizeof( UCHAR ));              }             except( EXCEPTION_EXECUTE_HANDLER )             {                  IoStatus->Status = STATUS_INVALID_PARAMETER;                 return FALSE;             }              //             // We're okay, lock the buffer pool             //             ExAcquireFastMutex( &LogMutex );             if( CurrentLog->Len  ||  CurrentLog->Next )             {                  //                 // Start output to a new output buffer                 //                 FilemonAllocateLog();                  //                 // Fetch the oldest to give to user                 //                 oldLog = FilemonGetOldestLog();                  if( oldLog != CurrentLog )                 {                      logMutexReleased = TRUE;                     ExReleaseFastMutex( &LogMutex );                  }                 else                 {                      logMutexReleased = FALSE;                 }                  //                 // Copy it to the caller's buffer                 //                 memcpy( OutputBuffer, oldLog->Data, oldLog->Len );                  //                 // Return length of copied info                 //                 IoStatus->Information = oldLog->Len;                  //                 // Deallocate buffer - unless its the last one                 //                 if( logMutexReleased )                 {                      ExFreePool( oldLog );                  }                 else                 {                      CurrentLog->Len = 0;                     ExReleaseFastMutex( &LogMutex );                 }              }             else             {                  //                 // There is no unread data                 //                 ExReleaseFastMutex( &LogMutex );                 IoStatus->Information = 0;             }             break;          default:              //             // Unknown control             //             DbgPrint (("Filemon: unknown IRP_MJ_DEVICE_CONTROL\n"));             IoStatus->Status = STATUS_INVALID_DEVICE_REQUEST;             break;         }          retval = TRUE;      }     else     {          //         // Its a call for a file system, so pass it through         //         if( FASTIOPRESENT( hookExt, FastIoDeviceControl ) )         {              FilemonGetFullPath( FALSE, FileObject, hookExt, fullPathName );             TIMESTAMPSTART();              retval = hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoDeviceControl(                          FileObject, Wait, InputBuffer, InputBufferLength, OutputBuffer,                          OutputBufferLength, IoControlCode, IoStatus, hookExt->FileSystem );              if(hookExt->Hooked)             {                  TIMESTAMPSTOP();                 LogRecord( TRUE, NULL, &dateTime, &timeResult,                            "%s\tFASTIO_DEVICE_CONTROL\t%s\tIOCTL: 0x%X\t%s",                            FilemonGetProcess( name ), fullPathName,                            IoControlCode,                            retval ?  ErrorString( IoStatus->Status, errorBuf ) : "FAILURE" );             }         }     }      return retval; }   //---------------------------------------------------------------------- // // FilemonFastIoAcquireFile // //---------------------------------------------------------------------- VOID FilemonFastIoAcquireFile(     PFILE_OBJECT FileObject ) {     PDEVICE_OBJECT      deviceObject, checkDevice;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      //     // We've got to locate our own device object     //     checkDevice = FileObject->DeviceObject->Vpb->DeviceObject;     while( checkDevice )     {          if( checkDevice->DriverObject == FilemonDriver )         {              //             // Found it             //             deviceObject = checkDevice;             hookExt = deviceObject->DeviceExtension;             if( FASTIOPRESENT( hookExt, AcquireFileForNtCreateSection ))             {                  GETPATHNAME(FALSE);                 TIMESTAMPSTART();                  hookExt->FileSystem->DriverObject->FastIoDispatch->AcquireFileForNtCreateSection(                     FileObject );                  if( FilterDef.logreads && hookExt->Hooked)                 {                      TIMESTAMPSTOP();                     LogRecord( TRUE, NULL, &dateTime, &timeResult,                                "%s\tFASTIO_ACQUIRE_FILE\t%s\t\tOK", FilemonGetProcess( name ),                                fullPathName );                 }                 FREEPATHNAME();             }             return;         }         checkDevice = checkDevice->AttachedDevice;     } }   //---------------------------------------------------------------------- // // FilemonFastIoReleaseFile // //---------------------------------------------------------------------- VOID FilemonFastIoReleaseFile(     PFILE_OBJECT FileObject ) {     PDEVICE_OBJECT      deviceObject, checkDevice;     PHOOK_EXTENSION     hookExt;     CHAR                *fullPathName, name[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      //     // We've got to locate our own device object     //     checkDevice = FileObject->DeviceObject->Vpb->DeviceObject;     while( checkDevice )     {          if( checkDevice->DriverObject == FilemonDriver )         {              deviceObject = IoGetRelatedDeviceObject( FileObject );             hookExt = deviceObject->DeviceExtension;              if( FASTIOPRESENT( hookExt, ReleaseFileForNtCreateSection ))             {                  GETPATHNAME(FALSE);                 TIMESTAMPSTART();                  hookExt->FileSystem->DriverObject->FastIoDispatch->ReleaseFileForNtCreateSection( FileObject );                  if( FilterDef.logreads && hookExt->Hooked)                 {                      TIMESTAMPSTOP();                     LogRecord( TRUE, NULL, &dateTime, &timeResult,                                "%s\tFASTIO_RELEASE_FILE\t%s\t\tOK", FilemonGetProcess( name ),                                fullPathName );                 }                 FREEPATHNAME();             }             return;         }         checkDevice = checkDevice->AttachedDevice;     } }   //---------------------------------------------------------------------- // // FilemonFastIoDetachDevice // // We get this call when a device that we have hooked is being deleted. // This happens when, for example, a floppy is formatted. We have // to detach from it and delete our device. We should notify the GUI // that the hook state has changed, but its not worth the trouble. // //---------------------------------------------------------------------- VOID FilemonFastIoDetachDevice(     PDEVICE_OBJECT SourceDevice,     PDEVICE_OBJECT TargetDevice ) {     PHOOK_EXTENSION     hookExt;     ULONG               i;     CHAR                name[PROCNAMELEN], drive[PROCNAMELEN];     LARGE_INTEGER       timeStampStart, timeStampComplete, timeResult;     LARGE_INTEGER       dateTime;      //     // See if a device (like a floppy) is being removed out from under us. If so,     // we have to detach from it before it disappears     //     for( i = 0; i < 26; i++ )     {          if( SourceDevice == DriveHookDevices[i] )         {              //             // We've hooked it, so we must detach             //             hookExt = SourceDevice->DeviceExtension;              DbgPrint(("Filemon: Detaching from drive: %c\n",                       hookExt->LogicalDrive ));              TIMESTAMPSTART();              sprintf( drive, "%c:", hookExt->LogicalDrive );             if( hookExt->Hooked )             {                  TIMESTAMPSTOP();                 LogRecord( TRUE, NULL, &dateTime, &timeResult,                            "%s\tFASTIO_DETACH_DEVICE\t%s\t\tOK",                            FilemonGetProcess( name ), drive );             }             IoDetachDevice( TargetDevice );             IoDeleteDevice( SourceDevice );              DriveHookDevices[i] = NULL;             return;         }     }      //     // It wasn't for us, so pass it on.     //     hookExt = SourceDevice->DeviceExtension;     if( FASTIOPRESENT( hookExt, FastIoDetachDevice ))     {          hookExt->FileSystem->DriverObject->FastIoDispatch->FastIoDetachDevice(             SourceDevice, TargetDevice );     } }   //---------------------------------------------------------------------- //     D I S P A T C H   A N D   H O O K   E N T R Y   P O I N T S //----------------------------------------------------------------------  //---------------------------------------------------------------------- // // FilemonHookDoneWork // // Worker routine that simply calls update Log. Since we want // to avoid using spin locks in order to improve SMP performance // we need to do everything at passive. When our completion routine // is called at dispatch, we queue the update off to a worker thread. // //---------------------------------------------------------------------- VOID FilemonHookDoneWork(     PVOID Context ) {     PFILEMON_WORK  filemonWork = (PFILEMON_WORK) Context;      DbgPrint(("HookWorkRoutine\n"));     LogRecord( FALSE, &filemonWork->Sequence,                NULL,                &filemonWork->TimeResult,                filemonWork->ErrString );     ExFreePool( filemonWork ); }   //---------------------------------------------------------------------- // // FilemonHookDone // // Gets control after a filesystem operation has completed so that // we can get return status information about it. // //---------------------------------------------------------------------- NTSTATUS FilemonHookDone(     IN PDEVICE_OBJECT DeviceObject,     IN PIRP Irp,     IN PVOID Context ) {     PIO_STACK_LOCATION   IrpSp; #if defined(_IA64_)     ULONG                seqNum = (ULONG) ((ULONG_PTR)Context); #else     ULONG                seqNum = (ULONG) Context; #endif     CHAR                 errval[ERRORLEN], errString[ERRORLEN];     KIRQL                oldirql;     LARGE_INTEGER        timeStampStart, timeStampComplete, timeResult;     PFILEMON_WORK        filemonWorkContext;      //     // A request completed - look at the result     //     IrpSp = IoGetCurrentIrpStackLocation( Irp );      //     // Log the return status in the output buffer. Tag it with the     // sequence number so that the GUI can match it with the IRP input information.     //     if( FilterOn )     {          //         // Quick, get the completion time         //         timeStampStart = IrpSp->Parameters.Read.ByteOffset;         timeStampComplete   = KeQueryPerformanceCounter(NULL);         timeResult.QuadPart = timeStampComplete.QuadPart - timeStampStart.QuadPart;          //         // Queue off to a worker thread if we have to         //         if( KeGetCurrentIrql() == DISPATCH_LEVEL )         {              filemonWorkContext = ExAllocatePool( NonPagedPool, sizeof(FILEMON_WORK));             if( filemonWorkContext )             {                  filemonWorkContext->Sequence   = seqNum;                 filemonWorkContext->TimeResult = timeResult;                 sprintf( filemonWorkContext->ErrString, "\t\t\t\t%s",                          ErrorString( Irp->IoStatus.Status, errval ));                 ExInitializeWorkItem( &filemonWorkContext->WorkItem,                                       FilemonHookDoneWork, filemonWorkContext );                 ExQueueWorkItem( &filemonWorkContext->WorkItem, CriticalWorkQueue );             }         }         else         {              sprintf( errString, "\t\t\t\t%s", ErrorString( Irp->IoStatus.Status, errval ));             LogRecord( FALSE, &seqNum, NULL, &timeResult, errString );         }     }  #if DBG     //     // We have finished processing an IRP so decrement oustanding IRP count     //     KeAcquireSpinLock( &CountMutex, &oldirql );     OutstandingIRPCount--;     DbgPrint(("-%d: %x\n", OutstandingIRPCount, Irp ));;     if( !OutstandingIRPCount ) FilemonDriver->DriverUnload = FilemonUnload;     KeReleaseSpinLock( &CountMutex, oldirql ); #endif      //     // Now we have to mark Irp as pending if necessary     //     if( Irp->PendingReturned )     {          IoMarkIrpPending( Irp );     }     return Irp->IoStatus.Status; }   //---------------------------------------------------------------------- // // FilemonHookRoutine // // This routine is the main hook routine where we figure out what // calls are being sent to the file system. // //---------------------------------------------------------------------- NTSTATUS FilemonHookRoutine(     PDEVICE_OBJECT HookDevice,     IN PIRP Irp ) {     PIO_STACK_LOCATION  currentIrpStack = IoGetCurrentIrpStackLocation(Irp);     PIO_STACK_LOCATION  nextIrpStack    = IoGetNextIrpStackLocation(Irp);     PMOVE_FILE_DATA     moveFile;     PQUERY_DIRECTORY    queryDirectory;     PFILE_OBJECT        FileObject;     PHOOK_EXTENSION     hookExt;     LARGE_INTEGER       dateTime;     LARGE_INTEGER       perfTime;     PCHAR               fullPathName = NULL;     BOOLEAN             hookCompletion, createPath;     CHAR                controlCodeBuffer[ERRORLEN];     CHAR                attributeString[ERRORLEN];     CHAR                optionString[ERRORLEN];     CHAR                name[PROCNAMELEN];     ULONG               i;     ANSI_STRING         directoryFilter;     PCHAR               queryFilter;     ULONG               seqNum;     KIRQL               oldirql;      //     // Extract the file object from the IRP     //     FileObject = currentIrpStack->FileObject;      //     // Point at the device extension, which contains information on which     // file system this IRP is headed for     //     hookExt = HookDevice->DeviceExtension;      //     // We note open cases so that when we query the file name     // we don't ask the file system for the name (since it won't     // have seen the file object yet).     //     if( currentIrpStack->MajorFunction == IRP_MJ_CREATE ||             currentIrpStack->MajorFunction == IRP_MJ_CREATE_NAMED_PIPE ||             currentIrpStack->MajorFunction == IRP_MJ_CREATE_MAILSLOT )     {          //         // Clear any existing fileobject/name association stored in the         // hash table         //         FilemonFreeHashEntry( FileObject );         createPath = TRUE;      }     else if( currentIrpStack->MajorFunction == IRP_MJ_CLOSE )     {          //         // We treat close as a special case of create for name querying         // since calling into NTFS during a close can result in a deadlock.         //         createPath = TRUE;      }     else if( currentIrpStack->MajorFunction == IRP_MJ_CLEANUP &&              FileObject->Flags & FO_STREAM_FILE )     {          //         // Treat cleanup of stream file objects as special create case, because         // querying them causes NTFS to screwup on NT 4         //         createPath = TRUE;      }     else     {          createPath = FALSE;     }      //     // Allocate a buffer and get the name only if we have to     //     if( FilterOn && hookExt->Hooked )     {          GETPATHNAME( createPath );     }      //     // Only log it if it passes the filter     //     if( hookExt->Hooked && fullPathName )     {          //         // If measuring absolute time go and get the timestamp.         //         KeQuerySystemTime( &dateTime );         perfTime = KeQueryPerformanceCounter( NULL );          //         // We want to watch this IRP complete         //         seqNum = (ULONG) - 1;         hookCompletion = FALSE;          //         // Determine what function we're dealing with         //         FilemonGetProcess( name );         switch( currentIrpStack->MajorFunction )         {          case IRP_MJ_CREATE:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_CREATE\t%s\tAttributes: %s Options: %s",                                         name, fullPathName,                                         CreateAttributesString( currentIrpStack->Parameters.Create.FileAttributes,                                                 attributeString ),                                         CreateOptionsString( currentIrpStack->Parameters.Create.Options,                                                 optionString ));              //             // If its an open-by-id we free the hash entry now so that on the next access to             // the file we'll pick up the file's real name.             //             if( currentIrpStack->Parameters.Create.Options & FILE_OPEN_BY_FILE_ID )             {                  FilemonFreeHashEntry( FileObject );             }             break;          case IRP_MJ_CREATE_NAMED_PIPE:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_CREATE_NAMED_PIPE\t%s\tAttributes: %s Options: %s",                                         name, fullPathName,                                         CreateAttributesString( currentIrpStack->Parameters.Create.FileAttributes,                                                 attributeString ),                                         CreateOptionsString( currentIrpStack->Parameters.Create.Options,                                                 optionString ));             break;          case IRP_MJ_CREATE_MAILSLOT:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_CREATE_MAILSLOT\t%s\tAttributes: %s Options: %s",                                         name, fullPathName,                                         CreateAttributesString( currentIrpStack->Parameters.Create.FileAttributes,                                                 attributeString ),                                         CreateOptionsString( currentIrpStack->Parameters.Create.Options,                                                 optionString ));             break;          case IRP_MJ_READ:              if( FilterDef.logreads )             {                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                             "%s\tIRP_MJ_READ%c\t%s\tOffset: %d Length: %d",                                             name,                                             (Irp->Flags & IRP_PAGING_IO) ||                                             (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',                                             fullPathName,                                             currentIrpStack->Parameters.Read.ByteOffset.LowPart,                                             currentIrpStack->Parameters.Read.Length );             }             break;          case IRP_MJ_WRITE:              if( FilterDef.logwrites )             {                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                             "%s\tIRP_MJ_WRITE%c\t%s\tOffset: %d Length: %d",                                             name,                                             (Irp->Flags & IRP_PAGING_IO) ||                                             (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',                                             fullPathName,                                             currentIrpStack->Parameters.Write.ByteOffset.LowPart,                                             currentIrpStack->Parameters.Write.Length );             }             break;          case IRP_MJ_CLOSE:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_CLOSE%c\t%s\t",                                         name,                                         (Irp->Flags & IRP_PAGING_IO) ||                                         (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',                                         fullPathName );              //             // This fileobject/name association can be discarded now.             //             FilemonFreeHashEntry( FileObject );             break;          case IRP_MJ_FLUSH_BUFFERS:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_FLUSH\t%s\t", name, fullPathName );             break;          case IRP_MJ_QUERY_INFORMATION:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_QUERY_INFORMATION\t%s\t%s",                                         name, fullPathName,                                         FileInformation[currentIrpStack->Parameters.QueryFile.FileInformationClass] );             break;          case IRP_MJ_SET_INFORMATION:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_SET_INFORMATION%c\t%s\t%s",                                         name,                                         (Irp->Flags & IRP_PAGING_IO) ||                                         (Irp->Flags & IRP_SYNCHRONOUS_PAGING_IO) ? '*' : ' ',                                         fullPathName,                                         FileInformation[currentIrpStack->Parameters.SetFile.FileInformationClass] );              //             // If its a rename, cleanup the name association.             //             if( currentIrpStack->Parameters.SetFile.FileInformationClass ==                     FileRenameInformation )             {                  FilemonFreeHashEntry( FileObject );             }             break;          case IRP_MJ_QUERY_EA:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_QUERY_EA\t%s\t", name, fullPathName );             break;          case IRP_MJ_SET_EA:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_SET_EA\t%s\t", name, fullPathName );             break;          case IRP_MJ_QUERY_VOLUME_INFORMATION:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_QUERY_VOLUME_INFORMATION\t%s\t%s",                                         name, fullPathName,                                         VolumeInformation[currentIrpStack->Parameters.QueryVolume.FsInformationClass] );             break;          case IRP_MJ_SET_VOLUME_INFORMATION:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_SET_VOLUME_INFORMATION\t%s\t%s",                                         name, fullPathName,                                         VolumeInformation[currentIrpStack->Parameters.QueryVolume.FsInformationClass] );             break;          case IRP_MJ_DIRECTORY_CONTROL:              switch( currentIrpStack->MinorFunction )             {             case IRP_MN_NOTIFY_CHANGE_DIRECTORY:                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                             "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\tChange Notify",                                             name, fullPathName );                 break;             case IRP_MN_QUERY_DIRECTORY:                 queryDirectory = (PQUERY_DIRECTORY)¤tIrpStack->Parameters;                 queryFilter = NULL;                 if( queryDirectory->FileName )                 {                      if( NT_SUCCESS( RtlUnicodeStringToAnsiString( &directoryFilter,                                     queryDirectory->FileName, TRUE )))                     {                          queryFilter = ExAllocatePool( PagedPool, directoryFilter.Length + 1 );                         if( queryFilter )                         {                              memcpy( queryFilter, directoryFilter.Buffer, directoryFilter.Length );                             queryFilter[ directoryFilter.Length ] = 0;                              //                             // Massage DOS-internal wildcards                             //                             for( i = 0; i < strlen( queryFilter ); i++ )                             {                                 if( queryFilter[i] == '<' ) queryFilter[i] = '*';                                 else if( queryFilter[i] == '>' ) queryFilter[i] = '?';                             }                         }                         RtlFreeAnsiString( &directoryFilter );                     }                 }                 if( queryFilter )                 {                      hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                                 "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\t%s: %s",                                                 name, fullPathName,                                                 FileInformation[queryDirectory->FileInformationClass],                                                 queryFilter );                     ExFreePool( queryFilter );                  }                 else                 {                      hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                                 "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\t%s",                                                 name, fullPathName,                                                 FileInformation[queryDirectory->FileInformationClass] );                 }                 break;             default:                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                             "%s\tIRP_MJ_DIRECTORY_CONTROL\t%s\t",                                             name, fullPathName );                 break;             }             break;          case IRP_MJ_FILE_SYSTEM_CONTROL:              switch( currentIrpStack->Parameters.DeviceIoControl.IoControlCode )             {             case FSCTL_MOVE_FILE:                 moveFile = (PMOVE_FILE_DATA) Irp->AssociatedIrp.SystemBuffer;                 sprintf( optionString, "Vcn: %d Len: %d Target: %d",                          moveFile->StartingVcn.LowPart,                          moveFile->ClusterCount,                          moveFile->StartingLcn.LowPart );                 ObReferenceObjectByHandle( moveFile->FileHandle, 0, NULL, KernelMode, &FileObject, NULL );                 FilemonGetFullPath( FALSE, FileObject, hookExt, fullPathName );                 ObDereferenceObject( FileObject );                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                             "%s\tFSCTL_MOVE_FILE\t%s\t%s",                                             name, fullPathName, optionString );                 break;             default:                 hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                             "%s\t%s\t%s\t%s",                                             name,                                             ControlCodeString( currentIrpStack,                                                     currentIrpStack->Parameters.DeviceIoControl.IoControlCode,                                                     controlCodeBuffer, optionString ),                                             fullPathName, optionString );             }             break;          case IRP_MJ_SHUTDOWN:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_SHUTDOWN\t\t", name );             break;          case IRP_MJ_LOCK_CONTROL:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_LOCK_CONTROL\t%s\tOffset: %d Length: %d",                                         name, fullPathName,                                         ((PLOCK_CONTROL)¤tIrpStack->Parameters)->ByteOffset.LowPart,                                         ((PLOCK_CONTROL)¤tIrpStack->Parameters)->Length ?                                         ((PLOCK_CONTROL)¤tIrpStack->Parameters)->Length->LowPart : 0 );             break;          case IRP_MJ_CLEANUP:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_CLEANUP\t%s\t", name, fullPathName );             break;          case IRP_MJ_DEVICE_CONTROL:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_DEVICE_CONTROL\t%s\tIOCTL: 0x%X", name,                                         fullPathName, currentIrpStack->Parameters.DeviceIoControl.IoControlCode );             break;          case IRP_MJ_QUERY_SECURITY:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_QUERY_SECURITY\t%s\t",                                         name, fullPathName );             break;          case IRP_MJ_SET_SECURITY:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_SET_SECURITY\t%s\t",                                         name, fullPathName );             break;          case IRP_MJ_POWER:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_POWER\t%s\tMinor: %x",                                         name, fullPathName,                                         currentIrpStack->MinorFunction );             break;          case IRP_MJ_PNP:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\tIRP_MJ_PNP\t%s\t%s",                                         name, fullPathName,                                         currentIrpStack->MinorFunction <= IRP_MN_QUERY_LEGACY_BUS_INFORMATION ?                                         PnpMinorCode[currentIrpStack->MinorFunction] : "New minor code" );             break;          default:              hookCompletion = LogRecord( TRUE, &seqNum, &dateTime, NULL,                                         "%s\t*UNKNOWN* 0x%X\t\t", name, currentIrpStack->MajorFunction );             break;         }      }     else     {          //         // We don't care about this IRP's completion         //         hookCompletion = FALSE;          //         // Do name processing for the sake of keeping the hash table current         //         switch( currentIrpStack->MajorFunction )         {         case IRP_MJ_CLOSE:              //             // This fileobject/name association can be discarded now.             //             FilemonFreeHashEntry( FileObject );             break;         }     }      //     // Free the buffer if we have one     //     if( fullPathName && fullPathName != InsufficientResources )     {          ExFreeToNPagedLookasideList( &FullPathLookaside, fullPathName );     }      //     // Copy parameters down to next level in the stack for the driver below us     //     *nextIrpStack = *currentIrpStack;  #if DBG     //     // If an unload isn't in progress, we should register a completion callback     // so that the IRP's return status can be examined.     //     KeAcquireSpinLock( &CountMutex, &oldirql ); #endif      if( !UnloadInProgress && hookCompletion )     {  #if DBG         //         // Increment the outstanding IRP count since this IRP will be headed         // for our completion routine         //         FilemonDriver->DriverUnload = NULL;         OutstandingIRPCount++;         DbgPrint(("+%d: %x\n", OutstandingIRPCount, Irp ));; #endif // DBG         //         // Grab the time stamp and Log it in the current stack location. This         // is legal since the stack location is ours, and we're done looking at         // the parameters. This makes it easy to pass this to the completion routine. The         // DiskPerf example in the NT DDK uses this trick.         //         currentIrpStack->Parameters.Read.ByteOffset = perfTime; #if defined(_IA64_)         IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) (ULONG_PTR) seqNum, TRUE, TRUE, TRUE ); #else         IoSetCompletionRoutine( Irp, FilemonHookDone, (PVOID) seqNum, TRUE, TRUE, TRUE ); #endif      }     else     {          //         // Set no completion routine         //         IoSetCompletionRoutine( Irp, FilemonHookDone, NULL, FALSE, FALSE, FALSE );     } #if DBG     KeReleaseSpinLock( &CountMutex, oldirql ); #endif      //     // Return the results of the call to the caller     //     return IoCallDriver( hookExt->FileSystem, Irp ); }   //---------------------------------------------------------------------- // // FilemonDeviceRoutine // // In this routine we handle requests to our own device. The only // requests we care about handling explicitely are IOCTL commands that // we will get from the GUI. We also expect to get Create and Close // commands when the GUI opens and closes communications with us. // //---------------------------------------------------------------------- NTSTATUS FilemonDeviceRoutine(     IN PDEVICE_OBJECT DeviceObject,     IN PIRP Irp ) {     PIO_STACK_LOCATION  irpStack;     PVOID               inputBuffer;     PVOID               outputBuffer;     ULONG               inputBufferLength;     ULONG               outputBufferLength;     ULONG               ioControlCode;      //     // Go ahead and set the request up as successful     //     Irp->IoStatus.Status      = STATUS_SUCCESS;     Irp->IoStatus.Information = 0;      //     // Get a pointer to the current location in the Irp. This is where     // the function codes and parameters are located.     //     irpStack = IoGetCurrentIrpStackLocation (Irp);      //     // Get the pointer to the input/output buffer and its length     //     inputBuffer        = Irp->AssociatedIrp.SystemBuffer;     inputBufferLength  = irpStack->Parameters.DeviceIoControl.InputBufferLength;     outputBuffer       = Irp->AssociatedIrp.SystemBuffer;     outputBufferLength = irpStack->Parameters.DeviceIoControl.OutputBufferLength;     ioControlCode      = irpStack->Parameters.DeviceIoControl.IoControlCode;      switch (irpStack->MajorFunction)     {     case IRP_MJ_CREATE:          DbgPrint(("Filemon: IRP_MJ_CREATE\n"));          //         // Start the sequence number at 0         //         Sequence = 0;         break;      case IRP_MJ_CLOSE:          DbgPrint(("Filemon: IRP_MJ_CLOSE\n"));          //         // A GUI is closing communication         //         FilterOn  = FALSE;          //         // If the GUI has no more references to us, reset the output         // buffers and hash table.         //         FilemonResetLog();         FilemonHashCleanup();          //         // Stop capturing drives         //         HookDriveSet( 0, DeviceObject->DriverObject );         UnhookSpecialFs( NPFS );         UnhookSpecialFs( MSFS );         break;      case IRP_MJ_DEVICE_CONTROL:          //         // This path will never execute because we have registered a         // fast I/O path for device control. That means that the fast I/O entry         // point will ALWAYS be called for Device Control operations         //         DbgPrint (("Filemon: IRP_MJ_DEVICE_CONTROL\n"));          //         // Get output buffer if its passed as an MDL         //         if( Irp->MdlAddress )         {              outputBuffer = MmGetSystemAddressForMdl( Irp->MdlAddress );         }          //         // Its a request from the GUI. Simply call our fast handler.         //         FilemonFastIoDeviceControl( irpStack->FileObject, TRUE,                                     inputBuffer, inputBufferLength,                                     outputBuffer, outputBufferLength,                                     ioControlCode, &Irp->IoStatus, DeviceObject );         break;     }      //     // Complete the IRP     //     IoCompleteRequest( Irp, IO_NO_INCREMENT );     return STATUS_SUCCESS; }   //---------------------------------------------------------------------- // // FilemonDispatch // // Based on which device the Irp is destined for we call either the // filesystem filter function, or our own device handling routine. // //---------------------------------------------------------------------- NTSTATUS FilemonDispatch(     IN PDEVICE_OBJECT DeviceObject,     IN PIRP Irp ) {     //     // Determine if its a request from the GUI to us, or one that is     // directed at a file system driver that we've hooked     //     if( ((PHOOK_EXTENSION) DeviceObject->DeviceExtension)->Type == GUIINTERFACE )     {          return FilemonDeviceRoutine( DeviceObject, Irp );      }     else     {          return FilemonHookRoutine( DeviceObject, Irp );     } }   //---------------------------------------------------------------------- // // FilemonUnload // // Our job is done - time to leave. Note that this function is // only called when debugging is on, since in reality it is not safe // to detach filter devices or unload a filter driver. // //---------------------------------------------------------------------- VOID FilemonUnload(     IN PDRIVER_OBJECT DriverObject ) {     WCHAR                  deviceLinkBuffer[]  = L"\\DosDevices\\Filemon";     UNICODE_STRING         deviceLinkUnicodeString;      //     // Delete the symbolic link for our GUI device     //     RtlInitUnicodeString( &deviceLinkUnicodeString, deviceLinkBuffer );     IoDeleteSymbolicLink( &deviceLinkUnicodeString );      DbgPrint(("Filemon.SYS: unloading\n"));      //     // The only device object left should be the GUI device, since     // we delete devices in our unload check.     //     IoDeleteDevice( DriverObject->DeviceObject );     DbgPrint(("Filemon.SYS: deleted devices\n"));      //     // Now we can free any memory that is allocated     //     FilemonFreeFilters();     FilemonHashCleanup();     FilemonFreeLog();     ExDeleteNPagedLookasideList( &FullPathLookaside );      //     // Delete the resources     //     ExDeleteResourceLite( &FilterResource );     ExDeleteResourceLite( &HashResource );      DbgPrint(("Filemon.SYS: freed memory\n")); }   //---------------------------------------------------------------------- // // DriverEntry // // Installable driver initialization. Here we just set ourselves up. // //---------------------------------------------------------------------- NTSTATUS DriverEntry(     IN PDRIVER_OBJECT DriverObject,     IN PUNICODE_STRING RegistryPath ) {     NTSTATUS                ntStatus;     PDEVICE_OBJECT          guiDevice;     WCHAR                   deviceNameBuffer[]  = L"\\Device\\Filemon";     UNICODE_STRING          deviceNameUnicodeString;     WCHAR                   deviceLinkBuffer[]  = L"\\DosDevices\\Filemon";     UNICODE_STRING          deviceLinkUnicodeString;     ULONG                   i;      DbgPrint (("Filemon.SYS: entering DriverEntry\n"));     FilemonDriver = DriverObject;      //     // Setup the device name     //     RtlInitUnicodeString (&deviceNameUnicodeString,                           deviceNameBuffer );      //     // Create the device used for GUI communications     //     ntStatus = IoCreateDevice ( DriverObject,                                 sizeof(HOOK_EXTENSION),                                 &deviceNameUnicodeString,                                 FILE_DEVICE_FILEMON,                                 0,                                 TRUE,                                 &guiDevice );      //     // If successful, make a symbolic link that allows for the device     // object's access from Win32 programs     //     if(NT_SUCCESS(ntStatus))     {          //         // Mark this as our GUI device         //         ((PHOOK_EXTENSION) guiDevice->DeviceExtension)->Type = GUIINTERFACE;          //         // Create a symbolic link that the GUI can specify to gain access         // to this driver/device         //         RtlInitUnicodeString (&deviceLinkUnicodeString,                               deviceLinkBuffer );         ntStatus = IoCreateSymbolicLink (&deviceLinkUnicodeString,                                          &deviceNameUnicodeString );         if(!NT_SUCCESS(ntStatus))         {              DbgPrint (("Filemon.SYS: IoCreateSymbolicLink failed\n"));             IoDeleteDevice( guiDevice );             return ntStatus;         }          //         // Create dispatch points for all routines that must be handled.         // All entry points are registered since we might filter a         // file system that processes all of them.         //         for( i = 0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++ )         {              DriverObject->MajorFunction[i] = FilemonDispatch;         } #if DBG         //         // Driver unload is only set if we are debugging Filemon. This is         // because unloading a filter is not really safe - threads could         // be in our fastio routines (or about to enter them), for example,         // and there is no way to tell. When debugging, we can risk the         // occasional unload crash as a trade-off for not having to         // reboot as often.         //         // DriverObject->DriverUnload = FilemonUnload; #endif // DBG          //         // Set up the Fast I/O dispatch table         //         DriverObject->FastIoDispatch = &FastIOHook;      }     else     {          //         // If something went wrong, cleanup the device object and don't load         //         DbgPrint(("Filemon: Failed to create our device!\n"));         return ntStatus;     }      //     // Initialize the name hash table     //     for(i = 0; i < NUMHASH; i++ ) HashTable[i] = NULL;      //     // Find the process name offset     //     ProcessNameOffset = FilemonGetProcessNameOffset();      //     // Initialize the synchronization objects     // #if DBG     KeInitializeSpinLock( &CountMutex ); #endif     ExInitializeFastMutex( &LogMutex );     ExInitializeResourceLite( &FilterResource );     ExInitializeResourceLite( &HashResource );      //     // Initialize a lookaside for file names     //     ExInitializeNPagedLookasideList( &FullPathLookaside, NULL, NULL,                                      0, MAXPATHLEN, 'mliF', 256 );      //     // Allocate the first output buffer     //     CurrentLog = ExAllocatePool( NonPagedPool, sizeof(*CurrentLog) );     if( !CurrentLog )     {          //         // Oops - we can't do anything without at least one buffer         //         IoDeleteSymbolicLink( &deviceLinkUnicodeString );         IoDeleteDevice( guiDevice );         return STATUS_INSUFFICIENT_RESOURCES;     }      //     // Set the buffer pointer to the start of the buffer just allocated     //     CurrentLog->Len  = 0;     CurrentLog->Next = NULL;     NumLog = 1;      return STATUS_SUCCESS; }