首页
论坛
课程
招聘
[原创]摘微过滤驱动回调的研究
2022-9-29 15:45 9499

[原创]摘微过滤驱动回调的研究

2022-9-29 15:45
9499

摘微过滤驱动回调的研究

常用命令

下面是通过fltmc进行文件过滤驱动加载的常用命令。

1
2
fltmc load DelProtect
fltmc unload DelProtect

问题

写过MiniFIlter驱动的都知道FltUnregisterFilter用于注销回调。

 

但是MSDN中有这样一段话:

 

A minifilter driver can only call FltUnregisterFilter to unregister itself, not another minifilter driver.

 

意思就是驱动应该自身去调用这个函数,而不是使用其他微过滤驱动去调用。

 

为此我写了一个驱动去实验,发现再调用后驱动就在调用FltUnregisterFilter后一去不复返了。

PCHunter

在对这个函数进行下断后,发现PCHunter在调用移除过滤器后确实会调用FltUnregisterFilter。

调试分析

上双机调试环境,把IDA拖入fltmgr,启动sync,Windbg 和 ret-sync联调。

1
2
3
.load F:\github\ret-sync\ext_windbg\sync\x64\Release\sync.dll
!sync
bp fltmgr!FltUnregisterFilter

先追踪一去不复返的原因。

 

 

经过调试发现ExWaitForRundownProtectionRelease 导致了函数的无限等待。

 

找到了这个原因,让我们看看MSDN,根据Remarks可知,需要通过调用ExReleaseRundownProtection 来释放保护,这个函数才能返回。

 

再次调试,看看这个对象的引用计数是怎样的。

 

 

在调用Remove之后,我们断在函数FltUnregisterFilter处:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1: kd> g
Breakpoint 0 hit
fltmgr!FltUnregisterFilter:
fffff880`011bd6a0 488bc4          mov     rax,rsp
1: kd> r
rax=0000000000000000 rbx=fffffa8062f7cd10 rcx=fffffa80629a8430
rdx=fffff88003071126 rsi=fffffa8062a2b4c2 rdi=fffff88003071224
rip=fffff880011bd6a0 rsp=fffff880030710a8 rbp=fffff88003071b60
 r8=fffff88003071226  r9=0000000000000000 r10=fffff880009f1b20
r11=fffffa8062a2b4ae r12=0000000000000000 r13=0000000000000001
r14=0000000000000001 r15=fffffa806298a060
iopl=0         nv up ei pl zr na po nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
fltmgr!FltUnregisterFilter:
fffff880`011bd6a0 488bc4          mov     rax,rsp

第一个参数即是_FLT_FILTER 的指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
1: kd> dt fltmgr!_FLT_FILTER @rcx
   +0x000 Base             : _FLT_OBJECT
   +0x020 Frame            : 0xfffffa80`617afac0 _FLTP_FRAME
   +0x028 Name             : _UNICODE_STRING "DelProtect"
   +0x038 DefaultAltitude  : _UNICODE_STRING "345101"
   +0x048 Flags            : 2 ( FLTFL_FILTERING_INITIATED )
   +0x050 DriverObject     : 0xfffffa80`6140aa50 _DRIVER_OBJECT
   +0x058 InstanceList     : _FLT_RESOURCE_LIST_HEAD
   +0x0d8 VerifierExtension : (null)
   +0x0e0 VerifiedFiltersLink : _LIST_ENTRY [ 0x00000000`00000000 - 0x00000000`00000000 ]
   +0x0f0 FilterUnload     : 0xfffff880`05076130     long  DelProtect!DelProtectUnload+0
   +0x0f8 InstanceSetup    : 0xfffff880`05076000     long  DelProtect!DelProtectInstanceSetup+0
   +0x100 InstanceQueryTeardown : 0xfffff880`050761a0     long  DelProtect!DelProtectInstanceQueryTeardown+0
   +0x108 InstanceTeardownStart : 0xfffff880`05076070     void  DelProtect!DelProtectInstanceTeardownStart+0
   +0x110 InstanceTeardownComplete : 0xfffff880`050760d0     void  DelProtect!DelProtectInstanceTeardownComplete+0
   +0x118 SupportedContextsListHead : (null)
   +0x120 SupportedContexts : [6] (null)
   +0x150 PreVolumeMount   : (null)
   +0x158 PostVolumeMount  : (null)
   +0x160 GenerateFileName : (null)
   +0x168 NormalizeNameComponent : (null)
   +0x170 NormalizeNameComponentEx : (null)
   +0x178 NormalizeContextCleanup : (null)
   +0x180 KtmNotification  : (null)
   +0x188 Operations       : 0xfffffa80`629a86c0 _FLT_OPERATION_REGISTRATION
   +0x190 OldDriverUnload  : (null)
   +0x198 ActiveOpens      : _FLT_MUTEX_LIST_HEAD
   +0x1e8 ConnectionList   : _FLT_MUTEX_LIST_HEAD
   +0x238 PortList         : _FLT_MUTEX_LIST_HEAD
   +0x288 PortLock         : _EX_PUSH_LOCK

接下来我们看看相关的计数

1
2
3
4
1: kd> ?? ((fltmgr!_FLT_FILTER*) (@rcx))->Base.RundownRef
struct _EX_RUNDOWN_REF
   +0x000 Count            : 0xc
   +0x000 Ptr              : 0x00000000`0000000c Void

可以看到再我们卸载时这个Count为0xC。

 

在调用ExWaitForRundownProtectionRelease 之前,我们再看一次计数

1
2
3
4
1: kd> ?? ((fltmgr!_FLT_FILTER*) (0xfffffa80629a8430))->Base.RundownRef
struct _EX_RUNDOWN_REF
   +0x000 Count            : 2
   +0x000 Ptr              : 0x00000000`00000002 Void

可以看到此时的计数是2。

 

那么我们接下来测试PCHunter。

 

 

再调用移除过滤器后我们也成功断在了入口处。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
1: kd> g
Breakpoint 0 hit
fltmgr!FltUnregisterFilter:
fffff880`011226a0 488bc4          mov     rax,rsp
0: kd> r
rax=fffff880011226a0 rbx=fffff80004773fe0 rcx=fffffa8061f83500
rdx=fffffa8061f83500 rsi=fffffa806110d040 rdi=fffffa8061f83500
rip=fffff880011226a0 rsp=fffff880060cebc8 rbp=0000000000000080
 r8=0000000000000000  r9=0000000000000000 r10=0000000000000001
r11=fffffa80643553dc r12=fffffa8061f83500 r13=fffff88006555ca0
r14=0000000000000000 r15=fffff80000b96080
iopl=0         nv up ei ng nz na po nc
cs=0010  ss=0018  ds=002b  es=002b  fs=0053  gs=002b             efl=00000286
fltmgr!FltUnregisterFilter:
fffff880`011226a0 488bc4          mov     rax,rsp

我们看一下引用计数,现在是0xa。

1
2
3
4
0: kd> ?? ((fltmgr!_FLT_FILTER*) (@rcx))->Base.RundownRef
struct _EX_RUNDOWN_REF
   +0x000 Count            : 0xa
   +0x000 Ptr              : 0x00000000`0000000a Void

放过去,运行到调用ExWaitForRundownProtectionRelease 之前,发现引用计数变为了0。

1
2
3
4
1: kd> ?? ((fltmgr!_FLT_FILTER*) (0xfffffa8061f83500))->Base.RundownRef
struct _EX_RUNDOWN_REF
   +0x000 Count            : 0
   +0x000 Ptr              : (null)

因此PCHunter肯定是调用了ExReleaseRundownProtection去释放运行时保护。

 

Let’s try it!

 

关键代码如下:

1
2
3
PEX_RUNDOWN_REF RunRefs = (PEX_RUNDOWN_REF)((char*)ppFltList[i] + offset);
ExReleaseRundownProtection(RunRefs);
FltUnregisterFilter(ppFltList[i]);

重新编译驱动,下断。

1
2
bp fltmgr!FltUnregisterFilter
bp fltmgr!FltUnregisterFilter+130

第一次断下记录rcx

1
2
3
4
5
6
7
0: kd> r
rax=0000000000000000 rbx=fffffa8062f29510 rcx=fffffa8062ed7890
rdx=000000000000000a rsi=fffffa8062bf1a62 rdi=fffff88006569224
rip=fffff880011ba6a0 rsp=fffff88006569098 rbp=fffff88006569b60
 r8=fffffa8062ed7898  r9=0000000000000000 r10=fffff8000460d820
r11=fffffa8062bf1a4e r12=0000000000000000 r13=0000000000000001
r14=0000000000000001 r15=fffffa8062a07060

第二次断下查看计数,Ok! 效果和PCHunter一样了。

1
2
3
4
1: kd> ?? ((fltmgr!_FLT_FILTER*) (0xfffffa8062ed7890))->Base.RundownRef
struct _EX_RUNDOWN_REF
   +0x000 Count            : 0
   +0x000 Ptr              : (null)

然后就成功移除掉了。

 


[2022冬季班]《安卓高级研修班(网课)》月薪两万班招生中~

收藏
点赞9
打赏
分享
最新回复 (8)
雪    币: 3
活跃值: 活跃值 (1721)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
咖啡_741298 活跃值 2022-9-29 19:49
2
0
感谢分享,学习了
雪    币: 10766
活跃值: 活跃值 (6330)
能力值: ( LV13,RANK:375 )
在线值:
发帖
回帖
粉丝
TkBinary 活跃值 5 2022-9-30 10:20
3
0
谢谢分享,学到了.
雪    币: 1148
活跃值: 活跃值 (710)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
曹操abc 活跃值 2022-9-30 11:56
4
0
什么情况下会出现这个现象 ?
雪    币: 3528
活跃值: 活跃值 (4365)
能力值: ( LV6,RANK:96 )
在线值:
发帖
回帖
粉丝
VirtualCC 活跃值 2022-9-30 12:15
5
0
曹操abc 什么情况下会出现这个现象 ?
_FLT_OBJECT对象引用计数不为0
雪    币: 1148
活跃值: 活跃值 (710)
能力值: ( LV3,RANK:20 )
在线值:
发帖
回帖
粉丝
曹操abc 活跃值 2022-9-30 14:03
6
0
VirtualCC _FLT_OBJECT对象引用计数不为0
可能我表达的不够清晰,正常情形下直接 FltUnregisterFilter 没碰到过这个现象,也是能正常卸载。在什么情形下会出现_FLT_OBJECT对象引用计数不为 0。 
雪    币: 3528
活跃值: 活跃值 (4365)
能力值: ( LV6,RANK:96 )
在线值:
发帖
回帖
粉丝
VirtualCC 活跃值 2022-9-30 15:21
7
0
情形有点多,建议你自己IDA 去交叉引用FltObjectReference函数。你卸载的时候并不能保证他引用计数刚好是0。
雪    币: 11381
活跃值: 活跃值 (8097)
能力值: ( LV12,RANK:312 )
在线值:
发帖
回帖
粉丝
一半人生 活跃值 5 2022-10-1 19:21
8
0
曹操abc 可能我表达的不够清晰,正常情形下直接 FltUnregisterFilter 没碰到过这个现象,也是能正常卸载。在什么情形下会出现_FLT_OBJECT对象引用计数不为 0。

FltUnregisterFilter本质是不能卸载其他驱动注册回调:

A minifilter driver can only call FltUnregisterFilter to unregister itself, not another minifilter driver.

引用清0是卸载回调的过程之一

最后于 2022-10-1 19:22 被一半人生编辑 ,原因:
雪    币: 76
活跃值: 活跃值 (913)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
saloyun 活跃值 2022-10-10 15:23
9
0
可以可以,大哥厉害
游客
登录 | 注册 方可回帖
返回