文件过滤系统驱动开发Filemon学习笔记WINDOWS文件过滤系统驱动开发,可用于硬盘还原,防病毒,文件安全防护,文件加密等诸多领域。而掌握核心层的理论及实践,对于成为一名优秀的开发人员不可或缺。WINDOWS文件过滤系统驱动开发的两个经典例子,Filemon与SFilter,初学者在经过一定的理论积累后,对此两个例子代码的研究分析,会是步入驱动开发殿堂的重要一步,相信一定的理论积累以及贯穿剖析理解此两个例程后,就有能力开始进行文件过滤系统驱动开发的实际工作了。对于SFilter例子的讲解,楚狂人的教程已经比较流行,而Filemon例子也许因框架结构相对明晰,易于剖析理解,无人贴出教程,本人在剖析Filemon的过程中积累的一些笔记资料,陆续贴出希望对初学者有所帮助,并通过和大家的交流而互相提高。Filemon学习笔记第一篇:Filemon的大致架构为,在此驱动程序中,创建了两类设备对象。一类设备对象用于和Filemon对应的exe程序通信,以接收用户输入信息,比如挂接或监控哪个分区,是否要挂接,是否要监控,监控何种操作等。此设备对象只创建了一个,在驱动程序的入口函数DriverEntry中。此类设备对象一般称为控制设备对象,并有名字,以方便应用层与其通信操作。第二类设备对象用于挂接到所须监控的分区,比如c:,d:或e:,f:,以便拦截到引应用层对该分区所执行的读,写等操作。此类设备对象为安全起见,一般不予命名,可根据须监控多少分区而创建一个或多个。驱动入口函数大致如下NTSTATUSDriverEntry(INPDRIVER_OBJECTDriverObject,INPUNICODE_STRINGRegistryPath){NTSTATUSntStatus;PDEVICE_OBJECTguiDevice;WCHARdeviceNameBuffer[]=L\\Device\\Filemon;UNICODE_STRINGdeviceNameUnicodeString;WCHARdeviceLinkBuffer[]=L\\DosDevices\\Filemon;UNICODE_STRINGdeviceLinkUnicodeString;ULONGi;DbgPrint((Filemon.SYS:enteringDriverEntry\n));FilemonDriver=DriverObject;////Setupthedevicename//RtlInitUnicodeString(&deviceNameUnicodeString,deviceNameBuffer);////CreatethedeviceusedforGUIcommunications//此设备对象用来和用户交互信息ntStatus=IoCreateDevice(DriverObject,sizeof(HOOK_EXTENSION),&deviceNameUnicodeString,FILE_DEVICE_FILEMON,0,TRUE,&guiDevice);////Ifsuccessful,makeasymboliclinkthatallowsforthedevice//object'saccessfromWin32programs//if(NT_SUCCESS(ntStatus)){////MarkthisasourGUIdevice//((PHOOK_EXTENSION)guiDevice-DeviceExtension)-Type=GUIINTERFACE;////CreateasymboliclinkthattheGUIcanspecifytogainaccess//tothisdriver/device//RtlInitUnicodeString(&deviceLinkUnicodeString,deviceLinkBuffer);ntStatus=IoCreateSymbolicLink(&deviceLinkUnicodeString,&deviceNameUnicodeString);if(!NT_SUCCESS(ntStatus)){DbgPrint((Filemon.SYS:IoCreateSymbolicLinkfailed\n));IoDeleteDevice(guiDevice);returnntStatus;}////Createdispatchpointsforallroutinesthatmustbehandled.//Allentrypointsareregisteredsincewemightfiltera//filesystemthatprocessesallofthem.//for(i=0;i=IRP_MJ_MAXIMUM_FUNCTION;i++){DriverObject-MajorFunction[i]=FilemonDispatch;}#ifDBG////DriverunloadisonlysetifwearedebuggingFilemon.Thisis//becauseunloadingafilterisnotreallysafe-threadscould//beinourfastioroutines(orabouttoenterthem),forexample,//andthereisnowaytotell.Whendebugging,wecanriskthe//occasionalunloadcrashasatrade-offfornothavingto//rebootasoften.////DriverObject-DriverUnload=FilemonUnload;#endif//DBG////SetuptheFastI/Odispatchtable//DriverObject-FastIoDispatch=&FastIOHook;}else{////Ifsomethingwentwrong,cleanupthedeviceobjectanddon'tload//DbgPrint((Filemon:Failedtocreateourdevice!\n));returnntStatus;}////Initializethenamehashtable//for(i=0;iNUMHASH;i++)HashTable[i]=NULL;////Findtheprocessnameoffset//ProcessNameOffset=FilemonGetProcessNameOffset();//为了得到当前进程名字////Initializethesynchronizationobjects//#ifDBGKeInitializeSpinLock(&CountMutex);#endifExInitializeFastMutex(&LogMutex);ExInitializeResourceLite(&FilterResource);ExInitializeResourceLite(&HashResource);////Initializealookasideforfilenames//ExInitializeNPagedLookasideList(&FullPathLookaside,NULL,NULL,0,MAXPATHLEN,'mliF',256);////Allocatethefirstoutputbuffer//CurrentLog=ExAllocatePool(NonPagedPool,sizeof(*CurrentLog));if(!CurrentLog){////Oops-wecan'tdoanythingwithoutatleastonebuffer//IoDeleteSymbolicLink(&deviceLinkUnicodeString);IoDeleteDevice(guiDevice);returnSTATUS_INSUFFICIENT_RESOURCES;}////Setthebufferpointertothestartofthebufferjustallocated//CurrentLog-Len=0;CurrentLog-Next=NULL;NumLog=1;returnSTATUS_SUCCESS;}在此驱动入口点函数中,主要做了生成新的设备对象,此设备对象用来和应用层信息交互,比如应用层向驱动传递需要挂接或者监控的分区盘符,或者是否挂接盘符,是否监控操作等。上面创建设备对象的代码为:ntStatus=IoCreateDevice(DriverObject,sizeof(HOOK_EXTENSION),&deviceNameUnicodeString,FILE_DEVICE_FILEMON,0,TRUE,&guiDevice);////Ifsuccessful,makeasymboliclinkthatallowsforthedevice//object'saccessfromWin32programs//if(NT_SUCCESS(ntStatus)){////MarkthisasourGUIdevice//((PHOOK_EXTENSION)guiDevice-DeviceExtension)-Type=GUIINTERFACE;////CreateasymboliclinkthattheGUIcanspecifytogainaccess//tothisdriver/device//RtlInitUnicodeString(&deviceLinkUnicodeString,deviceLinkBuffer);ntStatus=IoCreateSymbolicLink(&deviceLinkUnicodeString,&deviceNameUnicodeString);if(!NT_SUCCESS(ntStatus)){DbgPrint((Filemon.SYS:IoCreateSymbolicLinkfailed\n));IoDeleteDevice(guiDevice);returnntStatus;}上面代码完成的功能为创建了用于与应用层交互的控制设备对象,名字在参数&deviceNameUnicodeString,中。设备对象创建成功后又调用IoCreateSymbolicLink创建了一个符号连接,以便于应用层交互。在入口点函数DriverEntry代码中,还有一处代码:ProcessNameOffset=FilemonGetProcessNameOffset();//为了得到当前进程名字。此函数体如下:ULONGFilemonGetProcessNameOffset(VOID){PEPROCESScurproc;inti;curproc=PsGetCurrentProcess();//调用PsGetCurrentProcess取得KPEB基址//然后搜索KPEB,得到ProcessName相对KPEB的偏移量//Scanfor12KB,hopingtheKPEBnevergrowsthatbig!//for(i=0;i3*PAGE_SIZE;i++){if(!strncmp(SYSNAME,(PCHAR)curproc+i,strlen(SYSNAME))){returni;}}////Namenotfound-oh,well//return0;这个函数通过查找KPEB(KernelProcessEnvironmentBlock),取得进程名,GetProcessNameOffset主要是调用PsGetCurrentProcess取得KPEB基址,然后搜索KPEB,得到ProcessName相对KPEB的偏移量,存放在全局变量ProcessNameOffset中,得到此偏移量的作用是:无论当前进程为哪个,其名字在KPEB中