句柄
Windows支持的句柄是一个索引,指向该句柄所在进程的句柄表中的一个表项。例如,在C运行库中,文件操作使用句柄来表示,每当应用程序创建或打开一个文件时,只要此创建或打开操作成功,则C运行库返回一个句柄。以后应用程序对文件的读写操作都使用此句柄来标示该文件。
handle是一个32位的数,其中2~10位表示0级表的索引,11~20位表示1级表的索引,21~30位表示2级表的索引。
struct {
ULONG_PTR TagBits2:2
ULONG_PTR LowIndex:HANDLE_LOW_BITS (2~10)
ULONG_PTR MidIndex:HANDLE_HIGH_BITS (11~20)
ULONG_PTR HighIndex:HANDLE_HIGH_BITS (21~30)
ULONG_PTR KernelFlag:1
};
句柄表
句柄表是一个多层结构。
struct _HANDLE_TABLE{
ULONG_PTR TableCode;
...
}
TableCode域是一个指针,指向句柄表的最高层表项页面,它的低2位的值代表了当前句柄表的层数。也就是说,如果TableCode的最低2位为0,说明句柄表只有一层;如果TableCode的最低2位为1,则说明句柄表有两层;如果TableCode的最低2位为2,则说明句柄表有三层。
句柄表项
struct _HANDLE_TABLE_ENTRY{
PVOID Object;
...
}
Object指针指向句柄所代表的的内核对象,它的最低3位有特别含义:第0位OBJ_PROTECT_CLOSE,表示调用者是否允许关闭该句柄;第1位OBJ_INHERIT指示该进程所创建的子进程是否可以继承该句柄,即是否将该句柄项拷贝到它们的句柄表中;第2位OBJ_AUDIT_OBJECT_CLOSE,指示关闭该对象时是否产生一个审计事件。
将一个句柄解析成相应的内核对象
首先,一个有效的句柄有4中可能:
-1,代表当前进程
-2,代表当前线程
负值,其绝对值为内核句柄表中的索引,即system进程的句柄表
正值,当前进程的句柄表中的索引
下面代码根据TableCode和Handle获得object。
/* 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:
ASSERT(FALSE);
Entry = NULL;
}