NtQueryObject 获得内核对象使用计数
一个内核对象有两个计数器:一个是句柄计数,句柄是给用户态用的;另一个是指针计数,也叫引用计数,因为核心态也常常用到内核对象,为了方便,在核心态的代码用指针直接访问对象,所以Object Manager维护了这个指针引用计数。只有在句柄计数和引用计数都为0时,对象才被释放。一般而言,指针引用计数值比句柄计数值大。
再进一步,实际上,在用户态其实是可以查询一个内核对象的句柄计数和引用计数的。Ntdll.dll里导出的NtQueryObject函数可以查询内核对象的当前状态,只不过它没有被文档化。
函数声明如下:
DWORD WINAPI NtQueryObject( HANDLE handle, DWORD nQueryIndex, VOID* pOutBuffer, DWORD cbInBufferSize, VOID* cbOutBufferSize);
handle -- 待查询的句柄
nQueryIndex -- 0为查询对象的当前状态,包括句柄计数,引用计数等等。
pOutBuffer -- 存放查询结果
cbInBufferSize -- pOutBuffer的大小,注意,如果nQueryIndex为0,这里一定得是0x38
cbOutBufferSize -- 实际大小。
返回值:如果成功则返回0
pOutBuffer里返回的数据结构如下:
typedef struct _SYSTEM_HANDLE_STATE {
DWORD r1;
DWORD GrantedAccess;
DWORD HandleCount; // 减1为句柄计数
DWORD ReferenceCount; // 减1为指针引用计数
DWORD r5;
DWORD r6;
DWORD r7;
DWORD r8;
DWORD r9;
DWORD r10;
DWORD r11;
DWORD r12;
DWORD r13;
DWORD r14;
}SYSTEM_HANDLE_STATE, *PSYSTEM_HANDLE_STATE;