找回密码
 加入我们

QQ登录

只需一步,快速开始

搜索
查看: 9635|回复: 7

U 盘文件监控 附加源代码

[复制链接]

3

主题

28

回帖

2

精华

钻石会员

积分
2827
发表于 2013-1-8 22:38:16 | 显示全部楼层 |阅读模式
本帖最后由 catface0511 于 2013-1-9 11:18 编辑

很简单的一个小玩意
就是监控U盘插上后记录创建 改名字 删除操作。
不过我这个是MINIFILTER架构 没有通知用户层
直接在C盘目录下创建文件记录操作的。
后来改了改 用于记录某些EXE安装过程中出现了哪些SYS文件 方便分析
1.监控USB
PASSTHROUGH本身就监控卷的加载和卸载
我只是加了少许代码 区分哪些是USB加载 那些是磁盘加载
  1. // Create IRP Get The BusType
  2. //
  3. status = FltGetDiskDeviceObject(FltObjects->Volume, &DiskDeviceObject);
  4. if (status == STATUS_FLT_NO_DEVICE_OBJECT )
  5. {
  6.   return STATUS_SUCCESS;
  7. }else if(!NT_SUCCESS(status))
  8. {
  9.   return status;
  10. }
  11. KeInitializeEvent(&WaitEvent, NotificationEvent, FALSE);
  12. Query.PropertyId = StorageDeviceProperty;//StorageDeviceType;//
  13. Query.QueryType = PropertyStandardQuery;
  14. NewIrp = IoBuildDeviceIoControlRequest(IOCTL_STORAGE_QUERY_PROPERTY, DiskDeviceObject,
  15.    (PVOID)&Query, sizeof(STORAGE_DEVICE_DESCRIPTOR), (PVOID)pBuffer,
  16.    sizeof(STORAGE_DEVICE_DESCRIPTOR) * 4, FALSE, &WaitEvent, &IoStatus);
  17. if (NULL == NewIrp)   // can't create new irp
  18. {
  19.   DbgPrint(" BusTypeUnknown \n");
  20.   return STATUS_SUCCESS;
  21. }
  22. status = IoCallDriver(DiskDeviceObject, NewIrp);

  23. if (status == STATUS_PENDING)
  24. {
  25.   status = KeWaitForSingleObject(&WaitEvent, Executive, KernelMode, FALSE, NULL);
  26.   status = IoStatus.Status;
  27. }
  28. if (!NT_SUCCESS(status))
  29. {
  30.   DbgPrint(" BusTypeUnknown \n");
  31.   return STATUS_SUCCESS;
  32. }
  33. Descriptor = (PSTORAGE_DEVICE_DESCRIPTOR)pBuffer;
  34. if(Descriptor->BusType == 7)
  35. {
  36.   DbgPrint("GetStorageDeviceBusType  SUCCEED: %d DevType:%x \n   ",
  37.          Descriptor->BusType, DiskDeviceObject->DeviceType);
  38. }else if (Descriptor->BusType == 3)
  39. {
  40.   DbgPrint("GetStorageDeviceBusType  SUCCEED: %d DevType:%x  \n   ",
  41.          Descriptor->BusType, DiskDeviceObject->DeviceType);
  42. }else
  43. {
  44.   return STATUS_SUCCESS;
  45. }  
复制代码
我们设置一个实例上下文 记录它是USB类型
  1. //将卷情况写入实例上下文(对于一个卷只有一个实例的情况 实例上下文即卷上下文且更有效率)
  2. //
  3. status = FltAllocateContext( FltObjects->Filter,
  4.                                  FLT_INSTANCE_CONTEXT,
  5.                                  CTX_INSTANCE_CONTEXT_SIZE,
  6.                                  NonPagedPool,
  7.                                  &instanceContext );
  8. if (!NT_SUCCESS( status ))
  9. {
  10.   DbgPrint("Instance Setup  Allocate Context Failed %08x\n",status);
  11.   return status;
  12.     }
  13. instanceContext->Instance = FltObjects->Instance;
  14.     instanceContext->Volume = FltObjects->Volume;
  15. instanceContext->BusType = Descriptor->BusType;

  16. status = FltSetInstanceContext( FltObjects->Instance,
  17.                                     FLT_SET_CONTEXT_REPLACE_IF_EXISTS ,
  18.                                     instanceContext,
  19.                                     NULL );
  20.     if( !NT_SUCCESS( status ))
  21. {
  22.   DbgPrint("Instance Setup  Set Context Failed %08x\n",status);
  23.   if ( instanceContext != NULL )
  24.   {
  25.    FltReleaseContext( instanceContext );
  26.   }
  27.   return status;
  28. }

  29. if ( instanceContext != NULL )
  30. {
  31.         FltReleaseContext( instanceContext );
  32. }

  33. return STATUS_SUCCESS;
复制代码
然后是CREATE中进行操作
注意是CREATE后操作 CREATE预操作中 文件尚未建立 对于文件的确认判断是不确认的
  1. FLT_POSTOP_CALLBACK_STATUS
  2. PtPostOperationCreate(
  3.     __inout PFLT_CALLBACK_DATA Data,
  4.     __in PCFLT_RELATED_OBJECTS FltObjects,
  5.     __in_opt PVOID CompletionContext,
  6.     __in FLT_POST_OPERATION_FLAGS Flags
  7.     )
  8. {
  9.   // 确认文件创建成功
  10.   if ( !NT_SUCCESS( Data->IoStatus.Status ) || ( STATUS_REPARSE == Data->IoStatus.Status ) )   
  11.     {   
  12.      return FLT_POSTOP_FINISHED_PROCESSING;   
  13.     }
  14. if((create_option != FILE_CREATE) && (create_option != FILE_OVERWRITE_IF) ) //确认为新建文件操作
  15. {
  16.   return FLT_POSTOP_FINISHED_PROCESSING;
  17. }
  18. status =  FltQueryInformationFile(FltObjects->Instance,
  19.      FltObjects->FileObject,
  20.      &FileInformation,
  21.      sizeof(FileInformation),
  22.      FileStandardInformation,NULL);
  23. if(!NT_SUCCESS(status))   
  24. {
  25.    DbgPrint("Createpost QueryFile Failed %08x\n",status);
  26.    return  FLT_POSTOP_FINISHED_PROCESSING;
  27. }
  28. //确认不是创建文件夹 是文件夹则直接返回
  29.           // 其实这里MINIFILTER已经有API可以调用 不必这么麻烦
  30. if(FileInformation.Directory)
  31. {
  32.   return  FLT_POSTOP_FINISHED_PROCESSING;  
  33.            }            //尝试获得实例上下文 从而获得BUSTYPE
  34. //
  35. status = FltGetInstanceContext( FltObjects->Instance,
  36.                                     &PInstanceContext );
  37. if(NT_SUCCESS(status))
  38. {
  39.   BusType = PInstanceContext->BusType;
  40.   FltReleaseContext( PInstanceContext );
  41. }
  42.              // 如果BUFTYPE不是等于7 说明不是U盘文件 我们不必管他
  43.         // 后面则是确认文件名字等一系列操作了
  44.         // 这个很简单 MINIFLTER简化了很多
  45.         // FltGetFileNameInformation FltParseFileNameInformation 两个函数搞定
  46.        // 如果想转化为类似"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)
其实删除也是一种重命名路径的操作 被删除文件转移到垃圾箱里的重命名
  1. //我们只关心删除和重命名操作
  2. if((Data->Iopb->Parameters.SetFileInformation.FileInformationClass  != FileDispositionInformation) &&
  3.   (Data->Iopb->Parameters.SetFileInformation.FileInformationClass  != FileRenameInformation))
  4. {
  5.   return FLT_POSTOP_FINISHED_PROCESSING;
  6. }
  7. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8. //
  9. //尝试获得实例上下文 从而获得BUSTYPE
  10. //确认是否是U盘上的文件操作
  11. status = FltGetInstanceContext( FltObjects->Instance,
  12.                                     &PInstanceContext );
  13. if(NT_SUCCESS(status))
  14. {
  15.   BusType = PInstanceContext->BusType;
  16.   FltReleaseContext( PInstanceContext );
  17. }
复制代码
到这里  需要监控的操作 创建 删除 重命名 已经全部监控完成
操作在手 天下我有啊:cool::D:那么怎么记录他们呢 每次截获都OPENFILE WRITEFIEL么 ?  NO
那样很没效率 而且文件过滤驱动中这么做 很容易重入的。
(截获写操作的例程中又进行写操作,自己截获自己,为重入。 子子孙孙无穷匮也,也就是传说中的死循环:o:)

每当创建 重命名或者删除的操作被截获后,我们将要写入的内容丢入一个队列。
而开启的线程就无限循环,将队列的内容依次导出写入指定文件
  1. // driverentry的驱动入口函数中创建一个队列 和开启一个线程
  2. InitializeListHead(&MyGlovalVar.ProcessListHead);   //初始化链表头
  3.     KeInitializeSpinLock(&MyGlovalVar.ProcessListLock); //初始化链表锁
  4. KeInitializeEvent(
  5.         &MyGlovalVar.request_event,
  6.         SynchronizationEvent,
  7.         FALSE
  8.         );
  9. MyGlovalVar.terminate_thread = FALSE;

  10. //
  11. //创建进程
  12. //
  13. status = PsCreateSystemThread(
  14.         &thread_handle,
  15.         (ACCESS_MASK) 0L,
  16.         NULL,
  17.         NULL,
  18.         NULL,
  19.         FilePathThread,
  20.         &MyGlovalVar);
复制代码

  1. //FilePathThread函数
  2. VOID
  3. FilePathThread (IN PVOID Context)
  4. {
  5. PMYGLOBALVAR  GolVar;
  6. PLIST_ENTRY         request;
  7. PMYFILEDATA   PMyFileData;

  8. ASSERT(Context != NULL);
  9. GolVar = (PMYGLOBALVAR)Context;
  10. KeSetPriorityThread(KeGetCurrentThread(), LOW_REALTIME_PRIORITY);
  11. // 不断循环
  12. for( ; ; )
  13. {
  14.                   // 队列里的操作全部被线程完成后 线程在这里等待
  15.                   //等待EVENT时间触发,当有创建 重命名与删除操作截获入队列后 EVENT时间被触发
  16.   KeWaitForSingleObject(
  17.             &MyGlovalVar.request_event,
  18.             Executive,
  19.             KernelMode,
  20.             FALSE,
  21.             NULL
  22.             );
  23.          // 一个全局变量 当需要关闭线程的时候 这个变量被置为true
  24.          if (MyGlovalVar.terminate_thread)
  25.         {
  26.    DbgPrint("FilePathThread   :Thread Exit\n");
  27.             PsTerminateSystemThread(STATUS_SUCCESS);
  28.         }while (request = ExInterlockedRemoveHeadList(
  29.             &MyGlovalVar.ProcessListHead,
  30.             &MyGlovalVar.ProcessListLock))
  31.   {
  32.    PMyFileData = CONTAINING_RECORD(request, MYFILEDATA, myListEntry);
  33.    DbgPrint("Thread CHAR OPER is %s\n",PMyFileData->Oper);
  34.    DbgPrint("Thread UNICODE Path  is %wZ\n",&PMyFileData->PathName);
  35.    DbgPrint("Thread WCHAR ParName  is %S\n",PMyFileData->ParName);
  36.    
  37.    WriteLogFile(PMyFileData);
  38.    
  39.    if(PMyFileData->PathName.Buffer != NULL)
  40.     ExFreePool(PMyFileData->PathName.Buffer);
  41.    if(PMyFileData != NULL)
  42.     ExFreePool(PMyFileData);
  43.   }
复制代码
然后就是一些细节问题 比如截获到的路径名都是unicode但是写入TXT文件的时候 如果出现中文反而不显示 要转化成ASCII代码才行
这里的处理代码很挫。。。而且我没深入调查  大家有兴趣或者知道答案 请告知一声 谢谢。
另外创建IRP查询BUSTYPE的代码 是从驱动开发网的ZNSOFT的帖子里获取 如果没这个帖子 我区分不出U盘与一般磁盘 在这里表示感谢

/***********************************************************************************/
另外再说个这个代码的用处
在卷加载的时候通过BUSTYPE判断是不是USB 这个代码再开头已经给出了
判断出是USB之后 我们在写入例程对写入操作进行拦截
那么U盘就成为只读U盘了

Def_PassThrough0330.rar

121.63 KB, 阅读权限: 10, 下载次数: 42

售价: 1 水晶币  [记录]

代码

评分

参与人数 1水晶币 +100 收起 理由
Tesla.Angela + 100

查看全部评分

275

主题

3017

回帖

1

精华

管理员

嗷嗷叫的老马

积分
17064

论坛牛人贡献奖关注奖最佳版主进步奖人气王疯狂作品奖精英奖赞助论坛勋章乐于助人勋章

QQ
发表于 2013-1-9 01:16:13 | 显示全部楼层
过滤驱动很有意思....支持一下!
我就是嗷嗷叫的老马了......

1

主题

60

回帖

0

精华

铜牌会员

积分
122
发表于 2013-1-9 10:29:53 | 显示全部楼层
学习了

857

主题

2632

回帖

2

精华

管理员

此生无悔入华夏,  长居日耳曼尼亚。  

积分
36130
发表于 2013-1-9 18:58:30 | 显示全部楼层
U盘是否只读不重要,重要的是别让U盘上的程序跑起来就行了。

3

主题

28

回帖

2

精华

钻石会员

积分
2827
 楼主| 发表于 2013-1-11 22:11:04 | 显示全部楼层
ddk的例子不能监控USB 创建重命名新建 写入 删除操作吧

0

主题

2

回帖

0

精华

初来乍到

积分
17
发表于 2013-4-4 13:46:55 | 显示全部楼层
这个好,不过谁有底层的书籍我看看

7

主题

414

回帖

1

精华

铂金会员

积分
2173
发表于 2013-4-7 12:15:37 | 显示全部楼层
這個強,支持一下

0

主题

18

回帖

0

精华

初来乍到

积分
26
发表于 2020-3-15 10:38:15 | 显示全部楼层
支持一下。
您需要登录后才可以回帖 登录 | 加入我们

本版积分规则

快速回复 返回顶部 返回列表