U 盘文件监控

很简单的一个小玩意
就是监控U盘插上后记录创建 改名字 删除操作。
不过我这个是MINIFILTER架构;并且没有通知用户层
直接在C盘目录下创建文件记录操作的。
后来改了改;用于记录某些EXE安装过程中;出现了哪些SYS文件;方便分析同我的《关于隐藏文件夹附代码》一样否是从MINIFILTER的PASSTHROUGH框架改出的在PASSTHROUGH框架上逐步添加的一些代码
1.监控USB
PASSTHROUGH本身就监控卷的加载和卸载
我只是加了少许代码区分哪些是USB
[code]
// 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; 
 }  [/code]确认是USB设备后
我们设置一个实例上下文 记录它是USB类型
[code]
//将卷情况写入实例上下文(对于一个卷只有一个实例的情况 实例上下文即卷上下文且更有效率) 
 //
 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; 
[/code]然后是CREATE中进行操作
注意是CREATE后操作 CREATE预操作中 文件尚未建立 对于文件的确认判断是不确认的
[code]
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}
[/code]重命名 删除操作在哪里?在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)
其实删除也是一种重命名路径的操作 被删除文件转移到垃圾箱里的重命名
[code]
//我们只关心删除和重命名操作
 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 );
 }[/code]
到这里  需要监控的操作 创建 删除 重命名 已经全部监控完成
操作在手 天下我有啊:cool::D:那么怎么记录他们呢 每次截获都OPENFILE WRITEFIEL么 ?  NO
那样很没效率 而且文件过滤驱动中这么做 很容易重入的。(截获写操作的例程中又进行写操作,自己截获自己,为重入。 子子孙孙无穷匮也,也就是传说中的死循环:o:)
不过minifilter使用FLT系列函数已经解决了重入这个问题,但是这里我们还是不使用没效率的截获到就写入的办法。
这里参考了FILEDISK的做法 开启一个线程。
每当创建 重命名或者删除的操作被截获后,我们将要写入的内容丢入一个队列。
而开启的线程就无限循环,将队列的内容依次导出写入指定文件。[code]
// 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);[/code]
[code]
//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);
  }[/code]
然后就是一些细节问题 比如截获到的路径名都是unicode但是写入TXT文件的时候 如果出现中文反而不显示 要转化成ASCII代码才行
这里的处理代码很挫。。。而且我没深入调查  大家有兴趣或者知道答案 请告知一声 谢谢。
另外创建IRP查询BUSTYPE的代码 是从驱动开发网的ZNSOFT的帖子里获取 如果没这个帖子 我区分不出U盘与一般磁盘 在这里表示感谢
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值