Click here to Skip to main content
Click here to Skip to main content

USB & CD/DVD Blocking: One Way to Keep Data Free of Theft

By , 4 May 2011
 

Sample Image - maximum width is 600 pixels

Sample Image - maximum width is 600 pixels

Introduction

Have you ever thought of blocking access to USB Memory and CD? I will introduce an example of this. Perhaps some of you will not be interested in this, but I think this technique will be useful for more large-scale projects. I referenced a sample in Microsoft Windows DDK. This sample is implemented by file system filter driver. As you know, File System Filter Driver is commonly used in Anti-Virus and it can be used for some other purposes. In this sample, we can not only block access, but log the file path written to USB.

How to Use

This sample consists of 2 sysfiles and a DLL file. In order to test this sample, first execute install.exe in 1_install folder. You can uninstall this by executing uninstall.exe in 3_uninstall folder.
As seen above, click OK button first and then test the functions.

Using the Code

Here I would explain the file system filter driver. There are two ways of developing file system filter driver. One is to use filter function supported by FLTLIB.DLL in system32 directory. In this case, we can communicate with driver by using FilterConnectCommunicationPort() function and FilterSendMessage() function. Another one is to get file system driver's pointer and attach our driver to it by using IoAttachDeviceToDeviceStack() function.

DriverEntry

DriverEntry() function should be written like below:

NTSTATUS
DriverEntry (
    __in PDRIVER_OBJECT DriverObject,
    __in PUNICODE_STRING RegistryPath
    )
{
    PSECURITY_DESCRIPTOR sd;
    OBJECT_ATTRIBUTES oa;
    UNICODE_STRING uniString;
    NTSTATUS status;
	PFLT_VOLUME fltvolume;
	HANDLE handle = (PVOID)-1;
	PROCESS_DEVICEMAP_INFORMATION ldrives;
	ULONG           drive, bit;
	STRING			ansiString, ansiVolString;
	UNICODE_STRING	unString, unVolString;
	CHAR			szDrv[20];
	ULONG			sizeneeded;
	HANDLE hThread;
	OBJECT_ATTRIBUTES oaThread;
	KIRQL irql;

	ULONG i;

    try {
	ACDrvData.LogSequenceNumber = 0;
        	ACDrvData.MaxRecordsToAllocate = DEFAULT_MAX_RECORDS_TO_ALLOCATE;
        	ACDrvData.RecordsAllocated = 0;
       	ACDrvData.NameQueryMethod = DEFAULT_NAME_QUERY_METHOD;

        ACDrvData.DriverObject = DriverObject;

        InitializeListHead( &ACDrvData.OutputBufferList );
        KeInitializeSpinLock( &ACDrvData.OutputBufferLock );


#if ACDRV_LONGHORN

        //
        //  Dynamically import FilterMgr APIs for transaction support
        //

        ACDrvData.PFltSetTransactionContext = 
		FltGetRoutineAddress( "FltSetTransactionContext" );
        ACDrvData.PFltGetTransactionContext = 
		FltGetRoutineAddress( "FltGetTransactionContext" );
        ACDrvData.PFltEnlistInTransaction = 
		FltGetRoutineAddress( "FltEnlistInTransaction" );

#endif

		SpyReadDriverParameters(RegistryPath);

		status = FltRegisterFilter( DriverObject,
					&FilterRegistration,
					&ACDrvData.Filter );
        if (!NT_SUCCESS( status )) {

           leave;
        }

        status  = FltBuildDefaultSecurityDescriptor( &sd,
                                                     FLT_PORT_ALL_ACCESS );

        if (!NT_SUCCESS( status )) {
            leave;
        }

        RtlInitUnicodeString( &uniString, ACDRV_PORT_NAME );

        InitializeObjectAttributes( &oa,
                                    &uniString,
                                    OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
                                    NULL,
                                    sd );

        status = FltCreateCommunicationPort( ACDrvData.Filter,
                                             &ACDrvData.ServerPort,
                                             &oa,
                                             NULL,
                                             SpyConnect,
                                             SpyDisconnect,
                                             SpyMessage,
                                             1 );

        FltFreeSecurityDescriptor( sd );

        if (!NT_SUCCESS( status )) {
            leave;
        }
		...
		
		status = FltStartFiltering( ACDrvData.Filter );

		...
    } finally {

        if (!NT_SUCCESS( status ) ) {

             if (NULL != ACDrvData.ServerPort) {
                 FltCloseCommunicationPort( ACDrvData.ServerPort );
             }

             if (NULL != ACDrvData.Filter) {
                 FltUnregisterFilter( ACDrvData.Filter );
             }

             ExDeleteNPagedLookasideList( &ACDrvData.FreeBufferList );
        }
    }
    return status;
}

After FltStartFiltering() function is called, call FltAttachVolume() function to monitor the specific Disk drive or CD drive.

Unload Routine

Unload Routine should be written as below:

NTSTATUS
SpyFilterUnload (
    __in FLT_FILTER_UNLOAD_FLAGS Flags
    )
{
	PFLT_VOLUME		fltvolume;
	UNICODE_STRING	uniString;
	STRING			AnsiString;
	ULONG			i;
	KIRQL			irql;
    UNREFERENCED_PARAMETER( Flags );

    PAGED_CODE();

	...
	for(i = 0; i < 26; i++)
	{
		fltvolume = NULL;
		RtlInitAnsiString(&AnsiString, DrvInfo[i].szDrvName);
		RtlAnsiStringToUnicodeString(&uniString, &AnsiString, TRUE);
		FltGetVolumeFromName( ACDrvData.Filter, &uniString, &fltvolume);
		FltDetachVolume( ACDrvData.Filter, fltvolume, NULL);
		RtlFreeUnicodeString(&uniString);
	}
    
	FltCloseCommunicationPort( ACDrvData.ServerPort );
    FltUnregisterFilter( ACDrvData.Filter );
	ExDeleteNPagedLookasideList( &ACDrvData.FreeBufferList );
    
	return STATUS_SUCCESS;
}

FilterRegistration Variable Definition

FilterRegistration variable should be formatted like this:

CONST FLT_OPERATION_REGISTRATION Callbacks[] = {
    { IRP_MJ_CREATE,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_CREATE_NAMED_PIPE,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_CLOSE,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_READ,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_WRITE,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_QUERY_INFORMATION,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_SET_INFORMATION,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_QUERY_EA,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_SET_EA,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_FLUSH_BUFFERS,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_QUERY_VOLUME_INFORMATION,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_SET_VOLUME_INFORMATION,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_DIRECTORY_CONTROL,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_FILE_SYSTEM_CONTROL,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_DEVICE_CONTROL,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_INTERNAL_DEVICE_CONTROL,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_SHUTDOWN,
      0,
      SpyPreOperationCallback,
      NULL },                           //post operation callback not supported

    { IRP_MJ_LOCK_CONTROL,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_CLEANUP,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_CREATE_MAILSLOT,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_QUERY_SECURITY,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_SET_SECURITY,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_QUERY_QUOTA,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_SET_QUOTA,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_PNP,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_ACQUIRE_FOR_SECTION_SYNCHRONIZATION,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_RELEASE_FOR_SECTION_SYNCHRONIZATION,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_ACQUIRE_FOR_MOD_WRITE,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_RELEASE_FOR_MOD_WRITE,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_ACQUIRE_FOR_CC_FLUSH,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_RELEASE_FOR_CC_FLUSH,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

/*    { IRP_MJ_NOTIFY_STREAM_FILE_OBJECT,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },*/

    { IRP_MJ_FAST_IO_CHECK_IF_POSSIBLE,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_NETWORK_QUERY_OPEN,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_MDL_READ,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_MDL_READ_COMPLETE,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_PREPARE_MDL_WRITE,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_MDL_WRITE_COMPLETE,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_VOLUME_MOUNT,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_VOLUME_DISMOUNT,
      0,
      SpyPreOperationCallback,
      SpyPostOperationCallback },

    { IRP_MJ_OPERATION_END }
};

const FLT_CONTEXT_REGISTRATION Contexts[] = {

#if ACDRV_LONGHORN

    { FLT_TRANSACTION_CONTEXT,
      0,
      SpyDeleteTxfContext,
      sizeof(ACDRV_TRANSACTION_CONTEXT),
      'ypsM' },

#endif // ACDRV_LONGHORN

    { FLT_CONTEXT_END }
};

//
//  This defines what we want to filter with FltMgr
//

CONST FLT_REGISTRATION FilterRegistration = {

    sizeof(FLT_REGISTRATION),               //  Size
    FLT_REGISTRATION_VERSION,               //  Version
    0,                                      //  Flags

    Contexts,                               //  Context
    Callbacks,                              //  Operation callbacks

    SpyFilterUnload,                        //  FilterUnload

    NULL,                                   //  InstanceSetup
    SpyQueryTeardown,                       //  InstanceQueryTeardown
    NULL,                                   //  InstanceTeardownStart
    NULL,                                   //  InstanceTeardownComplete

    NULL,                                   //  GenerateFileName
    NULL,                                   //  GenerateDestinationFileName
    NULL                                    //  NormalizeNameComponent

#if ACDRV_LONGHORN
    ,
    SpyKtmNotificationCallback              //  KTM notification callback

#endif // ACDRV_LONGHORN

};

SpyPreOperationCallback() Function

SpyPreOperationCallback() function should be written like this:

FLT_PREOP_CALLBACK_STATUS
SpyPreOperationCallback (
    __inout PFLT_CALLBACK_DATA Data,
    __in PCFLT_RELATED_OBJECTS FltObjects,
    __deref_out_opt PVOID *CompletionContext
    )
{
	FLT_PREOP_CALLBACK_STATUS returnStatus = 
		FLT_PREOP_SUCCESS_NO_CALLBACK; //assume we are NOT going to call 
					//our completion routine
	
	...
	
	if (Data->Iopb->MajorFunction == IRP_MJ_SYSTEM_CONTROL)
		DbgPrint("System Control Called\n");
	//------------------------------------insert my process
	if (Data->Iopb->MajorFunction == IRP_MJ_CREATE) {
		
		...
		
		//If drive(path's first letter) is USB Memory Drive or CD Drive, 
		//Block!!!
		Data->IoStatus.Status = STATUS_ACCESS_DENIED;
		returnStatus = FLT_PREOP_COMPLETE;
		return returnStatus;
		
		...
	}
	returnStatus = FLT_PREOP_SUCCESS_WITH_CALLBACK;

	...

	return returnStatus;
}

Conclusion

Ok, it's all over. I know this is not the best method, but I think this technique can be used anytime. I hope this will be a good help for you to develop a similar program. If you have any questions, please contact me. I hope you are satisfied with my article. Please rate it for me. Thank you.

History

  • 27th April, 2011: Initial version

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

cnli
China China
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
Hint: For improved responsiveness ensure Javascript is enabled and choose 'Normal' from the Layout dropdown and hit 'Update'.
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberMichael_Romanov9 Dec '12 - 3:17 
QuestioncnlimemberGun Gun Febrianza9 Oct '12 - 15:15 
thank you this project help to develop another software Smile | :) Wink | ;)
Indonesian IT Intelijensi
Freedom of Revealing And Sharing Knowledge.
 
<img src="http://i564.photobucket.com/albums/ss86/febrianza/558392_461174860568975_902574845_n-1.jpg" border="0" alt="Photobucket">
 
www.net-sourcecode.blogspot.com

GeneralMy vote of 5memberGun Gun Febrianza9 Oct '12 - 15:14 
GeneralMy vote of 1memberDigvijay Chauhan20 Sep '11 - 11:36 
GeneralMy vote of 1memberprashu10012 May '11 - 22:47 
GeneralMy Vote of 0.00memberpersian music6 May '11 - 10:52 
GeneralMy vote of 1mvpDave Kreskowiak4 May '11 - 11:54 
GeneralRe: My vote of 1memberSharjith5 May '11 - 7:21 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web01 | 2.6.130523.1 | Last Updated 4 May 2011
Article Copyright 2011 by cnli
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid