内核对象类型不恰当验证
Windows一系列的“内核对象”暴露了内核的很多特性。这些对象有可能是由用户层通过句柄用户来执行的。句柄是整数值,内核会判断作为调用者进行交互的是哪个(通常是系统服务),然后将句柄解析成某个特定对象的指针。所有的对象都共享相同的句柄命名空间。
由于这些不同类型的对象共享着相同的命名空间,系统服务检查句柄的一项任务就是验证这些对象指向的是期望类型。这项工作是由对象管理例行程序bReferenceObjectByHandle完成的,这个例行程序会将句柄解析成对象指针并进行可选的嵌入类型检查,它是通过把标准对象页头中的类型域与需要验证的进行对照来完成检查的。
由于KAV关联着系统服务,它不可避免地需要处理内核句柄。不幸的是,它并没有正确地进行此类操作。在一些情况下,在使用对象指针前,KAV并不能确定指向某类型对象的句柄。如果错误类型的句柄被传递给了系统服务,那么系统就有可能崩溃。
典型的例子就是KAV的NtResumeThread关联,该关联试图跟踪系统中正在运行的线程的状态。在这个特例中,看起来用户层好像无法通过把错误类型的对象作为返回对象指针而导致系统崩溃。这主要是因为它仅仅是被用作查找表的钥匙,该列表由线程对象指针预先占用了。KAV跟NtSuspendThread相关联也是基于同样的目的,并且这项关联也在验证对象的句柄类型上存在问题。
.text:F82245E0 ; NTSTATUS __stdcall KavNtResumeThread(
HANDLE ThreadHandle,
PULONG PreviousSuspendCount)
.text:F82245E0 KavNtResumeThread proc near ; DATA XREF: sub_F82249D0+FBo
.text:F82245E0
.text:F82245E0 ThreadHandle = dword ptr 8
.text:F82245E0 PreviousSuspendCount= dword ptr 0Ch
.text:F82245E0
.text:F82245E0 push esi
.text:F82245E1 mov esi, [esp+ThreadHandle]
.text:F82245E5 test esi, esi
.text:F82245E7 jz short loc_F8224620
.text:F82245E9 lea eax, [esp+ThreadHandle] ;
.text:F82245E9 ; This should pass an object type here!在这里应当传递对象类型
.text:F82245ED push 0 ; HandleInformation
.text:F82245EF push eax ; Object
.text:F82245F0 push 0 ; AccessMode
.text:F82245F2 push 0 ; ObjectType
.text:F82245F4 push 0F0000h ; DesiredAccess
.text:F82245F9 push esi ; Handle
.text:F82245FA mov [esp+18h+ThreadHandle], 0
.text:F8224602 call ds:ObReferenceObjectByHandle
.text:F8224608 test eax, eax
.text:F822460A jl short loc_F8224620
.text:F822460C mov ecx, [esp+ThreadHandle]
.text:F8224610 push ecx
.text:F8224611 call KavUpdateThreadRunningState
.text:F8224616 mov ecx, [esp+ThreadHandle] ; Object
.text:F822461A call ds:ObfDereferenceObject
.text:F8224620
.text:F8224620 loc_F8224620: ; CODE XREF: KavNtResumeThread+7j
.text:F8224620 ; KavNtResumeThread+2Aj
.text:F8224620 mov edx, [esp+PreviousSuspendCount]
.text:F8224624 push edx
.text:F8224625 push esi
.text:F8224626 call OrigNtResumeThread
.text:F822462C pop esi
.text:F822462D retn 8
.text:F822462D KavNtResumeThread endp
.text:F822462D
.text:F8224590 ; NTSTATUS __stdcall KavNtSuspendThread(
HANDLE ThreadHandle,
PULONG PreviousSuspendCount)
.text:F8224590 sub_F8224590 proc near ; DATA XREF: sub_F82249D0+113o
.text:F8224590
.text:F8224590 ThreadHandle = dword ptr 8
.text:F8224590 PreviousSuspendCount= dword ptr 0Ch
.text:F8224590
.text:F8224590 push esi
.text:F8224591 mov esi, [esp+ThreadHandle]
.text:F8224595 test esi, esi
.text:F8224597 jz short loc_F82245D0
.text:F8224599 lea eax, [esp+ThreadHandle] ;
.text:F8224599 ; This should pass an object type here!
.text:F822459D push 0 ; HandleInformation
.text:F822459F push eax ; Object
.text:F82245A0 push 0 ; AccessMode
.text:F82245A2 push 0 ; ObjectType
.text:F82245A4 push 0F0000h ; DesiredAccess
.text:F82245A9 push esi ; Handle
.text:F82245AA mov [esp+18h+ThreadHandle], 0
.text:F82245B2 call ds:ObReferenceObjectByHandle
.text:F82245B8 test eax, eax
.text:F82245BA jl short loc_F82245D0
.text:F82245BC mov ecx, [esp+ThreadHandle]
.text:F82245C0 push ecx
.text:F82245C1 call KavUpdateThreadSuspendedState
.text:F82245C6 mov ecx, [esp+ThreadHandle] ; Object
.text:F82245CA call ds:ObfDereferenceObject
.text:F82245D0
.text:F82245D0 loc_F82245D0: ; CODE XREF: sub_F8224590+7j
.text:F82245D0 ; sub_F8224590+2Aj
.text:F82245D0 mov edx, [esp+PreviousSuspendCount]
.text:F82245D4 push edx
.text:F82245D5 push esi
.text:F82245D6 call OrigNtSuspendThread
.text:F82245DC pop esi
.text:F82245DD retn 8
.text:F82245DD sub_F8224590 endp
.text:F82245DD |
但是,并不是所有的KAV关联都这么幸运。KAV安装的NtTerminateProcess钩子会查看函数的进程句柄参数所指向的对象实体,这样就能确定要终止的进程的名称。但是KAV没有验证用户层提供的对象句柄是否是真的指向一个进程对象。
文章评论
共有 位CH网友发表了评论 查看完整内容