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;
}