一:背景
1. 讲故事
前几天高级调试训练营里的一位学员找到我,说他们的程序句柄爆高,经过自己分析之后发现是几百万的 process 句柄,截图如下:

说实话,第一眼看到有这么多的 process 句柄还是挺震惊的,在我的400+dump分析之旅中还是从未见过,这也给了我很大的好奇心,接下来我们就来分析下到底是何方神圣导致的问题。
二:WinDbg 分析
1. process 句柄真的爆高吗
dump分析的一个重要原则就是相信数据而不是人言,即使是我的学员。。。所以我让学员用 procdump 给我抓一个 minidump,我要亲自用 !handle
洞察 process 句柄个数,参考命令如下:
C#
0:000> !handle
...
Handle 000000000000c398
Type Process
Handle 000000000000c39c
Type Process
Handle 000000000000c3a0
Type Process
Handle 000000000000c3a4
Type Process
Handle 000000000000c3a8
Type Process
Handle 000000000000c3ac
Type Process
Handle 000000000000c3b0
Type Process
Handle 000000000000c3b4
Type Process
Handle 000000000000c3b8
Type Process
Handle 000000000000c3bc
...
由于process句柄太多,没法全部刷出来,不过从满篇的Process
来看,确实是这样,接下来的问题是如何知道 process 句柄是谁创建的?
2. Process 句柄是谁创建的
哈哈,学员就是学员,精髓都学到了,知道这种问题应该用什么工具,对,就是 perfview,学员用 perfview 追踪了 3分钟多,有些人可能要问,这个时间是怎么看出来的,可以打开 TraceInfo
选项就知道了,截图如下:

有了 etl 文件之后,打开 Windows Handle Ref Count Stacks
选项卡,可以看到 3分多时间内 追踪到了 5756
个句柄,截图如下:

接下来就是双击 Handle Type Process
行,展开这 5756 个句柄详情,然后多次点击具体的句柄观察特征,结果发现大量的 process 的上游都挂了 halcon 的 ReadImage() 方法,截图如下:

从调用栈来看,ReadImage()
会涉及到文件IO,所以在内核层自然会和文件系统驱动 fltmgr.sys
打交道,但在调用栈的末端被一个 dcfafilter.sys
驱动给拦截了,从名字上来看不像是windows自带的,而且也正是它创建的 process 句柄,类似 OpenProcess 操作。
到这里我的疑心越来越重,让朋友到 C:\Windows\System32\drivers
目录中看下这个驱动是干什么的?是哪个程序引用着这个驱动。可以用类似的命令查看。
C#
sc queryex type= driver
sc qc DCFAFilter
经过朋友的一顿猛如虎的操作,终于给找到了,原来是 ManageEngine Unified Endpoint Security - Agent
服务,截图如下;

拿着这个信息到网上一搜,我去,还真是第三方的运维监控软件,截图如下:

到这里就真相大白了,然来是 ManageEngine 捣的鬼。。。无语了。。。朋友关闭了这个服务之后,句柄恢复了正常,截图如下;

三:总结
我见过太多的安全软件导致程序出现各种故障,但那些都是在用户态
层面进行的干扰,而这次生产故障是我第一次见到有安全软件在内核态
干扰应用程序,长见识啦!