在kernel中读写文件要比在应用层麻烦一些,但是基本思路大体上还是一致的。
在内核中,也有很多相关的读写文件的API,本文只对
FltCreateFileEx
FltReadFile
FltWriteFile
进行简单说明。
这三个API和应用层的API CreateFileEx,ReadFile和WriteFile相对应。其作用分别是打开文件,从文件中读取数据和将数据写入文件。下面这个函数实现了文件拷贝操作,即将FullFileName的文件内容拷贝到FullFileName2中。
NTSTATUS ReadFileTest(INPUNICODE_STRINGFullFileName,INPUNICODE_STRINGFullFileName2)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
PVOID buffer = NULL;
ULONG total_len = 0;
ULONG readbytes = 0;
ULONG byteswritten = 0;
HANDLE FileHandle = NULL;
PFILE_OBJECT FileObject = NULL;
HANDLE FileHandle2 = NULL;
PFILE_OBJECT FileObject2 = NULL;
OBJECT_ATTRIBUTES ObjectAttributes;
OBJECT_ATTRIBUTES ObjectAttributes2;
IO_STATUS_BLOCK IoStatus;
PFLT_VOLUME Volume = NULL;
PFLT_INSTANCE Instance = NULL;
buffer = ExAllocatePoolWithTag(PagedPool, 4096,'ssmf');
InitializeObjectAttributes(
&ObjectAttributes,
FullFileName,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
InitializeObjectAttributes(
&ObjectAttributes2,
FullFileName2,
OBJ_KERNEL_HANDLE | OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
status = FltCreateFileEx(
gFilterHandle,
NULL,
&FileHandle,
&FileObject,
GENERIC_READ,
&ObjectAttributes,
&IoStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY | FILE_COMPLETE_IF_OPLOCKED,
NULL,
0,
IO_NO_PARAMETER_CHECKING
);
status = FltCreateFileEx(
gFilterHandle,
NULL,
&FileHandle2,
&FileObject2,
GENERIC_READ|GENERIC_WRITE,
&ObjectAttributes2,
&IoStatus,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OVERWRITE_IF,
FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_ALERT | FILE_SEQUENTIAL_ONLY | FILE_COMPLETE_IF_OPLOCKED,
NULL,
0,
IO_NO_PARAMETER_CHECKING
);
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("SSMF:Open the file status is status=%08x\n",status));
if (FileObject)
{
//read the file
//get the volume
status = FltGetVolumeFromFileObject(gFilterHandle, FileObject, &Volume);
if (NT_SUCCESS(status))
{
status = FltGetVolumeInstanceFromName(
gFilterHandle,
Volume,
NULL,
&Instance
);
if (NT_SUCCESS(status))
{
while (STATUS_END_OF_FILE != FltReadFile(Instance, FileObject, NULL, 4096,
buffer,FLTFL_IO_OPERATION_NON_CACHED, &readbytes, NULL,NULL))
{
total_len += readbytes;
PT_DBG_PRINT(PTDBG_TRACE_ROUTINES, ("SSMF:Read length is %u,total len is %u\n", readbytes, total_len));
FltWriteFile(Instance, FileObject2,NULL, readbytes, buffer, FLTFL_IO_OPERATION_NON_CACHED, &byteswritten, NULL,NULL);
}
}
if (Volume)
{
FltObjectDereference(Volume);
}
if (Instance)
{
FltObjectDereference(Instance);
}
}
}
if (FileObject)
{
FltClose(FileHandle);
ObDereferenceObject(FileObject);
}
if (FileObject2)
{
FltClose(FileHandle2);
ObDereferenceObject(FileObject2);
}
if (buffer != NULL)
{
ExFreePoolWithTag(buffer,'ssmf');
}
return status;
}
写这段代码的时候发生了一个小插曲,当我准备用sc stop ssmf来停止ssmf的时候,居然hung住了,我想肯定是我的代码有问题,果断按下ctrl+scroll键两次,让系统蓝屏,产生dump文件。
最后分析dump文件,果然是ssmf不能退出,如下图所示。
原因是在某种情况下没有打开FullfileName1,但是打开了FullfileName2,但是FileObject没有关闭,导致driver在unload的时候要等所有的run-down对象的引用计数都为0,但是针对FileObject2,没有调用
ObDereferenceObject(FileObject2);
则使系统调用ExfWaitForRundownProtectionRelease一直等待下去。