|
本帖最后由 catface0511 于 2013-1-9 11:18 编辑
很简单的一个小玩意
就是监控U盘插上后记录创建 改名字 删除操作。
不过我这个是MINIFILTER架构 没有通知用户层
直接在C盘目录下创建文件记录操作的。
后来改了改 用于记录某些EXE安装过程中出现了哪些SYS文件 方便分析
1.监控USB
PASSTHROUGH本身就监控卷的加载和卸载
我只是加了少许代码 区分哪些是USB加载 那些是磁盘加载- // Create IRP Get The BusType
- //
- status = FltGetDiskDeviceObject(FltObjects->Volume, &DiskDeviceObject);
- if (status == STATUS_FLT_NO_DEVICE_OBJECT )
- {
- return STATUS_SUCCESS;
- }else if(!NT_SUCCESS(status))
- {
- return status;
- }
- KeInitializeEvent(&WaitEvent, NotificationEvent, FALSE);
- Query.PropertyId = StorageDeviceProperty;//StorageDeviceType;//
- Query.QueryType = PropertyStandardQuery;
- NewIrp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_QUERY_PROPERTY, DiskDeviceObject,
- (PVOID)&Query, sizeof(STORAGE_DEVICE_DESCRIPTOR), (PVOID)pBuffer,
- sizeof(STORAGE_DEVICE_DESCRIPTOR) * 4, FALSE, &WaitEvent, &IoStatus);
- if (NULL == NewIrp) // can't create new irp
- {
- DbgPrint(" BusTypeUnknown \n");
- return STATUS_SUCCESS;
- }
- status = IoCallDriver(DiskDeviceObject, NewIrp);
-
- if (status == STATUS_PENDING)
- {
- status = KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, NULL);
- status = IoStatus.Status;
- }
- if (!NT_SUCCESS(status))
- {
- DbgPrint(" BusTypeUnknown \n");
- return STATUS_SUCCESS;
- }
- Descriptor = (PSTORAGE_DEVICE_DESCRIPTOR)pBuffer;
- if(Descriptor->BusType == 7)
- {
- DbgPrint("GetStorageDeviceBusType SUCCEED: %d DevType:%x \n ",
- Descriptor->BusType, DiskDeviceObject->DeviceType);
- }else if (Descriptor->BusType == 3)
- {
- DbgPrint("GetStorageDeviceBusType SUCCEED: %d DevType:%x \n ",
- Descriptor->BusType, DiskDeviceObject->DeviceType);
- }else
- {
- return STATUS_SUCCESS;
- }
复制代码 我们设置一个实例上下文 记录它是USB类型- //将卷情况写入实例上下文(对于一个卷只有一个实例的情况 实例上下文即卷上下文且更有效率)
- //
- status = FltAllocateContext( FltObjects->Filter,
- FLT_INSTANCE_CONTEXT,
- CTX_INSTANCE_CONTEXT_SIZE,
- NonPagedPool,
- &instanceContext );
- if (!NT_SUCCESS( status ))
- {
- DbgPrint("Instance Setup Allocate Context Failed %08x\n",status);
- return status;
- }
- instanceContext->Instance = FltObjects->Instance;
- instanceContext->Volume = FltObjects->Volume;
- instanceContext->BusType = Descriptor->BusType;
-
- status = FltSetInstanceContext( FltObjects->Instance,
- FLT_SET_CONTEXT_REPLACE_IF_EXISTS ,
- instanceContext,
- NULL );
- if( !NT_SUCCESS( status ))
- {
- DbgPrint("Instance Setup Set Context Failed %08x\n",status);
- if ( instanceContext != NULL )
- {
- FltReleaseContext( instanceContext );
- }
- return status;
- }
-
- if ( instanceContext != NULL )
- {
- FltReleaseContext( instanceContext );
- }
-
- return STATUS_SUCCESS;
复制代码 然后是CREATE中进行操作
注意是CREATE后操作 CREATE预操作中 文件尚未建立 对于文件的确认判断是不确认的- FLT_POSTOP_CALLBACK_STATUS
- PtPostOperationCreate(
- __inout PFLT_CALLBACK_DATA Data,
- __in PCFLT_RELATED_OBJECTS FltObjects,
- __in_opt PVOID CompletionContext,
- __in FLT_POST_OPERATION_FLAGS Flags
- )
- {
- // 确认文件创建成功
- if ( !NT_SUCCESS( Data->IoStatus.Status ) || ( STATUS_REPARSE == Data->IoStatus.Status ) )
- {
- return FLT_POSTOP_FINISHED_PROCESSING;
- }
- if((create_option != FILE_CREATE) && (create_option != FILE_OVERWRITE_IF) ) //确认为新建文件操作
- {
- return FLT_POSTOP_FINISHED_PROCESSING;
- }
- status = FltQueryInformationFile(FltObjects->Instance,
- FltObjects->FileObject,
- &FileInformation,
- sizeof(FileInformation),
- FileStandardInformation,NULL);
- if(!NT_SUCCESS(status))
- {
- DbgPrint("Createpost QueryFile Failed %08x\n",status);
- return FLT_POSTOP_FINISHED_PROCESSING;
- }
- //确认不是创建文件夹 是文件夹则直接返回
- // 其实这里MINIFILTER已经有API可以调用 不必这么麻烦
- if(FileInformation.Directory)
- {
- return FLT_POSTOP_FINISHED_PROCESSING;
- } //尝试获得实例上下文 从而获得BUSTYPE
- //
- status = FltGetInstanceContext( FltObjects->Instance,
- &PInstanceContext );
- if(NT_SUCCESS(status))
- {
- BusType = PInstanceContext->BusType;
- FltReleaseContext( PInstanceContext );
- }
- // 如果BUFTYPE不是等于7 说明不是U盘文件 我们不必管他
- // 后面则是确认文件名字等一系列操作了
- // 这个很简单 MINIFLTER简化了很多
- // FltGetFileNameInformation FltParseFileNameInformation 两个函数搞定
- // 如果想转化为类似"d:\ test.file"之类的 使用RtlVolumeDeviceToDosName}
复制代码 重命名 删除操作在哪里?在SETINFORMATION操作中FLT_POSTOP_CALLBACK_STATUS
PtPostOperationSetInfor(
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__in_opt PVOID CompletionContext,
__in FLT_POST_OPERATION_FLAGS Flags)
其实删除也是一种重命名路径的操作 被删除文件转移到垃圾箱里的重命名- //我们只关心删除和重命名操作
- if((Data->Iopb->Parameters.SetFileInformation.FileInformationClass != FileDispositionInformation) &&
- (Data->Iopb->Parameters.SetFileInformation.FileInformationClass != FileRenameInformation))
- {
- return FLT_POSTOP_FINISHED_PROCESSING;
- }
- ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
- //
- //尝试获得实例上下文 从而获得BUSTYPE
- //确认是否是U盘上的文件操作
- status = FltGetInstanceContext( FltObjects->Instance,
- &PInstanceContext );
- if(NT_SUCCESS(status))
- {
- BusType = PInstanceContext->BusType;
- FltReleaseContext( PInstanceContext );
- }
复制代码 到这里 需要监控的操作 创建 删除 重命名 已经全部监控完成
操作在手 天下我有啊:cool::D:那么怎么记录他们呢 每次截获都OPENFILE WRITEFIEL么 ? NO
那样很没效率 而且文件过滤驱动中这么做 很容易重入的。
(截获写操作的例程中又进行写操作,自己截获自己,为重入。 子子孙孙无穷匮也,也就是传说中的死循环:o:)
每当创建 重命名或者删除的操作被截获后,我们将要写入的内容丢入一个队列。
而开启的线程就无限循环,将队列的内容依次导出写入指定文件- // driverentry的驱动入口函数中创建一个队列 和开启一个线程
- InitializeListHead(&MyGlovalVar.ProcessListHead); //初始化链表头
- KeInitializeSpinLock(&MyGlovalVar.ProcessListLock); //初始化链表锁
- KeInitializeEvent(
- &MyGlovalVar.request_event,
- SynchronizationEvent,
- FALSE
- );
- MyGlovalVar.terminate_thread = FALSE;
-
- //
- //创建进程
- //
- status = PsCreateSystemThread(
- &thread_handle,
- (ACCESS_MASK) 0L,
- NULL,
- NULL,
- NULL,
- FilePathThread,
- &MyGlovalVar);
复制代码
- //FilePathThread函数
- VOID
- FilePathThread (IN PVOID Context)
- {
- PMYGLOBALVAR GolVar;
- PLIST_ENTRY request;
- PMYFILEDATA PMyFileData;
-
- ASSERT(Context != NULL);
- GolVar = (PMYGLOBALVAR)Context;
- KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
- // 不断循环
- for( ; ; )
- {
- // 队列里的操作全部被线程完成后 线程在这里等待
- //等待EVENT时间触发,当有创建 重命名与删除操作截获入队列后 EVENT时间被触发
- KeWaitForSingleObject(
- &MyGlovalVar.request_event,
- Executive,
- KernelMode,
- FALSE,
- NULL
- );
- // 一个全局变量 当需要关闭线程的时候 这个变量被置为true
- if (MyGlovalVar.terminate_thread)
- {
- DbgPrint("FilePathThread :Thread Exit\n");
- PsTerminateSystemThread(STATUS_SUCCESS);
- }while (request = ExInterlockedRemoveHeadList(
- &MyGlovalVar.ProcessListHead,
- &MyGlovalVar.ProcessListLock))
- {
- PMyFileData = CONTAINING_RECORD(request, MYFILEDATA, myListEntry);
- DbgPrint("Thread CHAR OPER is %s\n",PMyFileData->Oper);
- DbgPrint("Thread UNICODE Path is %wZ\n",&PMyFileData->PathName);
- DbgPrint("Thread WCHAR ParName is %S\n",PMyFileData->ParName);
-
- WriteLogFile(PMyFileData);
-
- if(PMyFileData->PathName.Buffer != NULL)
- ExFreePool(PMyFileData->PathName.Buffer);
- if(PMyFileData != NULL)
- ExFreePool(PMyFileData);
- }
复制代码 然后就是一些细节问题 比如截获到的路径名都是unicode但是写入TXT文件的时候 如果出现中文反而不显示 要转化成ASCII代码才行
这里的处理代码很挫。。。而且我没深入调查 大家有兴趣或者知道答案 请告知一声 谢谢。
另外创建IRP查询BUSTYPE的代码 是从驱动开发网的ZNSOFT的帖子里获取 如果没这个帖子 我区分不出U盘与一般磁盘 在这里表示感谢
/***********************************************************************************/
另外再说个这个代码的用处
在卷加载的时候通过BUSTYPE判断是不是USB 这个代码再开头已经给出了
判断出是USB之后 我们在写入例程对写入操作进行拦截
那么U盘就成为只读U盘了 |
评分
-
查看全部评分
|