typedef struct _ETW_UPDATE_PERIODIC_CAPTURE_STATE
{
ULONGLoggerId;
ULONGDueTime;//system time units (100-nanosecond intervals)
ULONGNumOfGuids;
GUIDGuids[ANYSIZE_ARRAY];
} ETW_UPDATE_PERIODIC_CAPTURE_STATE, * PETW_UPDATE_PERIODIC_CAPTURE_STATE;
__int64 __fastcall EtwpUpdatePeriodicCaptureState(unsigned int LoggerId, unsigned int DueTime, unsigned __int16 NumOfGuids, GUID *Guids)
{
...
//如果沒有定時器存在則直接創建定時器
if ( !LoggerContext_->ExTimerObject )
{
TimerContextInfo = (CONTEXTINFO *)ExAllocatePoolWithTag(NonPagedPoolNx, 0x30ui64, 'UwtE'); //創建回調函數參數,類型為_WORK_QUEUE_ITEM
TimerContextInfo_ = TimerContextInfo;
if ( !TimerContextInfo )
goto RETURN_ERROR_C0000017;
TimerContextInfo->LoggerId = LoggerId;//InBuff1.LoggerId
TimerContextInfo->Unknown = v22;
TimerContextInfo->WorkItem.WorkerRoutine = SendCaptureStateNotificationsWorker;// worker的回調函數
TimerContextInfo->WorkItem.Parameter = TimerContextInfo;// worker回調函數的參數,也就是SendCaptureStateNotificationsWorker的參數
TimerContextInfo->WorkItem.List.Flink = 0i64;
LoggerContext_->ExTimerObject = ExAllocateTimer((PEXT_CALLBACK)PeriodicCaptureStateTimerCallback, TimerContextInfo, 8u); //保存定時器
}
ExTimerObject = (PEX_TIMER)LoggerContext_->ExTimerObject;
LoggerContext_->DueTime = 0xFFFFFFFFFF676980ui64 * DueTime;
ExSetTimer((ULONG_PTR)ExTimerObject);//超時時間以秒計算,為負數
LODWORD(LoggerContext_->ExTimerState) = 1;
goto RETURN_1;
...
RETURN_1:
if ( (_InterlockedExchangeAdd64(pLock, 0xFFFFFFFFFFFFFFFFui64) & 6) == 2 )
ExfTryToWakePushLock(pLock);
KeAbPostRelease((ULONG_PTR)pLock);
RETURN_2:
EtwpReleaseLoggerContext(LoggerContext_, 0i64);
return (unsigned int)res_EtwpCheckNotificationAccess;
}
__int64 __fastcall EtwpUpdatePeriodicCaptureState(unsigned int LoggerId, unsigned int DueTime, unsigned __int16 NumOfGuids, GUID *Guids)
{
...
{
...
FREE_POOLS_AND_RESET:
GuidsPool = (void *)LoggerContext_->GuidsPool;
if ( GuidsPool )
{
ExFreePoolWithTag(GuidsPool, 0);
LoggerContext->GuidsPool = 0i64;
LOWORD(LoggerContext->NumOfGuids) = 0;
}
...
}
if ( (_DWORD)NumOfGuids_ )
{
while ( 1 )//循環判斷用戶傳入的guid是否具有訪問權限,如果有一個不滿足就進入FREE_POOLS_AND_RESET分支
{
res_EtwpCheckNotificationAccess = EtwpCheckNotificationAccess(
&Guids[v4].Data1,
(__int64)&LoggerContext_->field_0[0x124]);
if ( res_EtwpCheckNotificationAccess < 0 )
break;
if ( ++v4 >= (int)NumOfGuids_ )
goto ALL_GUIDS_HAVE_NOTIFICATION_ACCESS_OK;
}
res_EtwpCheckNotificationAccess = 0xC0000022;
v8 = 0;
goto FREE_POOLS_AND_RESET;
}
ALL_GUIDS_HAVE_NOTIFICATION_ACCESS_OK:
...
}
void __fastcall SendCaptureStateNotificationsWorker(CONTEXTINFO *TimerContextInfo)
{
...
if ( TimerContextInfo )
{
LoggerContext = (LOGGERCONTEXT *)EtwpAcquireLoggerContextByLoggerId(
TimerContextInfo->Unknown,
LOWORD(TimerContextInfo->LoggerId),
0);
if ( LoggerContext )
{
pLock = &LoggerContext->Lock;
ExAcquirePushLockExclusiveEx((ULONG_PTR)&LoggerContext->Lock, 0i64);
LODWORD(LoggerContext__->ExTimerState) = 0;
if ( *(_DWORD *)&LoggerContext__->field_0[336] )
{
//在第二個請求中我們已經將這個數量設置為空,所以後面會進入LABEL_31分支
NumOfGuids = LOWORD(LoggerContext__->NumOfGuids);
if ( (_WORD)NumOfGuids )
{
...
if ( (int)EtwpBuildNotificationPacket(v10, v23, v15, &v19) >= 0 )
{
EtwpSendDataBlock(v12, v19);
EtwpUnreferenceDataBlock(v19);
}
...
if ( LOWORD(LoggerContext__->NumOfGuids) && !LODWORD(LoggerContext__->ExTimerState) )
{
ExSetTimer(LoggerContext__->ExTimer);
LODWORD(LoggerContext__->ExTimerState) = 1;
v2 = 1;
}
...
...
}
}
if ( (_InterlockedExchangeAdd64(pLock, 0xFFFFFFFFFFFFFFFFui64) & 6) == 2 )
ExfTryToWakePushLock(pLock);
KeAbPostRelease((ULONG_PTR)pLock);
EtwpReleaseLoggerContext(LoggerContext__, 0i64);
if ( v2 )//這裡沒有進入上面分支所以不會設置為0
return;
goto LABEL_31;//
}
}
//最終釋放了之前的WORK_QUEUE_ITEM參數
LABEL_31:
ExFreePoolWithTag(TimerContextInfo, 0);
}
漏洞修復
__int64 __fastcall EtwpUpdatePeriodicCaptureState(unsigned int LoggerId, unsigned int DueTime, unsigned __int16 NumOfGuids, GUID *Guids)
{
...
ExAcquirePushLockExclusiveEx(EtwpLoggerContext1 + 688, 0i64);
CallbackContext1 = *(_QWORD *)(EtwpLoggerContext1 + 1080);//取出之前創建的Context
if ( CallbackContext1 )//如果存在了CallbackContext則進入
goto LABEL_31;
if ( !(_WORD)v4 )
{
LABEL_24:
if ( (_InterlockedExchangeAdd64((volatile signed __int64 *)(EtwpLoggerContext1 + 688), 0xFFFFFFFFFFFFFFFFui64) & 6) == 2)
ExfTryToWakePushLock(EtwpLoggerContext1 + 688);
KeAbPostRelease(EtwpLoggerContext1 + 688);
goto LABEL_27;
}
CallbackContext = ExAllocatePool2(64i64, 72i64, 0x55777445i64);
//設置LoggerContext+1080位置為創建的CallbackContext
*(_QWORD *)(EtwpLoggerContext1 + 1080) = CallbackContext;
CallbackContext1 = CallbackContext;
...
Pool2 = (void *)ExAllocatePool2(256i64, 16 * v4, 0x55777445i64);
*(_QWORD *)(CallbackContext1 + 24) = Pool2;
if ( Pool2 )
{
*(_WORD *)(CallbackContext1 + 16) = v4;
memmove(Pool2, (const void *)InputBuffer_kernel_C, 16 * v4);
if ( !*(_QWORD *)(CallbackContext1 + 8) )
{
//回調函數的參數變成了LoggerContext
Timer = ExAllocateTimer((__int64)PeriodicCaptureStateTimerCallback, EtwpLoggerContext1, 8u);
*(_QWORD *)(CallbackContext1 + 8) = Timer;
if ( !Timer )
{
ExFreePoolWithTag(*(PVOID *)(CallbackContext1 + 24), 0);
*(_QWORD *)(CallbackContext1 + 24) = 0i64;
*(_WORD *)(CallbackContext1 + 16) = 0;
goto LABEL_11;
}
*(_QWORD *)(CallbackContext1 + 56) = EtwpLoggerContext1;
*(_QWORD *)(CallbackContext1 + 48) = SendCaptureStateNotificationsWorker;
*(_QWORD *)(CallbackContext1 + 32) = 0i64;// WORK_QUEUE_ITEM的開始位置
}
*((_QWORD *)&v21 + 1) = 0xFFFFFFFFFFFFFFFFui64;
v17 = *(_QWORD *)(CallbackContext1 + 8);
v18 = 0xFFFFFFFFFF676980ui64 * a2;
*(_QWORD *)CallbackContext1 = v18;
ExSetTimer(v17, v18, 0i64, (__int64)&v21);
*(_DWORD *)(CallbackContext1 + 64) = 1;
goto LABEL_24;
}
...
}
void __fastcall PeriodicCaptureStateTimerCallback(__int64 Timer, __int64 EtwpLoggerContext)
{
if ( ExAcquireRundownProtectionCacheAwareEx(
*(PEX_RUNDOWN_REF_CACHE_AWARE *)(*(_QWORD *)(*(_QWORD *)(EtwpLoggerContext + 1096) + 448i64)
+ 8i64 * *(unsigned int *)EtwpLoggerContext),
1u) )
{
// EtwpLoggerContext + 1080就是CallbackContext,+32位置就是WORK_QUEUE_ITEM的開始位置
ExQueueWorkItem((PWORK_QUEUE_ITEM)(*(_QWORD *)(EtwpLoggerContext + 1080) + 32i64), NormalWorkQueue);
}
}
參考鏈接
https://www.pixiepointsecurity.com/blog/advisory-cve-2021-34486.html