📄 windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.htm
字号:
那么在 IRP_MJ_CLEANUP 的时候也需要对 FO_STREAM_FILE
类型的文件做同样处理。</P>
<P><IMG height=16
src="Windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.files/paragraph.gif"
width=14 align=absMiddle>
4、获得本地/远程访问用户名(域名/SID)</P>
<P>方法只有在 IRP_MJ_CREATE 中才可用,那是因为
IO_SECURITY_CONTEXT 只有在
IO_STACK_LOCATION->Parameters.Create.SecurityContext
才会有效。这样你才有可能从
IO_SECURITY_CONTEXT->SecurityContext->AccessState->SubjectSecurityContext.XXXToken
中获得访问 TOKEN,从而进一步得到用户名或 SID。记得 IFS 中有一个库,它的 LIB
导出一个函数可以让你在获得以上信息后得到用户名与域名。但如果你想兼容 NT4
的话,只能自己分析来得出本地和远程的 SID。</P>
<P><IMG height=16
src="Windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.files/paragraph.gif"
width=14 align=absMiddle> 5、文件与目录的判断</P>
<P>正确的方法在楚狂人的文档里已经说过了,再补充一句。如果你的文件过滤驱动要兼容所有文件系统,那么不要十分相信从
FileObject->FsContext 里取得的数据。正确的方法还是在你传递下去
IRP_MJ_CREATE 后从最下层文件系统延设备栈返回到你这里后再获得。</P>
<P><IMG height=16
src="Windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.files/paragraph.gif"
width=14 align=absMiddle> 6、加/解密中判断点</P>
<P>只判断
IRP_PAGING_IO,IRP_SYNCHRONOUS_PAGING_IO,IRP_NOCACHE
是没错的。如果有问题,相信是自己的问题。关于有人提到在
FILE_OBJECT->Flags中的
FO_NO_INTERMEDIATE_BUFFERING 是否需要判断,对此问题的回答是只要你判断了
IRP_NOCACHE 就不用再判断 FILE_OBJECT 中的,因为它最终会设置
IRP->Flags 为 IRP_NOCACHE。关于你看到的诸如
IRP_DEFER_IO_COMPLETION 等 IRP
不要去管它,因为它只是一个过程。最终读写还是如上所介绍。至于以上这些 IRP 哪个是由 CC MGR
发送的,哪些是由 I/O MGR
发送和在什么时候发送的,这个已经有很多讨论了,相信可以找到。</P>
<P><IMG height=16
src="Windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.files/paragraph.gif"
width=14 align=absMiddle> 7、举例说明关于 IRP
传递与完成注意事项</P>
<P>只看 Walter Oney 的那本 《Programming the Microsoft
Windows driver
model》里介绍的流程,自己没有实际的体会还是不够的,那里只介绍了基础概念,让自己有了知识。知道如何用,在什么情况下用,用哪种方法,能够用的稳定这叫有了技术。我们从另一个角度出发,把问题分为两段来看,这样利于总结。一个
IRP 在过滤驱动中,把它分为需要安装 CompleteRoutine 的与无需安装
CompleteRoutine 的。那么在不需要安装 CompleteRoutine
的有以下几类情况。</P>
<P>(1) 拿到这个 IRP 后什么都不做,直接调用 IoCompleteRequest()
来返回。<BR>(2) 拿到这个 IRP
后什么都不做,直接传递到底层设备,使用IoSkipCurrentIrpStackLocation()
后调用 IoCallDriver() 传递。<BR>(3) 使用
IoBuildSynchronousFsdRequest() 或
IoBuildDeviceIoControlRequest()来建立 IRP 的。</P>
<P>以上几种根据需要直接使用即可,除了一些参数与标志需要注意外,没有什么系统机制相关的东西需要注意了。那么再来看需要安装
CompleteRoutine 的情况。我们把这种情况再细分为两种,一是在
CompleteRoutine
中返回标志为STATUS_MORE_PROCESSING_REQUIRED
的情况。二是返回处这个外的标志,需要使用函数IoMarkIrpPending() 的情况。在
CompleteRoutine
中绝大多数就这么两种情况,你需要使用其中的一种情况。那么为什么需要安装
CompleteRoutine 呢?那是因为我们对其 IRP
从上层驱动,经过我们驱动,在经过底层设备栈返回到我们这一层驱动时需要得到其中内容作为参考依据的,还有对其中内容需要进行修改的。再有一种情况是没有经过上层驱动,而
IRP
的产生是在我们驱动直接下发到底层驱动,而经过设备栈后返回到我们这一层,且我们不在希望它继续向上返回的,因为这个
IRP 本身就不是从上层来的。综上所述,先来看下 IoMarkIrpPending()
的情况。<BR><BR>(1) 在 CompleteRoutine 中判断
Irp->PendingReturned 并使用
IoMarkIrpPending()然后返回。这种方法在没有使用 KeSetEvent()
的情况下,且不是自建 IRP 发送到底层驱动返回时使用。也就是说有可能我所做的工作都是在
CompleteRoutine
中进行的。比如加/解密时,我在这里对下层驱动返回数据的判断并修改。修改后因为没有使用
STATUS_MORE_PROCESSING_REQUIRED
标志,它会延设备堆一直向上返回并到用户得到数据为止。这里一定要注意,在这种情况下
CompleteRoutine返回后,不要在碰这个 IRP。也就是说如果这个时候你使用了
IoCompleteRequest()的话会出现一个
MULTIPLE_IRP_COMPLIETE_REQUEST 的 BSOD 错误。<BR></P>
<P>(2) 在 CompleteRoutine 中直接返回
STATUS_MORE_PROCESSING_REQUIRED 标志。这种情况在使用了
KeSetEvent() 的函数下出现。这里又有两个小小的分之。</P>
<P>1) 出现于上层发送到我这里,当我这里使用 IoCallDriver()
后,底层返回数据经过我这一层时,我想让它暂时停止继续向上传递,让这个 IRP
稍微歇息一会,等我对这个 IRP 返回的数据操作完成后(一般是没有在
CompleteRoutine中对返回数据进行操作情况下,也就是说等到完成例程返回后再进行操作),由我来调用
IoCompleteRequest()
让它延着设备栈继续返回。这里要注意,我们是想让它返回的,所以调用了
IoCompleteRequest()。这个可不同于下面所讲的自己从头分配 IRP 时在
CompleteRoutine 中已经调用 IoFreeIrp() 释放了当前IRP
的情况。比如我在做一个改变文件大小,向文件头写入加密标志的驱动时,在上层发来了
IRP_MJ_QUERY_INFORMATION
查询文件,我想在这个时候获得文件信息进行判断,然后根据我的判断结果再移动文件指针。注意:上面是两步,第一步是先获得文件大小,那么在这个时候我就需要用到上述办法,先让这个
IRP传递下去,得到我想要的东西后在进行对比。等待适当时机完成这个
IRP,让数据继续传递,直到用户收到为止。第二步我会结合下面小节来讲。</P>
<P>2) 出现于自己从头建立 IRP,当使用 IoAllocate() 或
IoBuildAsynchronousFsdRequest()创建 IRP 调用
IoCallDriver() 后,底层返回数据到我这一层时,我不想让这个 IRP
继续向上延设备栈传递。因为这个 IRP 就是在我这层次建立的,上层本就不知道有这么一个
IRP。那么到这里我就要在 CompleteRoutine 中使用
IoFreeIrp()来释放掉这个 IRP,并不让它继续传递。这里一定要注意,在
CompleteRoutine函数返回后,这个 IRP 已经释放了,如果这个时候在有任何关于这个
IRP 的操作那么后果是灾难性的,必定导致 BSOD 错误。前面 1)
小节给出的例子只完成了第一步这里继续讲第二步,第一步我重用这个 IRP
得到了文件大小,那么这个时候虽然知道大小,但我还是无法知道这个文件是否被我加过密。这时,我就需要在这里自己从头建立一个
IRP_MJ_READ 的 IRP
来读取文件来判断是否我加密过了的文件,如果是,则要减少相应的大小,然后继续返回。注意:这里的返回是指让第一步的IRP
返回。而不是我们自己创建的。我们创建的都已经在CompleteRoutine 中销毁了。</P>
<P><IMG height=16
src="Windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.files/paragraph.gif"
width=14 align=absMiddle> 8、关于完成 IRP 的动作简介</P>
<P>当一个底层驱动调用了 IoCompleteRequest() 函数时,基本上所有设备栈相关
IRP 处理工作都是在它那里完成的。包括 IRP->Flags 的一些标志的判断,对 APC
的处理,抛出MULTIPLE_IRP_COMPLETE_REQUESTS
错误等。当它延设备栈一直调用驱动所安装的 CompleteRoutine时,如果发现
STATUS_MORE_PROCESSING_REQUIRED
这个标志,则会停止向上继续回滚。这也是为什么在 CompleteRoutine
中使用这个标志即可暂停 IRP 的原因。</P>
<P><IMG height=16
src="Windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.files/paragraph.gif"
width=14 align=absMiddle> 9、关于 ObQueryNameString
的使用</P>
<P>这个函数的使用,在有些环境下会有问题。它的上层函数是
ZwQueryObject()。在某些情况下会导致系统挂起,或者直接 BSOD。它是从
对象管理器中的 ObpRootDirectoryObject开始遍历,通过
OBJECT_HEADER_TO_NAME_INFO 获得对象名称。今天问了下
PolyMeta好象是在处理 PIPE 时会挂启,这个问题出现在 2000 系统。在 XP
上好象补丁了。 </P>
<P><IMG height=16
src="Windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.files/paragraph.gif"
width=14 align=absMiddle> 10、关于重入问题</P>
<P>其实这个问题在很久前的 IFS FAQ
里已经介绍的很清楚,包括处理方法以及每种方法可能带来的问题。IFS FAQ 里的 Q34
一共介绍了四种方法,包括自己从头建立 IRP发送,使用
ShadowDevice,使用特征字符串,根据线程 ID,在 XP
下使用IoCreateFileSpecifyDeviceObjectHint()
函数。并且把以上几种在不同环境下使用要处理的问题也做了简单的介绍。且在 Q33 里介绍了在 CIFS
碰到的 FILE_COMPLETE_IF_OPLOCKED
问题的解决方法。<BR><BR><BR>(全文完)
</P></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-15,修改于: 2008-12-15
23:12 已浏览205次,有评论0条</FONT> <A id=star title=推荐这篇文章
onclick="NewWindows(this.href);return false;"
href="http://blog.chinaunix.net/u2/star.php?blogid=21790&artid=1722296">推荐</A>
<A id=complaint title=投诉这篇文章
onclick="NewWindows(this.href);return false;"
href="http://blog.chinaunix.net/u2/complaint.php?blogid=21790&artid=1722296">投诉</A>
</TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE></TD></TR></TBODY></TABLE><BR>
<TABLE style="BORDER-COLLAPSE: collapse" borderColor=#bbf0ff cellSpacing=0
cellPadding=0 width="100%" align=center border=1>
<TBODY>
<TR>
<TD
background="Windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.files/bg_line.gif"
height=28> <B>网友评论</B></TD></TR>
<TR>
<TD align=middle>
<TABLE style="COLOR: #0066cc; BORDER-COLLAPSE: collapse"
cellSpacing=0 cellPadding=0 width="100%" border=0>
<TBODY></TBODY></TABLE></TD></TR></TBODY></TABLE><BR>
<TABLE style="BORDER-COLLAPSE: collapse" borderColor=#bbf0ff cellSpacing=0
cellPadding=0 width="100%" align=center border=1>
<TBODY>
<TR>
<TD
background="Windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.files/bg_line.gif"
height=28> <B>发表评论</B></TD></TR>
<TR>
<TD bgColor=#ffffff height=1></TD></TR>
<TR>
<TD align=middle bgColor=#ffffff><IFRAME name=comment
src="Windows 文件过滤驱动经验总结 - 驱动开发 - 私のウェブサイト.files/comment.htm"
frameBorder=0 width=600
height=160></IFRAME></TD></TR></TBODY></TABLE><BR><BR></TD>
<TD width=10></TD></TR></TBODY></TABLE>
<TABLE style="BORDER-COLLAPSE: collapse" cellSpacing=0 cellPadding=0 width=950
align=center border=0>
<TBODY>
<TR>
<TD height=50></TD></TR>
<TR>
<TD align=middle><BR>
<P>Copyright © 2001-2006 ChinaUnix.net All Rights Reserved<BR>
<P>感谢所有关心和支持过ChinaUnix的朋友们 <BR>页面生成时间:0.31967
<P><A href="http://www.miibeian.gov.cn/" target=_blank>京ICP证041476号</A>
</P></TD></TR></TBODY></TABLE></CENTER></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -