yandong_8212
驱动小牛
驱动小牛
  • 注册日期2006-07-28
  • 最后登录2011-02-11
  • 粉丝0
  • 关注0
  • 积分1046分
  • 威望464点
  • 贡献值1点
  • 好评度173点
  • 原创分0分
  • 专家分1分
阅读:2601回复:2

今天闲来无事,研究了下SFilter,写了点总结,请指正.

楼主#
更多 发布于:2009-11-06 15:16
我以前是从FileSpy入手的.总体感觉其实差不多,SFilter比较纯净采用的是自动加载模式,没有提供多于的控制指令.FileSpy采用手动加载,提供了日志输出和一些控制指令.
今天我先发表一下对Sfilter的分析,方便初学者.以后也可能发表一下FileSpy,WDM的过滤驱动分析,不足之处请大家指正.我的邮箱是YanDong_8212@163.com
同时,在这里对初学者说一句,学习驱动最重要是去跟踪调试,多动手.

4.1 数据结构分析
1)
typedef struct _SFILTER_DEVICE_EXTENSION {

//
// Pointer to the file system device object we are attached to
//

PDEVICE_OBJECT AttachedToDeviceObject;

//
// Pointer to the real (disk) device object that is associated with
// the file system device object we are attached to
//

PDEVICE_OBJECT StorageStackDeviceObject;

//
// Name for this device. If attached to a Volume Device Object it is the
// name of the physical disk drive. If attached to a Control Device
// Object it is the name of the Control Device Object.
//

UNICODE_STRING DeviceName;

//
// Buffer used to hold the above unicode strings
//

WCHAR DeviceNameBuffer[MAX_DEVNAME_LENGTH];

} SFILTER_DEVICE_EXTENSION, *PSFILTER_DEVICE_EXTENSION;
该结构是放在新建的DeviceObject->DeviceExtension里面的,其中AttachedToDeviceObject保存的是新建的DeviceObject关联的文件系统设备对象, StorageStackDeviceObject保存的是磁盘设备,DeviceName保存设备的名称

举例:
当U盘插入时,各结构的值如下, StorageStackDeviceObject是\Driver\Disk的一个设备,
DeviceName是\Device\Harddisk2\DP(1)0-0+b, AttachedToDeviceObject是\FileSystem\FastFat的一个设备;

2)
typedef struct _FSCTRL_COMPLETION_CONTEXT {

//
// The workitem that will be initialized with our context and
// worker routine if this completion processing needs to be completed
// in a worker thread.
//

WORK_QUEUE_ITEM WorkItem;

//
// The device object to which this device is currently directed.
//

PDEVICE_OBJECT DeviceObject;

//
// The IRP for this FSCTRL operation.
//

PIRP Irp;

//
// For mount operations, the new device object that we have allocated
// and partially initialized that we will attach to the mounted volume
// if the mount is successful.
//

PDEVICE_OBJECT NewDeviceObject;

} FSCTRL_COMPLETION_CONTEXT, *PFSCTRL_COMPLETION_CONTEXT;
该结构用WINVER < 0x0501时的MoundVolume和LoadFileSystem处理,主要就是保存之前的信息,在完成例程里面使用.
4.2 基本函数,变量及宏
1) IS_MY_DEVICE_OBJECT(_devObj) 判断当前DeviceObject是否属于本驱动
2) IS_MY_CONTROL_DEVICE_OBJECT(_devObj) 判断当前DeviceObject是不是用于DeviceIoctrl的对象,该对象在DriverEntry中初始化,上层应用程序可以根据该设备和驱动通讯.通讯时需先建立符号连接例,具体方法参照Filespy的DriverEntry.
3) VALID_FAST_IO_DISPATCH_HANDLER 判断驱动是否支持对应的FastIo
4) SfGetFileName 获取文件名,该函数提供操作成功方式和操作失败两种方式.
5) SfGetFileNameCleanup清除上面函数中产生的文件名Buffer.
6) DELAY_ONE_MICROSECOND 这一系列宏用于Sleep(KeDelayExecutionThread)使用,驱动中的Sleep都为负数.
7) PDRIVER_OBJECT gSFilterDriverObject = NULL;驱动对象
8) PDEVICE_OBJECT gSFilterControlDeviceObject = NULL;驱动的DeviceIoctrl设备对象.
9) FAST_MUTEX gSfilterAttachLock; 关联设备时的锁
10) SFDEBUG_* 用于日志的分级控制;
11) GET_DEVICE_TYPE_NAME 获取设备的类型,需要区分设备类型时,可以使用该宏;

4.1.3 DriverEntry分析
1) 该函数是驱动初始化的入口,是驱动最先执行的函数,类似于应用层的main,WinMain;
2) SfLoadDynamicFunctions: XP及之后版本,需要动态加载一些函数,具体函数可以查看IFS帮助,其中比较关键的是RegisterFileSystemFilterCallbacks,在内存映射等操作时会在会调用SfPreFsFilterPassThrough和SfPostFsFilterPassThrough
3) SfReadDriverParameters:该函数用于读取Services\ DebugFlags,并将值赋给SfDebug,如果不设置该值就不进行调试和关联.所以,编译后需要修改此值才能调试和跟踪;
4) 一系列的初始化操作:指定DriverUnload回调,包括Attach时的锁,创建DeviceIoctrl设备对象,IRP Dispatch函数回调,FastIo Dispatch回调, RegisterFileSystemFilterCallbacks, RawDisk,RawCdrom回调(系统启动时,自动关联,系统关闭时,自动去除关联;关联之后,新mount的卷都会被截获到IRP_MJ_FILESYSTEM_CTRL,因此初始化时最重要的就是注册这一系列的回调,这些在之后的操作中会用到.)
5) ClearFlag( gSFilterControlDeviceObject->Flags, DO_DEVICE_INITIALIZING ):专门把这一句提出来是为了引起足够的重视,每个DeviceObject在初始化完毕后,都必须去掉这个标记,标识设备已经完成初始化.
4.3 DriverUnload分析
1) 该函数类似于析构函数,值在XP及之后版本存在,和DriverEntry功能刚好相反.
2) IoUnregisterFsRegistrationChange:取消注册的回调;
3)枚举本驱动的所有DevicObject,并反初始化;
4) 枚举本驱动的所有DeviceObject并删除
5) 释放FastIoDispatch内存;

4.4 SfFsNotification分析
该函数用于卷设备发生变化时的通知调用,功能很简单.内部调用SfAttachToFileSystemDevice和SfDetachToFileSystemDevice,作用对象是文件系统设备.当Attch上去后,之后的IRP_MJ_FILESYSTEM_CTRL才会通过本层驱动.
4.5流程及结构分析
整体结构:




1) 如上图所示,那么流程是(不知道能发图片不,FSDO-FileSystemDO,VDO-VolumeDO,AFDO-attach FS DO, AVDO-attch VDO,总体意思就是文件系统包含多个卷设备,Sfilter会同时Attach到文件系统和卷设备上.):

FSDO->VDO->AFDO->AVDO
STEP 1:文件系统创建
STEP2:文件系统自行Mount卷
STEP3:Sfilter在DriverEntry中注册的SfFsNotification 关联到文件系统对象上形成AFDO,并且枚举已有的卷设备VDO,形成AVDO

2) 当有类似U盘的设备插入,流程是:
IRP_MJ_FILESYSTEM_CTRL/IRP_MN_MOUNT_VOLUME->ATTACHE到新的VDO上,形成AVDO

3) 值得注意的是,设备Mount之后默认是没有Unmount的操作的,所以一个设备对象建立以后就不会删除,直到系统重启,除非是通过DeviceIoctrl由上层主动发起.
4.6 自身数据结构的存放问题
1) 如果是整个驱动都需要的数据结构,直接作为全局或保存在DeviceExtension中;
2) 如果是跟卷相关的数据结构,最好是在Attach到卷设备时,放在卷设备的DeviceExtension中;
3) 补充说明,如果在DeviceExtension中申请了ERESOURCE,那么必须在DeleteDevice时释放ERESOURCE,因为ERESOURCE保存在系统全局列表中,否则下次调用ERESOURCE相关的函数时会报奇怪的错误.
4.7 常用手法
1) 文件名处理:
通常需要在DeviceExtension中维护一个列表,保存已打开的文件列表.当create成功时,将以FileObject或FCB为索引,进行保存;当Close时,删除对应的Entry;当其他时候需要访问时,通过FileObject或FCB进行查询获得,其他时候FileObject->FileName字段是不可信的,仅做调试参考.

2) 下发IO操作,不做任何处理:
PassThrough()
{
IoSkipCurrentIrpStackLocation( Irp );
Status = IoCallDriver(AttachedDevice, Irp );
return status;
}
3) 以某种错误直接结束IRP
DenyThrough()
{
Irp->IoStatus.Status = status = STATUS_ACCESS_DENY;
Irp->IoStatus.Information = 0;
IoCompleteIrp(Irp, IO_NO_INCREMENT);
Return status;
}
4) 需要判断下以后的状态并做修改
KeInitializeEvent( &waitEvent, NotificationEvent, FALSE );
IoCopyCurrentIrpStackLocationToNext( Irp );
IoSetCompletionRoutine(
Irp,
CreateCompletion,
&waitEvent,
TRUE,
TRUE,
TRUE );
status = IoCallDriver(AttachedToDeviceObject, Irp );

if (STATUS_PENDING == status) {
NTSTATUS localStatus = KeWaitForSingleObject(&waitEvent, Executive, KernelMode, FALSE, NULL);
ASSERT(STATUS_SUCCESS == localStatus);
}
//此处判断

IoCompleteIrp(Irp, IO_NO_INCREMENT);
Return status;
5) 重定向操作

ExFreePool(FileObject->FileName.Buffer);
FileObject->FileName.Length = 0;
FileObject->FileName.MaximumLength = MAX_PATH;
FileObject->DeviceObject = NULL;
RtlInitUnicodeString(&FileObject->FileName, temp_buf);
status = Irp->IoStatus.Status = STATUS_REPARSE;
Irp->IoStatus.Information = IO_REPARSE;
Return IO_REPARSE;

6) 隐藏文件
处理IRP_MJ_DIR_CTRL/ IRP_MN_QUERY_DIRECTORY中的FileBothDirectoryInformation;

7) ...

商务MSN:YanDong_8212@163.com
neak47
驱动小牛
驱动小牛
  • 注册日期2009-05-25
  • 最后登录2016-01-09
  • 粉丝4
  • 关注0
  • 积分140分
  • 威望1221点
  • 贡献值1点
  • 好评度0点
  • 原创分0分
  • 专家分1分
沙发#
发布于:2009-11-06 15:40
支持原创。。
xum2008
驱动牛犊
驱动牛犊
  • 注册日期2009-05-08
  • 最后登录2014-08-10
  • 粉丝0
  • 关注0
  • 积分75分
  • 威望741点
  • 贡献值0点
  • 好评度0点
  • 原创分0分
  • 专家分0分
板凳#
发布于:2009-11-06 23:51
太好了。。。
喜欢这样的东西。。
游客

返回顶部