摘微过滤驱动回调的研究-续
问题
自上回发现对象引用计数后,再次在Win10上进行测试,发现大概率又卡死在ExWaitForRundownProtectionRelease函数。因为只有引用计数在调用这个函数之前不为0,就会进入等待。那么PCHunter是怎么处理引用计数的呢?Why not reverse it?
逆向PCHunter驱动
首先我们通过WinArk设置一个镜像回调拦截驱动加载。这里感谢砍酱的提醒,如果PCHunter已经启动过了,那么pchunter关闭的时候不会卸载驱动。所以需要手动卸载后再拦截。
拦截到驱动后
拖入IDA,上ret-sync。
1
2
3
|
.load F:\github\ret
-
sync\ext_windbg\sync\x64\Release\sync.dll
!sync
bp fltmgr!FltUnregisterFilter
|
我们使用一个DelProtect.sys,作为测试驱动,然后依旧选择移除过滤器,函数断下
1
2
3
4
|
0
: kd> g
Breakpoint
0
hit
FLTMGR!FltUnregisterFilter:
fffff804`
73eed6b0
48895c2418
mov qword ptr [rsp
+
18h
],rbx
|
此时我们通过下面的指令查看当前线程函数入口
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
0
: kd> !thread @$thread
THREAD ffffcf8f7fc74080 Cid
0004.03c4
Teb:
0000000000000000
Win32Thread:
0000000000000000
RUNNING on processor
0
Not impersonating
DeviceMap ffffa88a30e14c00
Owning Process ffffcf8f7bc8d300 Image: System
Attached Process N
/
A Image: N
/
A
Wait Start TickCount
0
Ticks:
76618
(
0
:
00
:
19
:
57.156
)
Context Switch Count
1
IdealProcessor:
1
UserTime
00
:
00
:
00.000
KernelTime
00
:
00
:
00.000
Win32 Start Address PCHunter64as (
0xfffff80477666a18
)
Stack Init ffffbb8c5239dc90 Current ffffbb8c5239dc20
Base ffffbb8c5239e000 Limit ffffbb8c52398000 Call
0000000000000000
Priority
8
BasePriority
8
PriorityDecrement
0
IoPriority
2
PagePriority
5
Child
-
SP RetAddr : Args to Child : Call Site
ffffbb8c`
5239dbd8
fffff804`
77666a4b
:
00000000
`
00000000
ffffcf8f`
7bc8d300
ffffcf8f`
7eb43180
00000000
`
00000192
: FLTMGR!FltUnregisterFilter
ffffbb8c`
5239dbe0
fffff804`
711c3d65
: ffffcf8f`
7fc74080
fffff804`
77666a18
ffffcf8f`
805a4bc0
00000000
`
00000001
: PCHunter64as
+
0x16a4b
ffffbb8c`
5239dc10
fffff804`
71268a8c
: fffff804`
6f89b180
ffffcf8f`
7fc74080
fffff804`
711c3d10
ffffcf8f`
7cd85870
: nt!PspSystemThreadStartup
+
0x55
ffffbb8c`
5239dc60
00000000
`
00000000
: ffffbb8c`
5239e000
ffffbb8c`
52398000
00000000
`
00000000
00000000
`
00000000
: nt!KiStartSystemThread
+
0x1c
|
可以看到函数地址为0xfffff80477666a18
在IDA中转到
通过交叉引用,可知此为r0接口处理处
再往上走就是其他一堆功能函数了
继续分析,我们对这个功能函数下断,从头跟踪一次,因为FltUnregisterFilter
已经走到很后面了。
我们使用命令查看返回地址之前的反汇编
1
2
3
4
5
6
7
8
9
10
|
0
: kd> ub PCHunter64as
+
0x16a4b
PCHunter64as
+
0x16a34
:
fffff804`
77666a34
488bd8
mov rbx,rax
fffff804`
77666a37
e89cf60000 call PCHunter64as
+
0x260d8
(fffff804`
776760d8
)
fffff804`
77666a3c
4885ff
test rdi,rdi
fffff804`
77666a3f
740a
je PCHunter64as
+
0x16a4b
(fffff804`
77666a4b
)
fffff804`
77666a41
4885c0
test rax,rax
fffff804`
77666a44
7405
je PCHunter64as
+
0x16a4b
(fffff804`
77666a4b
)
fffff804`
77666a46
488bcf
mov rcx,rdi
fffff804`
77666a49
ffd0 call rax
|
由此rax指向的函数就是FltUnregisterFilter
,线程函数的context传入的是PFLT_FILTER
。
继续分析这里面还有一个rbx指向的函数指针。
1
2
3
4
5
6
7
8
9
10
|
0
: kd> u rbx
nt!PsTerminateSystemThread:
fffff804`
7173cca0
4883ec28
sub rsp,
28h
fffff804`
7173cca4
8bd1
mov edx,ecx
fffff804`
7173cca6
65488b0c2588010000
mov rcx,qword ptr gs:[
188h
]
fffff804`
7173ccaf
f7417400040000 test dword ptr [rcx
+
74h
],
400h
fffff804`
7173ccb6
0f84bc651200
je nt!PsTerminateSystemThread
+
0x1265d8
(fffff804`
71863278
)
fffff804`
7173ccbc
41b001
mov r8b,
1
fffff804`
7173ccbf
e88cfa0000 call nt!PspTerminateThreadByPointer (fffff804`
7174c750
)
fffff804`
7173ccc4
4883c428
add rsp,
28h
|
综上这个线程函数分析完毕,姚老师不是在线程函数里完成_FLT_OBJECT的对象引用计数递减的。
继续进行函数调用上层分析,根据内核编程基础,可直接推测在创建线程后,对_ETHREAD增加引用计数,然后进行等待,等待完成后解引用对象,最后关闭线程句柄。
由此分析完毕,这个函数也不是我们想找的。
继续往上分析,也无大发现。
静态分析无果,Windbg动态调试。
我们跟踪一下哪里调用进来的这个函数。下断返回地址。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
0
: kd> bp FFFFF804776669FF
0
: kd> g
Breakpoint
1
hit
PCHunter64as
+
0x169ff
:
fffff804`
776669ff
ff15b3360600 call qword ptr [PCHunter64as
+
0x7a0b8
(fffff804`
776ca0b8
)]
0
: kd> !sync
[sync] No argument found, using default host (
127.0
.
0.1
:
9100
)
[sync] sync success, sock
0x638
[sync] probing sync
[sync] sync
is
now enabled with host
127.0
.
0.1
[sync] recv: connection closed
[sync] sync
is
off
0
: kd> !sync
[sync] No argument found, using default host (
127.0
.
0.1
:
9100
)
[sync] sync success, sock
0x638
[sync] probing sync
[sync] sync
is
now enabled with host
127.0
.
0.1
|
然后就断下来了。
F10 一步步单步返回。
调试过程中出现了一些异常,为了避免跑飞啥的,下个ret处的断点。
最后我们回溯到了DriverObject的0xE函数里。
总感觉真的少了点什么步骤,因此我们在这里下个断点,放过去,然后加载卸载其他文件过滤驱动。从头来一次。
再次选中卸载一个微软驱动的微过滤器,后我们断在了DispatchHandler里。
一步步的调试,并为IDA添加注释。
这里我们不再断在线程函数里。
1
2
3
4
5
6
7
8
|
0
: kd> bd
*
0
: kd> bl
0
d Enable Clear fffff804`
73eed6b0
0001
(
0001
) FLTMGR!FltUnregisterFilter
1
d Enable Clear fffff804`
776669ff
0001
(
0001
) PCHunter64as
+
0x169ff
2
d Enable Clear fffff804`
776668e5
0001
(
0001
) PCHunter64as
+
0x168e5
3
d Enable Clear fffff804`
776c160f
0001
(
0001
) PCHunter64as
+
0x7160f
0
: kd> be
3
|
g放行,第二次断下到call ebx, 看了一下再初始化内存为0,然后没有传递相关微过滤驱动相关的东西,猜想应该是摘掉后遍历一次。直接放过去。
我们试试手动刷新会调用到哪里进行验证,确实如此。
第二次也断在同样的地方。由此逻辑就是刷新会调用两个功能函数。而移除后进行了刷新的调用。因此移除的功能只涉及一次函数调用。
白干了!PCHunter不卡的原因是他启用的系统线程去处理的?因为经过逆向分析,Windows 10 确实啥也没做。他不卡是因为创建了系统线程去跑,能不能摘掉就听天由命了。不信看官自己试试,他也摘不掉。
证明方法:通过遍历系统进程的线程,然后搜函数地址为0xFFFFF80477666A18的线程
1
2
3
4
5
6
7
|
0
: kd> !process
0
0
System
PROCESS ffffcf8f7bc8d300
SessionId: none Cid:
0004
Peb:
00000000
ParentCid:
0000
DirBase:
001ad002
ObjectTable: ffffa88a30e04ac0 HandleCount:
2216.
Image: System
0
: kd> !process ffffcf8f7bc8d300
|
综上所述,解决思路就是用系统线程去跑,如果没摘掉再跑一次,等到对象引用计数降为为0然后就摘掉了
更多【摘微过滤驱动回调的研究-续】相关视频教程:www.yxfzedu.com