📄 filemon学习笔记 --- windows文件过滤系统驱动开发 - 驱动开发 - 私のウェブサイト.htm
字号:
<DIV> 中针对不同的MajorFunction,打印出相关操作信息。</DIV>
<DIV> 因此函数体太长 不再全部列出。</DIV>
<DIV> 其函数体总体框架为:得到被操作的文件名字,打印相关操作信息,然后下发IRP到底层驱动。</DIV>
<DIV> 在下发IRP到底层驱动处理前,本层驱动必须负责设置下层IO堆栈的内容。这样下一层驱动调用IoGetCurrentIrpStackLocation()时能得到相应的数据。</DIV>
<DIV> 设置下层IO堆栈的内容,一般用两个函数来实现:</DIV>
<DIV> IoCopyCurrentIrpStackLocationToNext( Irp
)</DIV>
<DIV> 此函数一般用在本驱动设置了完成例程时调用,把本层IO _STACK_LOCATION
中的参数copy到下层,但与完成例程相关的参数信息例外。因为本驱动设置的完成例程只对本层驱动有效。</DIV>
<DIV> IoSkipCurrentIrpStackLocationToNext(Irp)</DIV>
<DIV> 此函数的作用是:直接把本层驱动IO堆栈的内容设置为下层驱动IO堆栈指针的指向。因两层驱动IO堆栈的内容完全一致,省却copy过程。</DIV>
<DIV> 而在Filemon的处理中,它用了一个特别的办法,没有调用此两个函数,FilemonHookRoutine函数体里面有三句代码:</DIV>
<DIV>PIO_STACK_LOCATION currentIrpStack =
IoGetCurrentIrpStackLocation(Irp);<BR>PIO_STACK_LOCATION nextIrpStack =
IoGetNextIrpStackLocation(Irp);<BR>*nextIrpStack =
*currentIrpStack;//此步设置了下层驱动的IO_STACK_LOCATION<BR>直接设置了下层驱动IO堆栈的值。在FilemonHookRoutine函数里,用一个宏实现了复杂的获得拦截到的被操作文件的名字:if(
FilterOn && hookExt->Hooked )
{<BR> GETPATHNAME( createPath
);<BR>}GETPATHNAME( createPath )宏展开为:#define
GETPATHNAME(_IsCreate) <BR> fullPathName
= ExAllocateFromNPagedLookasideList(
&FullPathLookaside );<BR> if( fullPathName
)
{ <BR> FilemonGetFullPath(
_IsCreate, FileObject, hookExt, fullPathName
);<BR> } else
{ <BR> fullPathName
=
InsufficientResources; <BR> } 在函数:FilemonGetFullPath(
_IsCreate, FileObject, hookExt, fullPathName
)中实现了获得被操作的文件名字,此函数代码较多,判断条件复杂,理解起来比较麻烦,下面重点讲解。</DIV>
<DIV> 对函数FilemonGetFullPath的理解关键在于理顺结构,</DIV>
<DIV> 此函数的功能就是获得文件名字,获得文件名字一般在三种状态下:</DIV>
<DIV> 一:在打开文件请求中,但在打开文件前。</DIV>
<DIV> 二:在打开文件请求中,但在打开文件后,通过在本层驱动中设置完成例程。在完成例程中获得。</DIV>
<DIV> 三:在过滤到读写等操作时。</DIV>
<DIV> 而在此函数中,它包含了第一种和第三种方法,通过一些烦琐的条件判断,先判断出目前是处于什么状态中,然后根据不同状态采取不同方法。</DIV>
<DIV> 先分析当在第一种条件下,此函数的处理方法,可以精炼为如下:VOID<BR>FilemonGetFullPath(<BR> BOOLEAN
createPath,<BR> PFILE_OBJECT
fileObject,<BR> PHOOK_EXTENSION
hookExt,<BR> PCHAR
fullPathName<BR> )<BR>{<BR> ULONG
pathLen, prefixLen, slashes;<BR> PCHAR
pathOffset, ptr;<BR> BOOLEAN
gotPath;<BR> PFILE_OBJECT relatedFileObject;<BR> <BR> ANSI_STRING
fileName;<BR> ANSI_STRING
relatedName;<BR> <BR> UNICODE_STRING fullUniName;<BR> <BR> prefixLen
= 2; // "C:"<BR> if( !fileObject )
{<BR> sprintf( fullPathName, "%C:",
hookExt->LogicalDrive
);<BR> return;<BR> }<BR> <BR> //<BR> //
Initialize variables<BR> //<BR> fileName.Buffer
= NULL;<BR> relatedName.Buffer =
NULL;<BR> gotPath = FALSE;<BR> if(
!fileObject->FileName.Buffer)<BR> {<BR> sprintf(
fullPathName, "%C:",
hookExt->LogicalDrive);<BR> return;<BR> }else<BR> DbgPrint("fileOjec->FileName:%s",fileObject->FileName);<BR>
if( !NT_SUCCESS( RtlUnicodeStringToAnsiString(
&fileName, &fileObject->FileName, TRUE
))) {<BR> sprintf( fullPathName, "%C: <Out
of Memory>", hookExt->LogicalDrive
);<BR> return;<BR> }<BR> <BR> pathLen
= fileName.Length +
prefixLen;<BR> relatedFileObject =
fileObject->RelatedFileObject;<BR> //<BR> //
Only look at related file object if this is a
relative name<BR> //<BR> if(
fileObject->FileName.Buffer[0] != L''
&&<BR> relatedFileObject &&
relatedFileObject->FileName.Length )
{<BR> DbgPrint("relatedFileObject filename :
%s",relatedFileObject->FileName);<BR> <BR> if(
!NT_SUCCESS( RtlUnicodeStringToAnsiString(
&relatedName,
&relatedFileObject->FileName, TRUE )))
{<BR> <BR> sprintf( fullPathName,
"%C: <Out of Memory>",
hookExt->LogicalDrive
);<BR> RtlFreeAnsiString( &fileName
);<BR> return;<BR> }<BR> pathLen
+= relatedName.Length+1;<BR> }<BR> if(
fileObject->DeviceObject->DeviceType !=
FILE_DEVICE_NETWORK_FILE_SYSTEM )
{<BR> sprintf( fullPathName, "%C:",
hookExt->LogicalDrive );<BR> }<BR> if(
pathLen >= MAXPATHLEN )
{<BR> <BR> strcat( fullPathName, "
<Name Too Long>" );<BR> } else
{<BR> <BR> //<BR> // Now we can build
the path name<BR> //<BR> fullPathName[
pathLen ] = 0;<BR> <BR> pathOffset =
fullPathName + pathLen -
fileName.Length;<BR> memcpy( pathOffset,
fileName.Buffer, fileName.Length + 1
);<BR> <BR> if(
fileObject->FileName.Buffer[0] != L''
&&<BR> relatedFileObject &&
relatedFileObject->FileName.Length )
{<BR> //<BR> // Copy the component,
adding a slash
separator<BR> //<BR> *(pathOffset -
1) = '';<BR> pathOffset -=
relatedName.Length +
1;<BR> <BR> memcpy( pathOffset,
relatedName.Buffer, relatedName.Length
);<BR> //<BR> // If we've got to
slashes at the front zap
one<BR> //<BR> if( pathLen > 3
&& fullPathName[2] == '' &&
fullPathName[3] == ''
) {<BR> <BR> strcpy(
fullPathName + 2, fullPathName + 3
);<BR> }<BR> }<BR> } <BR>} 上面的精简后的函数代码为只考虑目前处于第一种情况,即打开文件请求中,但文件尚未打开时。</DIV>
<DIV> 在此时,文件的名字信息存储在文件对象fileObject->FileName,与
fileObject->RelatedFileObject->FileName,
FileObject->FileName 是RelatedObject
的相对路径,通过对两者的解析组合出文件名字。</DIV>
<DIV> 而在FilemonGetFullPath
函数体中的另一段代码:FilemonGetFullPath<BR>{<BR>…………………..<BR>…………………..<BR>…………………..<BR>if(
!gotPath && !createPath )
{<BR> <BR> fileNameInfo =
(PFILE_NAME_INFORMATION) ExAllocatePool(
NonPagedPool,<BR> MAXPATHLEN*sizeof(WCHAR)
);<BR> if( fileNameInfo
&&<BR> FilemonQueryFile(hookExt->FileSystem,
fileObject, FileNameInformation,<BR>
fileNameInfo, (MAXPATHLEN - prefixLen -
1)*sizeof(WCHAR) )) {<BR> fullUniName.Length
= (SHORT)
fileNameInfo->FileNameLength;<BR> fullUniName.Buffer
= fileNameInfo->FileName;<BR> if(
NT_SUCCESS( RtlUnicodeStringToAnsiString(
&fileName, &fullUniName, TRUE )))
{<BR> fullPathName[ fileName.Length +
prefixLen ] = 0;<BR> if( hookExt->Type
== NPFS ) {<BR> <BR> strcpy(
fullPathName, NAMED_PIPE_PREFIX );<BR> }
else if( hookExt->Type == MSFS )
{<BR> strcpy( fullPathName,
MAIL_SLOT_PREFIX );<BR> } else if(
fileObject->DeviceObject->DeviceType !=
FILE_DEVICE_NETWORK_FILE_SYSTEM )
{<BR> sprintf( fullPathName, "%C:",
hookExt->LogicalDrive );<BR> } else
{<BR> <BR> //<BR> // No
prefix for network
devices<BR> //<BR> }<BR> memcpy(
&fullPathName[prefixLen], fileName.Buffer,
fileName.Length );<BR> gotPath =
TRUE;<BR> RtlFreeAnsiString( &fileName
);<BR> fileName.Buffer =
NULL;<BR> }<BR> }<BR> if( fileNameInfo
) ExFreePool( fileNameInfo
);<BR>}<BR>…………………<BR>…………………<BR>…………………<BR>}</DIV>
<DIV> 上面这段代码是处理另外一种情况,即是在其他读写请求中,自己根据拦截到的fileObject构建IRP,下发到底层,以此来查询文件名信息。整个过程还是易于理解的。</DIV>
<DIV> 在理清这两种脉络后,再剖析此整个函数,就很容易理解整个函数代码了。</DIV>
<DIV> 代码中对 MajorFunction ==
IRP_MJ_CREATE_NAMED_PIPE</DIV>
<DIV> MajorFunction == IRP_MJ_CREATE_MAILSLOT
的判断是为了辨别对拦截到的进程间的两种通信方式:命名管道与邮槽的处理。</DIV>
<DIV> 周末来了,祝大家周末愉快。余下的整理后再帖,希望和大家多交流。</DIV>
<DIV> 连城碧 QQ 276265852 MSN:<A
href="mailto:haochao0000@hotmail.com">haochao0000@hotmail.com</A></DIV>
<DIV></DIV></DIV></TD></TR></TBODY></TABLE>
<P style="MARGIN: 5px; LINE-HEIGHT: 150%"></P></TD></TR>
<TR>
<TD height=25><FONT color=#000066> 发表于:
2008-12-06,修改于: 2008-12-06
11:45 已浏览165次,有评论0条</FONT> <A id=star title=推荐这篇文章
onclick="NewWindows(this.href);return false;"
href="http://blog.chinaunix.net/u2/star.php?blogid=21790&artid=1682616">推荐</A>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -