windows handle manager
来源:互联网 发布:免费商业源码分享 编辑:程序博客网 时间:2024/05/23 11:19
前导
reactos 句柄的设计位于ex执行体中,一般情况下句柄的使用都或多或少的伴随着对象的使用。目前认为句柄是用户层对系统层引用。
内核句柄表的创建
/* Create kernel handle table */ PsGetCurrentProcess()->ObjectTable = ExCreateHandleTable(NULL); ObpKernelHandleTable = PsGetCurrentProcess()->ObjectTable;
在内核对象管理器初始化时即ObInitSystem,在这个函数中,我们创建了内核句柄表,使用ExCreateHandleTable函数,这个函数返回句柄表的指针。并将内核句柄表设置成ob管理器句柄表全局结构。
PHANDLE_TABLENTAPIExCreateHandleTable(IN PEPROCESS Process OPTIONAL)
这个函数返回句柄表,先是调用ExpAllocateHandleTable来申请句柄,然后将这个句柄表插入到HandleTableListHead全局句柄表中。接着我们来看内部函数如何来分配句柄表。
PHANDLE_TABLENTAPIExpAllocateHandleTable(IN PEPROCESS Process OPTIONAL, IN BOOLEAN NewTable){ PHANDLE_TABLE HandleTable; PHANDLE_TABLE_ENTRY HandleTableTable, HandleEntry; ULONG i; PAGED_CODE(); /* Allocate the table */ HandleTable = ExAllocatePoolWithTag(PagedPool, sizeof(HANDLE_TABLE), TAG_OBJECT_TABLE); if (!HandleTable) return NULL; /* Check if we have a process */ if (Process) { /* FIXME: Charge quota */ } /* Clear the table */ RtlZeroMemory(HandleTable, sizeof(HANDLE_TABLE)); /* Now allocate the first level structures */ HandleTableTable = ExpAllocateTablePagedPoolNoZero(Process, PAGE_SIZE); if (!HandleTableTable) { /* Failed, free the table */ ExFreePoolWithTag(HandleTable, TAG_OBJECT_TABLE); return NULL; } /* Write the pointer to our first level structures */ HandleTable->TableCode = (ULONG_PTR)HandleTableTable; /* Initialize the first entry */ HandleEntry = &HandleTableTable[0]; HandleEntry->NextFreeTableEntry = -2; HandleEntry->Value = 0; /* Check if this is a new table */ if (NewTable) { /* Go past the root entry */ HandleEntry++; /* Loop every low level entry */ for (i = 1; i < (LOW_LEVEL_ENTRIES - 1); i++) { /* Set up the free data */ HandleEntry->Value = 0; HandleEntry->NextFreeTableEntry = (i + 1) * SizeOfHandle(1); /* Move to the next entry */ HandleEntry++; } /* Terminate the last entry */ HandleEntry->Value = 0; HandleEntry->NextFreeTableEntry = 0; HandleTable->FirstFree = SizeOfHandle(1); } /* Set the next handle needing pool after our allocated page from above */ HandleTable->NextHandleNeedingPool = LOW_LEVEL_ENTRIES * SizeOfHandle(1); /* Setup the rest of the handle table data */ HandleTable->QuotaProcess = Process; HandleTable->UniqueProcessId = PsGetCurrentProcess()->UniqueProcessId; HandleTable->Flags = 0; /* Loop all the handle table locks */ for (i = 0; i < 4; i++) { /* Initialize the handle table lock */ ExInitializePushLock(&HandleTable->HandleTableLock[i]); } /* Initialize the contention event lock and return the lock */ ExInitializePushLock(&HandleTable->HandleContentionEvent); return HandleTable;}
在这个函数中我们首先为HandleTable申请空间,函数返回后会将其记录在进程结构体EPROCESS中,进程通过这个结构体内部成员就可以获取到句柄表。
然后我们会相应的填写HandleTable内部数据,来描述当前的进程句柄表的情况如上图所示。其结构如下:
typedef struct _HANDLE_TABLE{#if (NTDDI_VERSION >= NTDDI_WINXP) ULONG_PTR TableCode;#else PHANDLE_TABLE_ENTRY **Table;#endif PEPROCESS QuotaProcess; PVOID UniqueProcessId;#if (NTDDI_VERSION >= NTDDI_WINXP) EX_PUSH_LOCK HandleTableLock[4]; LIST_ENTRY HandleTableList; EX_PUSH_LOCK HandleContentionEvent;#else ERESOURCE HandleLock; LIST_ENTRY HandleTableList; KEVENT HandleContentionEvent;#endif PHANDLE_TRACE_DEBUG_INFO DebugInfo; LONG ExtraInfoPages;#if (NTDDI_VERSION >= NTDDI_LONGHORN) union { ULONG Flags; UCHAR StrictFIFO:1; }; LONG FirstFreeHandle; PHANDLE_TABLE_ENTRY LastFreeHandleEntry; LONG HandleCount; ULONG NextHandleNeedingPool;#else ULONG FirstFree; ULONG LastFree; ULONG NextHandleNeedingPool; LONG HandleCount; union { ULONG Flags; UCHAR StrictFIFO:1; };#endif} HANDLE_TABLE, *PHANDLE_TABLE;
然后我们首先为一级表申请空间 HandleTableTable = ExpAllocateTablePagedPoolNoZero(Process, PAGE_SIZE);很显然我们创建了一页句柄表,得到页的开始地址。这个HandleTableTable是一个如下结构的表项。
typedef struct _HANDLE_TABLE_ENTRY{ union { PVOID Object; ULONG_PTR ObAttributes; PHANDLE_TABLE_ENTRY_INFO InfoTable; ULONG_PTR Value; }; union { ULONG GrantedAccess; struct { USHORT GrantedAccessIndex; USHORT CreatorBackTraceIndex; }; LONG NextFreeTableEntry; };} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;
当一级表满时,我们接着创建二级表。会在HandleTable中记录下指向。
/* Write the pointer to our first level structures */ HandleTable->TableCode = (ULONG_PTR)HandleTableTable;
我们在申请的一级表中弄一块空间,由HANDLE_TABLE_ENTRY定义,这是一个句柄表项,于是我们初始化这个表项,填写一些值。
然后在EXPROCESS中的handleTable中记录一些值,这些值记录着改变。
申请句柄前期准备工作
当我们创建进程时,有一个时间我们要在全局Cid中创建进程的CID句柄,以这个为例,我们来学习在句柄表中如何创建得到一个句柄。
Process->UniqueProcessId = ExCreateHandle(PspCidTable, &CidEntry);
ExCreateHandle的定义如下,在指定的句柄表中创建句柄。
HANDLENTAPIExCreateHandle(IN PHANDLE_TABLE HandleTable, IN PHANDLE_TABLE_ENTRY HandleTableEntry)
函数内部使用ExpAllocateHandleTableEntry来申请句柄表项。
/* Allocate a new entry */ NewEntry = ExpAllocateHandleTableEntry(HandleTable, &Handle);
我们首先介绍一下关于句柄的一些数据结构,然后介绍申请句柄时的逻辑。
ex执行体中我们使用EXHANDLE来表示一个句柄
typedef union _EXHANDLE{ struct { ULONG_PTR TagBits:2; ULONG_PTR Index:29; }; struct { ULONG_PTR TagBits2:2; ULONG_PTR LowIndex:HANDLE_LOW_BITS; ULONG_PTR MidIndex:HANDLE_HIGH_BITS; ULONG_PTR HighIndex:HANDLE_HIGH_BITS; ULONG_PTR KernelFlag:KERNEL_FLAG_BITS; }; HANDLE GenericHandleOverlay; ULONG_PTR Value;} EXHANDLE, *PEXHANDLE;
而应用层我们定义句柄如下:
/* Handle Type */typedef void *HANDLE, **PHANDLE;
应用层的句柄定义竟如此简单,以至于我们一直疑惑句柄的意义和价值。 而ex中也仅仅是将Handle.GenericHandleOverlay赋值给HANDLE
而在具体句柄表中申请句柄项,其申请函数如下。
PHANDLE_TABLE_ENTRYNTAPIExpAllocateHandleTableEntry(IN PHANDLE_TABLE HandleTable, OUT PEXHANDLE NewHandle)
检查空闲句柄:
1.首先检查句柄表是否有空闲。
2.如果没有空闲项剩余,就锁定表再检查一下
3.如果还是没有,移除空闲句柄,使得剩余出可用句柄
4.如果还是没有,我们调用ExpAllocateHandleTableEntrySlow来实际申请句柄
最后我们记录下得到的句柄 Handle.Value = (OldValue & FREE_HANDLE_MASK);
使用这个句柄值查询句柄表 Entry = ExpLookupHandleTableEntry(HandleTable, Handle);,获得对应的句柄项。之后递增句柄表的句柄数目,返回句柄。
实际的句柄申请函数
BOOLEAN NTAPIExpAllocateHandleTableEntrySlow(IN PHANDLE_TABLE HandleTable, IN BOOLEAN DoInit){ ULONG i, j, Index; PHANDLE_TABLE_ENTRY Low = NULL, *Mid, **High, *SecondLevel, **ThirdLevel; ULONG NewFree, FirstFree; PVOID Value; ULONG_PTR TableCode = HandleTable->TableCode; ULONG_PTR TableBase = TableCode & ~3; ULONG TableLevel = (ULONG)(TableCode & 3); PAGED_CODE(); /* Check how many levels we already have */ if (TableLevel == 0) { /* Allocate a mid level, since we only have a low level */ Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low); if (!Mid) return FALSE; /* Link up the tables */ Mid[1] = Mid[0]; Mid[0] = (PVOID)TableBase; /* Write the new level and attempt to change the table code */ TableBase = ((ULONG_PTR)Mid) | 1; Value = InterlockedExchangePointer((PVOID*)&HandleTable->TableCode, (PVOID)TableBase); } else if (TableLevel == 1) { /* Setup the 2nd level table */ SecondLevel = (PVOID)TableBase; /* Get if the next index can fit in the table */ i = HandleTable->NextHandleNeedingPool / SizeOfHandle(LOW_LEVEL_ENTRIES); if (i < MID_LEVEL_ENTRIES) { /* We need to allocate a new table */ Low = ExpAllocateLowLevelTable(HandleTable, DoInit); if (!Low) return FALSE; /* Update the table */ Value = InterlockedExchangePointer((PVOID*)&SecondLevel[i], Low); ASSERT(Value == NULL); } else { /* We need a new high level table */ High = ExpAllocateTablePagedPool(HandleTable->QuotaProcess, SizeOfHandle(HIGH_LEVEL_ENTRIES)); if (!High) return FALSE; /* Allocate a new mid level table as well */ Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low); if (!Mid) { /* We failed, free the high level table as welll */ ExpFreeTablePagedPool(HandleTable->QuotaProcess, High, SizeOfHandle(HIGH_LEVEL_ENTRIES)); return FALSE; } /* Link up the tables */ High[0] = (PVOID)TableBase; High[1] = Mid; /* Write the new table and change the table code */ TableBase = ((ULONG_PTR)High) | 2; Value = InterlockedExchangePointer((PVOID*)&HandleTable->TableCode, (PVOID)TableBase); } } else if (TableLevel == 2) { /* Setup the 3rd level table */ ThirdLevel = (PVOID)TableBase; /* Get the index and check if it can fit */ i = HandleTable->NextHandleNeedingPool / SizeOfHandle(MAX_MID_INDEX); if (i >= HIGH_LEVEL_ENTRIES) return FALSE; /* Check if there's no mid-level table */ if (!ThirdLevel[i]) { /* Allocate a new mid level table */ Mid = ExpAllocateMidLevelTable(HandleTable, DoInit, &Low); if (!Mid) return FALSE; /* Update the table pointer */ Value = InterlockedExchangePointer((PVOID*)&ThirdLevel[i], Mid); ASSERT(Value == NULL); } else { /* We have one, check at which index we should insert our entry */ Index = (HandleTable->NextHandleNeedingPool / SizeOfHandle(1)) - i * MAX_MID_INDEX; j = Index / LOW_LEVEL_ENTRIES; /* Allocate a new low level */ Low = ExpAllocateLowLevelTable(HandleTable, DoInit); if (!Low) return FALSE; /* Update the table pointer */ Value = InterlockedExchangePointer((PVOID*)&ThirdLevel[i][j], Low); ASSERT(Value == NULL); } } else { /* Something is really broken */ ASSERT(FALSE); } /* Update the index of the next handle */ Index = InterlockedExchangeAdd((PLONG) &HandleTable->NextHandleNeedingPool, SizeOfHandle(LOW_LEVEL_ENTRIES)); /* Check if need to initialize the table */ if (DoInit) { /* Create a new index number */ Index += SizeOfHandle(1); /* Start free index change loop */ for (;;) { /* Setup the first free index */ FirstFree = HandleTable->FirstFree; Low[LOW_LEVEL_ENTRIES - 1].NextFreeTableEntry = FirstFree; /* Change the index */ NewFree = InterlockedCompareExchange((PLONG) &HandleTable->FirstFree, Index, FirstFree); if (NewFree == FirstFree) break; } } /* All done */ return TRUE;}
这函数来实际申请一个句柄,函数中根据需要创建一级和二级或是三级句柄表,然后设置空闲句柄项。
根据句柄值获得句柄项
比较简单,使用handle中的索引,按着句柄表看是三级二级或是一级查询即可
PHANDLE_TABLE_ENTRYNTAPIExpLookupHandleTableEntry(IN PHANDLE_TABLE HandleTable, IN EXHANDLE Handle){ ULONG TableLevel; ULONG_PTR TableBase; PHANDLE_TABLE_ENTRY HandleArray, Entry; PVOID *PointerArray; /* Clear the tag bits */ Handle.TagBits = 0; /* Check if the handle is in the allocated range */ if (Handle.Value >= HandleTable->NextHandleNeedingPool) { return NULL; } /* Get the table code */ TableBase = HandleTable->TableCode; /* Extract the table level and actual table base */ TableLevel = (ULONG)(TableBase & 3); TableBase &= ~3; PointerArray = (PVOID*)TableBase; HandleArray = (PHANDLE_TABLE_ENTRY)TableBase; /* Check what level we're running at */ switch (TableLevel) { case 2: /* Get the mid level pointer array */ PointerArray = PointerArray[Handle.HighIndex]; /* Fall through */ case 1: /* Get the handle array */ HandleArray = PointerArray[Handle.MidIndex]; /* Fall through */ case 0: /* Get the entry using the low index */ Entry = &HandleArray[Handle.LowIndex]; /* All done */ break; default: NT_ASSERT(FALSE); Entry = NULL; } /* Return the handle entry */ return Entry;}
- windows handle manager
- Windows中的句柄(handle)
- windows handle之DuplicateHandle
- windows handle msg
- WINDOWS HANDLE null INVALID_HANDLE_VALUE
- Windows HANDLE是什么
- Windbg调试windows handle泄漏
- FireMonkey的窗口Handle转为Windows窗口的Handle
- FireMonkey的窗口Handle转为Windows窗口的Handle
- Windows Heap Manager
- windows qemu manager
- Credential manager of windows
- windows config manager
- windows message manager
- windows Heap manager
- windows Object Manager
- handle
- HANDLE
- Secure REST API with oauth2 (翻译)
- 开播啦
- Linux C 获取当前应用程序的绝对路径
- 开播啦
- 开播啦
- windows handle manager
- 909422229__Android UI基础之二【本人总结,适用于新手】
- 物化视图(Materialized View)优化
- 开播啦
- Unity3D 5.4.0 终于可以使用protobuff 3.0.0了
- 开播啦
- 开播啦
- Softmax回归
- 开播啦