FileMon源码中另一个比较疑惑的地方,FileMon创建了两类设备,一个是用于和ring3通信的GUI设备,另一个是hook的过滤设备,但在代码中,当收到发向GUI设备的IRP_MJ_DEVICE_CONTROL时,代码竟是去调用属于hook设备的功能函数,而在这个功能函数里面通过条件判断是否是GUI设备来分别处理,而对于发给GUI设备的其他IRP都在直接在GUI的处理函数中直接处理的,不知道作者这样写是否有什么深层的含义,不过对于我这种初学者来说,这样的写法倒是容易引起混乱,还是不同设备的功能函数,分开来写好一点。下面附上相关代码:
//=========================================================
//GUI设备的功能函数,注意IRP_MJ_DEVICE_CONTROL的实现
//=========================================================
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;
}
//=========================================================
//hook设备的功能函数,在里面夹杂了处理GUI设备的IRP_MJ_DEVICE_CONTROL的代码
//=========================================================
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;
}