本文为看雪论坛优秀文章
看雪论坛作者ID:VirtualCC
一
常用命令
下面是通过fltmc进行文件过滤驱动加载的常用命令。
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联调。
.load F:\github\ret-sync\ext_windbg\sync\x64\Release\sync.dll
!sync
bp fltmgr!FltUnregisterFilter
先追踪一去不复返的原因。
经过调试发现ExWaitForRundownProtectionRelease 导致了函数的无限等待。
找到了这个原因,让我们看看MSDN,根据Remarks可知,需要通过调用ExReleaseRundownProtection(https://learn.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-exreleaserundownprotection) 来释放保护,这个函数才能返回。
再次调试,看看这个对象的引用计数是怎样的。
在调用Remove之后,我们断在函数FltUnregisterFilter处:
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: 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: kd> ?? ((fltmgr!_FLT_FILTER*) (@rcx))->Base.RundownRef
struct _EX_RUNDOWN_REF
+0x000 Count : 0xc
+0x000 Ptr : 0x00000000`0000000c Void
可以看到再我们卸载时这个Count为0xC。
在调用ExWaitForRundownProtectionRelease 之前,我们再看一次计数。
1: kd> ?? ((fltmgr!_FLT_FILTER*) (0xfffffa80629a8430))->Base.RundownRef
struct _EX_RUNDOWN_REF
+0x000 Count : 2
+0x000 Ptr : 0x00000000`00000002 Void
可以看到此时的计数是2。
那么我们接下来测试PCHunter。
再调用移除过滤器后我们也成功断在了入口处。
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。
0: kd> ?? ((fltmgr!_FLT_FILTER*) (@rcx))->Base.RundownRef
struct _EX_RUNDOWN_REF
+0x000 Count : 0xa
+0x000 Ptr : 0x00000000`0000000a Void
放过去,运行到调用ExWaitForRundownProtectionRelease 之前,发现引用计数变为了0。
1: kd> ?? ((fltmgr!_FLT_FILTER*) (0xfffffa8061f83500))->Base.RundownRef
struct _EX_RUNDOWN_REF
+0x000 Count : 0
+0x000 Ptr : (null)
因此PCHunter肯定是调用了ExReleaseRundownProtection去释放运行时保护。
Let’s try it!
关键代码如下:
PEX_RUNDOWN_REF RunRefs = (PEX_RUNDOWN_REF)((char*)ppFltList[i] + offset);
ExReleaseRundownProtection(RunRefs);
FltUnregisterFilter(ppFltList[i]);
重新编译驱动,下断。
bp fltmgr!FltUnregisterFilter
bp fltmgr!FltUnregisterFilter+130
第一次断下记录rcx。
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: kd> ?? ((fltmgr!_FLT_FILTER*) (0xfffffa8062ed7890))->Base.RundownRef
struct _EX_RUNDOWN_REF
+0x000 Count : 0
+0x000 Ptr : (null)
然后就成功移除掉了。
看雪ID:VirtualCC
https://bbs.pediy.com/user-home-770117.htm
2.5折门票限时抢购
峰会官网:https://meet.kanxue.com/kxmeet-6.htm
# 往期推荐
1.进程 Dump & PE unpacking & IAT 修复 - Windows 篇
2.NtSocket的稳定实现,Client与Server的简单封装,以及SocketAsyncSelect的一种APC实现
3.如何保护自己的代码?给自己的代码添加NoChange属性
球分享
球点赞
球在看
点击“阅读原文”,了解更多!