BAV扫描lnk文件出现卡壳分析过程的分享
一.发现问题
这2天接到反馈:BAV在严格模式下,使用explorer资源管理器操作lnk文件(快捷方式)时,出现explorer界面无法响应的问题。大概过了8秒左右才有响应,查看日志,界面恢复响应的前后时间和日志中显示引擎扫描开始和结束
的时间一致,初步可以确认是由于BAV拦截explorer操作lnk文件时进行扫描导致explorer无响应,下面还有另一个方法进一步验证了这个想法
二.调试
既然知道是bav扫描文件时出现卡壳了,那就分析下扫描文件的线程栈,看下是卡在哪个函数上,这里说下怎么找哪个线程,在我们这个情况下,由于我们的扫描引擎是用一个线程池的机制,所以线程ID基本就是那几个,在出现引擎卡壳的时候,可以一个一个的试。但如果完全不知道的话,只能用笨方法了,简单的就是用内核调试,在卡壳的时候切到引擎的进程,输入!process -1 7,可以显示所有的当前进程的线程详情,然后就慢慢一个一个的看了。
OK,到这里,假设我们已经找到了是哪个线程了,如下,

(图1)
可以看见原来是在打开扫描文件时就卡了,发现是由于waitfor一个对象。
另外补充一下,就是这里也要找出explorer无响应时是卡在哪里,可以进一步确认是由于BAV引擎导致explorer卡壳。这个方法也是像上面那样用双机调试!process -1 7查找可疑线程

(图2)
证据确凿,确实是扫描引擎卡壳引起的了。
对了,这里另外也说个技巧,上面说的是windbg双机查看栈,要是手头不方便,也可以使用sysinternal的工具procexp.exe来查看,由于它也加了驱动,所以是可以查看内核栈的,不过用它看的缺点是在你不知道是哪个栈的时候,不能像windbg那样全列出来,而只能一个一个的点着看。
好,科普完成,继续调试问题,在调试过程中我发现NtfsWaitForCreateEvent这个最终有返回,说明它成功等待成功了,在MS中,所有的dispatch对象头都有一个共同的头
kd> dt nt!_DISPATCHER_HEADER
+0x000 Type : UChar
+0x001 TimerControlFlags : UChar
+0x001 Absolute : Pos 0, 1 Bit
+0x001 Coalescable : Pos 1, 1 Bit
+0x001 KeepShifting : Pos 2, 1 Bit
+0x001 EncodedTolerableDelay : Pos 3, 5 Bits
+0x001 Abandoned : UChar
+0x001 Signalling : UChar
+0x002 ThreadControlFlags : UChar
+0x002 CpuThrottled : Pos 0, 1 Bit
+0x002 CycleProfiling : Pos 1, 1 Bit
+0x002 CounterProfiling : Pos 2, 1 Bit
+0x002 Reserved : Pos 3, 5 Bits
+0x002 Hand : UChar
+0x002 Size : UChar
+0x003 TimerMiscFlags : UChar
+0x003 Index : Pos 0, 1 Bit
+0x003 Processor : Pos 1, 5 Bits
+0x003 Inserted : Pos 6, 1 Bit
+0x003 Expired : Pos 7, 1 Bit
+0x003 DebugActive : UChar
+0x003 ActiveDR7 : Pos 0, 1 Bit
+0x003 Instrumented : Pos 1, 1 Bit
+0x003 Reserved2 : Pos 2, 4 Bits
+0x003 UmsScheduled : Pos 6, 1 Bit
+0x003 UmsPrimary : Pos 7, 1 Bit
+0x003 DpcActive : UChar
+0x000 Lock : Int4B
+0x004 SignalState : Int4B
+0x008 WaitListHead : _LIST_ENTRY
其中的SignalState字段很那啥,对于常见的内核对象,基本有对这个字段的操作,如event在reset的话,会对这个字段写入,根据这特点,我们可以下一个内核写入的断点,
的系统跑起来后,系统断点下来,栈如下:

(图3)
发现栈中有一个函数RequestOplock,同时在图2中也有,查询MS相关资料,这是MS的一个oplock机制,总结下来就是在打开的时候(图2)如果用Oplcock的方式打开,那么其它人只能在它释放(图3)这个openlock后才能打开
根据MS说明,打开文件时要想使用oplock机制,需要在create option中指明FILE_OPEN_REQUIRING_OPLOCK标志,回头验证图2中打开标志,确实存在这个标志。
另外说下为什么最终explorer等待8秒后恢复响应,那是因为bav的扫描引擎中,有一个超时机制,超过8秒如果没结果,就直接返回了。
三.解决问题
目前此问题只在BAV的严格模式下,同时是explorer操作时lnk类型文件时才出现。
所以目前解决方案我推荐的是,在严格模式下如果发现是oplock的方式打开lnk文件时,直接放过即可。由于这个扫描是在post create行为中发生的,虽然放过了,但在clean up行为即closehandle后,还会进行扫描的,这时候就不会发生deadlock了,closehandle后的话,就不会有oplock了。
完
补充下上面的分析过程,这里"deadlock"的原因如下面MSDN据说是因为使用FILE_OPEN_REQUIRING_OPLOCK这个标志。
http://msdn.microsoft.com/en-us/library/windows/hardware/ff566424(v=vs.85).aspx
An application that uses the FILE_OPEN_REQUIRING_OPLOCK flag must request an oplock after this call succeeds, or all subsequent attempts to open the file will be blocked without the benefit of normal oplock processing. Similarly, if this call succeeds but the subsequent oplock request fails, an application that uses this flag must close its handle after it detects that the oplock request has failed.

浙公网安备 33010602011771号