【文章标题】: 挂钩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
[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!