关于RundownProtect到底是什么东西

时间:2023-02-20 23:09:16

RundownProtect这个字段相信只要是读过WRK源码的都会看过这个东西,这个字段在进程和线程的结构中都存在。最典型的例子就是对进程要进行什么操作的时候会先引用这个字段进行加保护,等操作结束后再进行解保护。但是一直没搞懂这个到底在保护什么和保护是怎么实现的。这里正好来看一下,首先是结构

   

    EX_RUNDOWN_REF RundownProtect;

这是ETHREAD的一部分,可见是一个EX_RUNDOWN_REF结构。我们来看一下EX_RUNDOWN_REF是什么样子的。

typedef struct _EX_RUNDOWN_REF
{
     union
     {
          ULONG Count;
          PVOID Ptr;
     };
} EX_RUNDOWN_REF, *PEX_RUNDOWN_REF;

这里结构都是基于Vista内核的。看的出来,所谓的EX_RUNDOWN_REF结构其实就是一个整数而已。关键是怎么使用的这个结构,想知道这一点得看一下ExAcquireRundownProtection()函数,这个函数是经常调用来给进程加保护的。我在WRK找到了这个函数的代码,如下

 1 NTKERNELAPI
 2 BOOLEAN
 3 FORCEINLINE
 4 FASTCALL
 5 ExAcquireRundownProtection (
 6      __inout PEX_RUNDOWN_REF RunRef
 7      )
 8 {
 9     ULONG_PTR Value, NewValue;
10 
11     Value = ReadForWriteAccess(&RunRef->Count) & ~EX_RUNDOWN_ACTIVE;
12     NewValue = Value + EX_RUNDOWN_COUNT_INC;
13     NewValue = (ULONG_PTR) InterlockedCompareExchangePointerAcquire (&RunRef->Ptr,
14                                                                      (PVOID) NewValue,
15                                                                      (PVOID) Value);
16     if (NewValue == Value) {
17         return TRUE;
18     } else {
19         return ExfAcquireRundownProtection (RunRef);
20     }
21 }

下面是ExfAcquireRundownProtection的代码

 1 NTKERNELAPI
 2 BOOLEAN
 3 FASTCALL
 4 ExfAcquireRundownProtection (
 5      __inout PEX_RUNDOWN_REF RunRef
 6      )
 7 /*++
 8 
 9 Routine Description:
10 
11     Reference a rundown block preventing rundown occurring if it hasn't already started
12     This routine is NON-PAGED because it is being called on the paging path.
13 
14 Arguments:
15 
16     RunRef - Rundown block to be referenced
17 
18 Return Value:
19 
20     BOOLEAN - TRUE - rundown protection was acquired, FALSE - rundown is active or completed
21 
22 --*/
23 {
24     ULONG_PTR Value, NewValue;
25 
26     Value = RunRef->Count;
27     do {
28         //
29         // If rundown has started return with an error
30         //
31         if (Value & EX_RUNDOWN_ACTIVE) {
32             return FALSE;
33         }
34 
35         //
36         // Rundown hasn't started yet so attempt to increment the unsage count.
37         //
38         NewValue = Value + EX_RUNDOWN_COUNT_INC;
39 
40         NewValue = (ULONG_PTR) InterlockedCompareExchangePointer (&RunRef->Ptr,
41                                                                   (PVOID) NewValue,
42                                                                   (PVOID) Value);
43         if (NewValue == Value) {
44             return TRUE;
45         }
46         //
47         // somebody else changed the variable before we did. Either a protection call came and went or rundown was
48         // initiated. We just repeat the whole loop again.
49         //
50         Value = NewValue;
51     } while (TRUE);
52 }