前言
2021年3月,微软发布了一个补丁来修正Windows内核中的一个漏洞。该错误可能允许攻击者以升级的权限执行代码。该漏洞是由THEORI的安全研究员JeongOh Kyea向ZDI项目报告的。本文详细介绍了CVE-2021-26900的原理,以及它是如何绕过CVE-2020-1381在2020年7月的修复。
DirectComposition
DirectComposition是Windows中的一个组件,在Windows 8中被添加,它能够有效地支持图像转换和动画等图形效果。360Vulcan在CanSecWest 2017上发表了关于寻找DirectComposition漏洞的演讲—Win32k Dark Composition [PDF]。
DirectComposition可以通过以NtDComposition开头的win32k系统调用进行访问。在Windows 10 RS1之前,调用者为每个动作进行单独的系统调用,如创建或释放资源。在Windows 10 RS1之后,被合并到NtDCompositionProcessChannelBatchBuffer这一个系统调用中,它以批处理模式处理几个命令。360Vulcan在CanSecWest 2017上发表的工作对这个函数进行了Fuzz测试,以找到漏洞。此后,与DirectComposition有关的许多漏洞被发现,包括一个Pwn2Own的漏洞:CVE-2020-1382。
触发DirectComposition漏洞时有三个必要的系统调用:
- NtDCompositionCreateChannel
- NtDCompositionProcessChannelBatchBuffer
- NtDCompositionCommitChannel
要创建DirectComposition对象,调用者必须首先使用NtDCompositionCreateChannel系统调用创建一个通道。
// Create Channel
HANDLE hChannel;
PVOID pMappedAddress = NULL; SIZE_T SectionSize = 0x4000;
DWORD dwArg1, dwArg2;
NtDCompositionCreateChannel(&hChannel, &SectionSize, &pMappedAddress); // Data is Transferred through pMappedAddress
创建通道之后,可以使用NtDCompositionProcessChannelBatchBuffer系统调用发送几个命令。每个命令都有自己的格式,且大小不同。
enum DCOMPOSITION_COMMAND_ID
{
ProcessCommandBufferIterator,
CreateResource,
OpenSharedResource,
ReleaseResource,
GetAnimationTime,
CapturePointer,
OpenSharedResourceHandle,
SetResourceCallbackId,
SetResourceIntegerProperty,
SetResourceFloatProperty,
SetResourceHandleProperty,
SetResourceHandleArrayProperty,
SetResourceBufferProperty,
SetResourceReferenceProperty,
SetResourceReferenceArrayProperty,
SetResourceAnimationProperty,
SetResourceDeletedNotificationTag,
AddVisualChild,
RedirectMouseToHwnd,
SetVisualInputSink,
RemoveVisualChild
};
映射的段地址pMappedAddress用于存储一批命令。在pMappedAddress存储几个命令之后,调用者可以调用NtDCompositionProcessChannelBatchBuffer来处理这些命令。
要触发漏洞,我们需要使用3个命令:
- CreateResource
- SetResourceBufferProperty
- ReleaseResource
首先,CreateResource
用于创建特定类型的对象。CreateResource
命令的大小为16字节,格式如下。根据Windows版本不同,资源类型可能有所不同。可以通过分析win32kbase!DirectComposition: CApplicationChannel: CreateResource
来轻松地获得资源类型编号。
// Create Resource
*(DWORD*)(pMappedAddress) = CreateResource;
*(HANDLE*)(pMappedAddress + 4) = 1; // Resource ID (a unique number)
// For example, on Windows 20H2, 19042.804:
// 0x58 == CInteractionTrackerMarshaler
// 0x59 == CInteractionTrackerBindingManagerMarshaler
*(DWORD*)(pMappedAddress + 8) = 0x59; // Resource Type
*(DWORD*)(pMappedAddress + 12) = FALSE;
ntStatus = NtDCompositionProcessChannelBatchBuffer(hChannel, 16, &dwArg1, &dwArg2);
接着,SetResourceBufferProperty
用于设置目标对象的数据。该命令的大学和个数取决于资源类型。
*(DWORD*)pMappedAddress = SetResourceBufferProperty;
*(HANDLE*)(pMappedAddress + 4) = 1; // Resource ID
*(DWORD*)(pMappedAddress + 8) = subcmd; // Sub-Command
*(DWORD*)(pMappedAddress + 12) = datasize; // Datasize
CopyMemory(pMappedAddress + 16, data, datasize); // Data
// Total size of command == 16 + datasize
ntStatus = NtDCompositionProcessChannelBatchBuffer(hChannel, 16 + datasize, &dwArg1, &dwArg2);
最后,使用ReleaseResource
来释放资源。ReleaseResource
命令的大小为8字节,格式如下。
*(DWORD*)(pMappedAddress) = ReleaseResource;
*(HANDLE*)(pMappedAddress + 4) = 1; // Resource ID
ntStatus = NtDCompositionProcessChannelBatchBuffer(hChannel, 8, &dwArg1, &dwArg2);
NtDCompositionCommitChannel系统调用将这些命令序列化后,通过本地过程调用(LPC)协议发送到桌面窗口管理器(dwm.exe)。在从内核接收到命令之后,桌面窗口管理器(dwm.exe)将把这些命令呈现到屏幕上。
关于漏洞
CVE-2021-26900涉及CInteractionTrackerBindingManagerMarshaler
和CInteractionTrackerMarshaler
。此漏洞与CVE-2020-1381非常相似,因此在讨论CVE-2021-26900之前,我们将先详细解释CVE-2020-1381。
CVE-2020-1381
CVE-2020-1381修复补丁于2020年7月发布。该漏洞发生在DirectComposition::CInteractionTrackerBindingManagerMarshaler::SetBufferProperty
函数中,该函数是CInteractionTrackerBindingManagerMarshaler
对象中SetResourceBufferProperty
命令的处理程序。
NTSTATUS DirectComposition::CInteractionTrackerBindingManagerMarshaler::SetBufferProperty(DirectComposition::CInteractionTrackerBindingManagerMarshaler *binding, DirectComposition::CApplicationChannel *resinfo, unsigned int subcmd, void* databuffer, size_t datasize, bool *out)
{
if( subcmd || datasize != 12 )
return STATUS_INVALID_PARAMETER;
resource1_id = *(DWORD*)(databuffer)
resource2_id = *(DWORD*)(databuffer+4)
new_entry_id = *(DWORD*)(databuffer+8)
// [1]. Get Proper Resource
if ( resource1_id && resource1_id < resinfo->resourceid_max )
tracker1 = *( (resource1_id - 1) * resinfo->entry_size + resinfo->resource_list );
else
tracker1 = NULL;
if ( resource2_id && resource2_id < resinfo->resourceid_max )
tracker2 = *( (resource2_id - 1) * resinfo->entry_size + resinfo->resource_list );
else
tracker2 = NULL;
// [2]. Check Resource type == CInteractionTrackerMarshaler
if ( tracker1 && tracker2 && tracker1->IsOfType(0x58) && tracker2->IsOfType(0x58) )
{
/*
1. Find tracker pair in tracker list
1-1 If it exists, update entry_id
1-2 If it does not exist, add a new entry
*/
}
/* ... */
}
CInteractionTrackerBindingManagerMarshaler
对象接受12字节作为SetResourceBufferProperty
命令的数据。数据由三个DWORDs组成:resource1_id
、resource2_id
和new_entry_id
。
这个函数首先从用户指定的resource1_id
和resource2_id
中检索资源[1]。然后检查每个资源的类型是否为0x58
,这是CInteractionTrackerMarshaler
的资源类型[2]。
接下来,这对CInteractionTrackerMarshaler
资源被附加到CInteractionTrackerBindingManagerMarshaler
对象的跟踪器列表中。如名称所示,这两种对象类型CInteractionTrackerMarshaler
和CInteractionTrackerBindingManagerMarshaler
是相互关联的。CInteractionTrackerBindingManagerMarshaler
对象保存了CInteractionTrackerMarshaler
对象对的列表,并且每个CInteractionTrackerMarshaler
对象都有一个返回到CInteractionTrackerBindingManagerMarshaler
对象的指针。
当DirectComposition:: cinteractiontrackbindingmanagermarshaler::SetBufferProperty
函数第一次被调用时,跟踪器对被添加到列表中,因为列表是空的。
// Size == 32 bytes
struct TrackerEntry
{
CInteractionTrackerMarshaler* Tracker1;
CInteractionTrackerMarshaler* Tracker2;
DWORD entry_id;
DWORD flag1;
BYTE flag2;
};
NTSTATUS DirectComposition::CInteractionTrackerBindingManagerMarshaler::SetBufferProperty(DirectComposition::CInteractionTrackerBindingManagerMarshaler *binding, DirectComposition::CApplicationChannel *resinfo, unsigned int subcmd, void* databuffer, size_t datasize, bool *out)
{
// ....
// 1-2. Add New Entry
if ( new_entry_id )
{
// [3]. Append Pair Data to list
result = DirectComposition::CDCompDynamicArrayBase::Grow(binding->tracker_list, 1, 'siCD');
if ( result < 0 )
return result;
entry_size = binding->tracker_list.entrysize; // 0x20 by default
offset = entry_size * (binding->tracker_list.numofentry - 1);
dest = binding->tracker_list.ptr + offset;
// struct TrackerEntry* TrackerPairEntry;
TrackerPairEntry->Tracker1 = tracker1;
TrackerPairEntry->Tracker2 = tracker2;
TrackerPairEntry->entry_id = new_entry_id;
TrackerPairEntry->flag1 = 0;
TrackerPairEntry->flag2 = 1;
memmove(dest, TrackerPairEntry, entry_size);
// [4]. Set reference from `CInteractionTrackerMarshaler` to `CInteractionTrackerBindingManagerMarshaler`
if ( !tracker1->binding_obj )
DirectComposition::CInteractionTrackerMarshaler::SetBindingManagerMarshaler(tracker1, resinfo, binding);
if ( !tracker2->binding_obj )
DirectComposition::CInteractionTrackerMarshaler::SetBindingManagerMarshaler(tracker2, resinfo, binding);
}
// ...
}
为了将新条目添加到跟踪器列表中,tracker_list
的大小增加1,并写入新的跟踪器对数据[3]。然后,它使用DirectComposition::CInteractionTrackerMarshaler::SetBindingManagerMarshaler
函数设置每个CInteractionTrackerMarshaler
对象到CInteractionTrackerBindingManagerMarshaler
对象的引用[4]。
void DirectComposition::CInteractionTrackerMarshaler::SetBindingManagerMarshaler(DirectComposition::CInteractionTrackerMarshaler* tracker, DirectComposition::CApplicationChannel *resinfo, DirectComposition::CInteractionTrackerBindingManagerMarshaler *binding_obj)
{
old_binding_obj = tracker->binding_obj;
if ( old_binding_obj != binding_obj )
{
if ( binding_obj )
binding_obj->refcnt++;
DirectComposition::CApplicationChannel::ReleaseResource(_resource_list, old_binding_obj);
tracker->binding_obj = binding_obj;
}
}
DirectComposition::CInteractionTrackerMarshaler::SetBindingManagerMarshaler
函数将tracker->binding_obj
更新为一个新的CInteractionTrackerBindingManagerMarshaler
对象。
将CInteractionTrackerMarshaler
对象对附加到tracker_list
之后,CInteractionTrackerMarshaler
对象和CInteractionTrackerBindingManagerMarshaler
对象之间的关系如下:
因为它们是相互引用的,所以在释放对象时必须清除这些引用。让我们看看CInteractionTrackerMarshaler
对象被释放的情况。要释放与CInteractionTrackerMarshaler
对象相关的资源,需要调用DirectComposition::CInteractionTrackerMarshaler::ReleaseAllReferences
函数。
void DirectComposition::CInteractionTrackerMarshaler::ReleaseAllReferences(DirectComposition::CInteractionTrackerMarshaler *tracker, DirectComposition::CApplicationChannel *resinfo)
{
/* Omitted */
// ...
binding = tracker->binding_obj;
if( binding )
{
DirectComposition::CInteractionTrackerBindingManagerMarshaler::RemoveTrackerBindings(binding, tracker->resource_id);
DirectComposition::CApplicationChannel::ReleaseResource(resinfo, binding);
}
tracker->binding_obj = NULL;
}
void DirectComposition::CInteractionTrackerBindingManagerMarshaler::RemoveTrackerBindings(DirectComposition::CInteractionTrackerBindingManagerMarshaler *binding, int resource_id)
{
for (int i = 0; i < binding->tracker_list.numofentry; i++)
{
entry_size = binding->tracker_list.entrysize; // 0x20 by default
entry_ptr = (struct TrackerEntry *)(binding->tracker_list.ptr + entry_size * i);
entry_tracker1 = entry_ptr->Tracker1;
entry_tracker2 = entry_ptr->Tracker2;
if(entry_tracker1->resource_id == resource_id || entry_tracker2->resource_id == resource_id)
{
// set entry_id to 0
entry_ptr->entry_id = 0;
}
}
// Delete the entry of which entry_id is zero.
DirectComposition::CInteractionTrackerBindingManagerMarshaler::CleanUpListItemsPendingDeletion(binding);
}
如果CInteractionTrackerBindingManagerMarshaler
对象有一个与CInteractionTrackerBindingManagerMarshaler
对象的绑定,则调用DirectComposition:: CInteractionTrackerBindingManagerMarshaler::RemoveTrackerBindings
来删除相应的跟踪条目。
在DirectComposition:: CInteractionTrackerBindingManagerMarshaler::RemoveTrackerBindings
中,如果条目中的两个跟踪器对象中有一个具有与被删除对象匹配的资源id,那么该条目的entry_id
将被设置为0。最后,它调用DirectComposition:: CInteractionTrackerBindingManagerMarshaler:: cleanuplisttitemspendingdeletion
来清除那些entry_id
等于0的条目。
然而,如果一个单独的CInteractionTrackerMarshaler
被添加到多个cinteractiontrackbindingmanagermarshaler
跟踪列表会发生什么?因为在添加新条目时没有检查,已经绑定到CInteractionTrackerBindingManagerMarshaler
对象的CInteractionTrackerMarshaler
对象可以绑定到第二个CInteractionTrackerBindingManagerMarshaler
对象。
下图显示了这种情况:
在这种情况下,如果Tracker1
被释放,只有TrackBindingB
中的条目被删除,因为Tracker1
被绑定到TrackBindingB
。最终,TrackBindingB
对象的条目具有已释放的对象指针。
这个悬空对象指针稍后会在DirectComposition:: CInteractionTrackerBindingManagerMarshaler:: EmitBoundTrackerMarshalerUpdateCommands
函数中解引用,该函数可以通过ntdcompontioncommitchannel系统调用来触发。这个系统调用在批处理命令的序列化期间引用资源。
bool DirectComposition::CInteractionTrackerBindingManagerMarshaler::EmitBoundTrackerMarshalerUpdateCommands(DirectComposition::CInteractionTrackerBindingManagerMarshaler *binding, DirectComposition::CBatch **a2)
{
result = true;
for (int i = 0; i < binding->tracker_list.numofentry; i++)
{
entry_size = binding->tracker_list.entrysize; // 0x20 by default
entry_ptr = (struct TrackerEntry *)(binding->tracker_list.ptr + entry_size * i);
entry_tracker1 = entry_ptr->Tracker1;
entry_tracker2 = entry_ptr->Tracker2;
if( entry_ptr->entry_id )
{
result = entry_tracker1->EmitUpdateCommands(a2) & result;
result = entry_tracker2->EmitUpdateCommands(a2) & result;
}
}
}
上面显示的函数为tracker_list
中的对象调用EmitUpdateCommands
方法。被释放的对象将在进程中被引用,这导致了一个“释放后再使用”的漏洞。
CVE-2021-26900
CVE-2021-26900将绕过CVE-2020-1381的补丁重新触发上述漏洞。CVE-2020-1381的补丁如下所示。
NTSTATUS DirectComposition::CInteractionTrackerBindingManagerMarshaler::SetBufferProperty(DirectComposition::CInteractionTrackerBindingManagerMarshaler *binding, DirectComposition::CApplicationChannel *resinfo, unsigned int subcmd, void* databuffer, size_t datasize, bool *out)
{
// ...
// 1-2. Add New Entry
if ( new_entry_id )
{
if ( !tracker1->binding_obj || tracker1->binding_obj == binding ) { // [*] Check tracker1->binding_obj
if ( !tracker2->binding_obj || tracker2->binding_obj == binding ) { // [*] Check tracker2->binding_obj
/* Add Tracker Pair routine */
result = DirectComposition::CDCompDynamicArrayBase::Grow(binding->tracker_list, 1, 'siCD');
// ...
// Omitted
}
}
}
// ...
}
标有[*]为新增的部分,是用来检查CInteractionTrackerMarshaler
对象的binding_obj
。它检查CInteractionTrackerMarshaler
是否已经绑定到另一个CInteractionTrackerBindingManagerMarshaler
。
然而,这个补丁可以通过更新跟踪器条目绕过。让我们看看更新跟踪器条目的代码:
NTSTATUS DirectComposition::CInteractionTrackerBindingManagerMarshaler::SetBufferProperty(DirectComposition::CInteractionTrackerBindingManagerMarshaler *binding, DirectComposition::CApplicationChannel *resinfo, unsigned int subcmd, void* databuffer, size_t datasize, bool *out)
{
// ...
// 1. Find tracker pair in tracker list
for (int i = 0; i < binding->tracker_list.numofentry; i++)
{
entry_size = binding->tracker_list.entrysize; // 0x20 by default
entry_ptr = (struct TrackerEntry *)(binding->tracker_list.ptr + entry_size * i);
entry_tracker1 = entry_ptr->Tracker1;
entry_tracker2 = entry_ptr->Tracker2;
tracker1_id = tracker1->resource_id;
tracker2_id = tracker2->resource_id;
if ( (entry_tracker1->resource_id == tracker1_id && entry_tracker2->resource_id == tracker2_id) ||
(entry_tracker1->resource_id == tracker2_id && entry_tracker2->resource_id == tracker1_id) )
{
// 1-1 If it exists, update entry_id
if ( entry_ptr->entry_id == new_entry_id )
return 0;
// [1] Update entry_id
entry_ptr->entry_id = new_entry_id;
entry_ptr->flag2 = 1;
if ( !new_entry_id )
{
// [2] if the new_entry_id is zero, remove relationship between CInteractionTrackerMarshaler and
// CInteractionTrackerBindingManagerMarshaler "if NECESSARY"
DirectComposition::CInteractionTrackerBindingManagerMarshaler::RemoveBindingManagerReferenceFromTrackerIfNecessary(binding, resinfo, tracker1_id, tracker2_id);
}
else
{
// Some routine
}
// ...
return 0;
}
}
// 1-2. Add New Entry
// ...
}
首先,上面的代码尝试找到具有跟踪器对(tracker1, tracker2)
或(tracker2, tracker1)
的条目。如果有条目,则将entry_id
更新为new_entry_id
([1])。
与此漏洞相关的最重要的部分是[2]。当new_entry_id
为0时,CInteractionTrackerBindingManagerMarshaler
对象将此条目视为不必要的。为了处理这个条目,它调用DirectComposition:: CInteractionTrackerBindingManagerMarshaler::RemoveBindingManagerReferenceFromTrackerIfNecessary
函数。但是这个函数不会删除这个条目,它只删除绑定。
void DirectComposition::CInteractionTrackerBindingManagerMarshaler::RemoveBindingManagerReferenceFromTrackerIfNecessary(DirectComposition::CInteractionTrackerBindingManagerMarshaler *binding, DirectComposition::CApplicationChannel *resinfo, int resource1_id, int resource2_id)
{
if (resource1_id && resource1_id < resinfo->resourceid_max)
tracker1 = *( (resource1_id - 1) * resinfo->entry_size + resinfo->resource_list );
else
tracker1 = NULL;
if(resource2_id && resource2_id < resinfo->resourceid_max)
tracker2 = *( (resource2_id - 1) * resinfo->entry_size + resinfo->resource_list );
else
tracker2 = NULL;
tracker1_exist = false;
tracker2_exist = false;
// Check type of Resources
if ( tracker1 && tracker2 && tracker1->IsOfType(0x58) && tracker2->IsOfType(0x58) )
{
for(int i = 0; i < binding->tracker_list.numofentry; i++)
{
entry_size = binding->tracker_list.entrysize; // 0x20 by default
entry_ptr = (struct TrackerEntry *)(binding->tracker_list.ptr + entry_size * i);
entry_tracker1 = entry_ptr->Tracker1;
entry_tracker2 = entry_ptr->Tracker2;
tracker1_id = tracker1->resource_id;
tracker2_id = tracker2->resource_id;
// Find the entry
if ( entry_ptr->entry_id ) {
if ( entry_tracker1->resource_id == tracker1_id || entry_tracker2->resource_id == tracker1_id )
tracker1_exist = true;
if ( entry_tracker1->resource_id == tracker2_id || entry_tracker2->resource_id == tracker2_id )
tracker2_exist = true;
}
}
// If there is no other object related with tracker1 or tracker2
// Remove the binding.
if ( !tracker1_exist )
DirectComposition::CInteractionTrackerMarshaler::SetBindingManagerMarshaler(tracker1, resinfo, 0);
if ( !tracker2_exist )
DirectComposition::CInteractionTrackerMarshaler::SetBindingManagerMarshaler(tracker2, resinfo, 0);
}
}
上面的函数尝试寻找资源id为tracker1_id
或tracker2_id
的条目。如果没有其他资源id为tracker1_id
或tracker2_id
的条目,这意味着这两个对象不必相互引用。因此,DirectComposition::CInteractionTrackerMarshaler::SetBindingManagerMarshaler
函数被一个NULL绑定对象调用,以移除CInteractionTrackerMarshaler
对象的绑定。
然而,尽管从CInteractionTrackerMarshaler
到cinteractiontrackbindingmanagermarshaler
的绑定被移除,tracker1
或tracker2
的指针仍然留在跟踪器列表中。用零值new_entry_id
更新条目会产生如下所示的状态:
现在,CInteractionTrackerMarshaler
对象的binding_obj
被设置为零,这可以绕过CVE-2020-1381的补丁。如果我们将tracker1
绑定到另一个CInteractionTrackerBindingManagerMarshaler
对象,状态会发生如下变化。
接下来,将TrackerBindingA
中的entry_id
更新为非零值将产生与CVE-2020-1381中相同的状态。
修复
该补丁应用于win32kbase.sys以修复CVE-2021-26900,如下:
NTSTATUS DirectComposition::CInteractionTrackerBindingManagerMarshaler::SetBufferProperty(DirectComposition::CInteractionTrackerBindingManagerMarshaler *binding, DirectComposition::CApplicationChannel *resinfo, unsigned int subcmd, void* databuffer, size_t datasize, bool *out)
{
...
if( ( entry_tracker1->resource_id == tracker1_id && entry_tracker2->resource_id == tracker2_id ) ||
( entry_tracker1->resource_id == tracker2_id && entry_tracker2->resource_id == tracker1_id ) )
{
// 1-1 If it exists, update entry_id
if ( entry_ptr->entry_id == new_entry_id )
return 0;
// [1]. Update entry_id
entry_ptr->entry_id = new_entry_id;
entry_ptr->flag2 = 1;
- if ( !new_entry_id ) {
- DirectComposition::CInteractionTrackerBindingManagerMarshaler::RemoveBindingManagerReferenceFromTrackerIfNecessary(binding, resinfo, tracker1_id, tracker2_id);
- }
- else {
- // Some routine
- }
...
return 0;
}
// 1-2. Add New Entry
if ( new_entry_id )
{
if (!tracker1->binding_obj || tracker1->binding_obj == binding) { // [*] Check tracker1->binding_obj
if (!tracker2->binding_obj || tracker2->binding_obj == binding) { // [*] Check tracker2->binding_obj
+ overflow_check = tracker1->listref++ == -1;
+ if ( overflow_check ) {
+ tracker1->listref = -1
+ }
+ else {
+ overflow_check = tracker2->listref++ == -1;
+ if ( overflow_check ) {
+ tracker1->listref--;
+ tracker2->listref--;
+ }
+ else {
/* Tracker Pair Add routine */
result = DirectComposition::CDCompDynamicArrayBase::Grow(binding->tracker_list, 1, 'siCD');
...
// Omitted
+ }
+ }
}
}
}
...
}
该补丁适用于将条目添加到tracker_list
、修改entry_id
并释放资源的代码。
当修改entry_id
时,虽然entry_id
为0,但是绑定不会被删除。
接下来,当添加条目时,listref
字段被添加到资源中。当相同的对象被插入到tracker_list
中时,该字段用于正确地释放对象。
void DirectComposition::CInteractionTrackerBindingManagerMarshaler::CleanUpListItemsPendingDeletion(DirectComposition::CInteractionTrackerBindingManagerMarshaler *binding, DirectComposition::CApplicationChannel *resinfo)
{
live_obj_num = 0;
for (int i = 0; i < binding->tracker_list.numofentry; i++)
{
entry_size = binding->tracker_list.entrysize; // 0x20 by default
entry_ptr = (struct TrackerEntry *)(binding->tracker_list.ptr + entry_size * i);
entry_tracker1 = entry_ptr->Tracker1;
entry_tracker2 = entry_ptr->Tracker2;
+ if ( entry_ptr->entry_id )
+ {
// Make list compact
write_ptr = (struct TrackerEntry *)(binding->tracker_list.ptr + entry_size * live_obj_num);
memmove(write_ptr, entry_ptr, entry_size)
+ }
+ else
+ {
+ // NULL entry_id
+ entry_tracker1->listref--;
+ if (!entry_tracker1->listref) {
+ DirectComposition::CInteractionTrackerMarshaler::SetBindingManagerMarshaler(entry_tracker1, resinfo, 0);
+ }
+ entry_tracker2->listref--;
+ if (!entry_tracker2->listref) {
+ DirectComposition::CInteractionTrackerMarshaler::SetBindingManagerMarshaler(entry_tracker1, resinfo, 0);
+ }
+ }
}
DirectComposition::CDCompDynamicArrayBase::Shrink(binding->tracker_list,
binding->tracker_list.numofentry - live_obj_num);
}
最后,当释放资源时,绑定实际上会在DirectComposition:: CInteractionTrackerBindingManagerMarshaler:: CleanUpListItemsPendingDeletion
函数中被删除。
这里可以找到此漏洞的POC。