天天看點

Windows程序中的句柄表

1  Windows程序中的句柄表

句柄是一個對象引用,同一個對象在不同的環境下可能有不同的引用(句柄)值。句柄僅在一個程序範圍内有效。

HANDLE_TABLE 結構的定義:

typedef struct _HANDLE_TABLE {

    ULONG_PTR TableCode;//指向句柄表的存儲結構

    struct _EPROCESS *QuotaProcess;//句柄表的記憶體資源記錄在此程序中

    HANDLE UniqueProcessId;//建立程序的ID,用于回調函數

    #define HANDLE_TABLE_LOCKS 4

    EX_PUSH_LOCK HandleTableLock[HANDLE_TABLE_LOCKS];//句柄表鎖,僅在句柄表擴充時使用

    LIST_ENTRY HandleTableList;//所有的句柄表形成一個連結清單

    EX_PUSH_LOCK HandleContentionEvent;//連結清單投為全局變量HandleTableListHead

    PHANDLE_TRACE_DEBUG_INFO DebugInfo;//調試資訊,僅當調試句柄時才有意義

    LONG ExtraInfoPages;//審計資訊所占用的頁面數量

    ULONG FirstFree;//空閑連結清單表頭的句柄索引

    ULONG LastFree;//最近被釋放的句柄索引,用于FIFO類型空閑連結清單

    ULONG NextHandleNeedingPool;//下一次句柄表擴充的起始句柄索引

    LONG HandleCount;//正在使用的句柄表項的數量

    union {

        ULONG Flags;//标志域/

        // For optimization we reuse handle values quickly. This can be a problem for

        // some usages of handles and makes debugging a little harder. If this

        // bit is set then we always use FIFO handle allocation.

        BOOLEAN StrictFIFO : 1;//是否使用FIFO風格的重用,即先釋放先重用

    };

} HANDLE_TABLE, *PHANDLE_TABLE;

TableCode : 指向句柄表的最高層表項頁面,低2位的值表示目前句柄表的層數。

如果最低2位為0,說明句柄表隻有1層,最多能容納512個句柄。

如果最低2位為1,說明句柄表有2層,最多能容納512*1024個句柄。

如果最低2位為2,說明句柄表有3層,最多能容納512*1024*1024個句柄。

Windows 程序的句柄表結構

Windows程式中的句柄表

執行體在建立程序時,首先為新程序配置設定一個單層句柄表。由ExCreateHandleTable 函數來完成,該函數調用ExpAllocateHandleTable 來構造初始的句柄表。由函數

ExpAllocateHandleTableEntryShow 來擴充句柄表。代碼見base\ntos\ex\handle.c.

FirstFree : 記錄了目前句柄表中的空閑句柄鍊。通過句柄索引值來連結。

HANDLE_TABLE_ENTRY 結構定義如下:

typedef struct _HANDLE_TABLE_ENTRY {

    union {

        PVOID Object;

        ULONG ObAttributes;

        PHANDLE_TABLE_ENTRY_INFO InfoTable;

        ULONG_PTR Value;

    };

    union {

        union {

            ACCESS_MASK GrantedAccess;

            struct {

                USHORT GrantedAccessIndex;

                USHORT CreatorBackTraceIndex;

            };

        };

        LONG NextFreeTableEntry;

    };

} HANDLE_TABLE_ENTRY, *PHANDLE_TABLE_ENTRY;

Object : 指向句柄所代表的核心對象,最低3位含義:第0 位OBJ_PROTECT_CLOSE,表示調用者是否允許關閉該句柄;第1位OBJ_INHERIT,訓示該程序所建立的子程序是否可以繼承該句柄,即是否将該句柄項拷貝到它們的句柄表中;第2位OBJ_AUDIT_OBJECT_CLOSE,訓示關閉該對象時是否産生一個審計事件

第二個union中,如果句柄表項指向一個有效的對象,則GrantedAccess 記錄了該句柄的通路掩碼;如果這是一個空閑的句柄表項,則NextFreeTableEntry 将加入到句柄表的空閑單連結清單中。

一個有效的句柄有4中可能:-1,表示目前程序;-2表示目前線程;負值,其絕對值為核心句柄表中的索引;不超過226的正值,目前程序的句柄表中的索引。

核心句柄表即系統的全局句柄表,wrk 中即變量ObpKernelHandleTable,也是System 程序的句柄表。解析句柄函數ObReferenceObjectByHandle,見base\ntos\ob\obref.c 。

将一個對象插入到句柄表中的函數是ObInsertObject,見base\ntos\ob\obinsert.c 。

對象的引用有兩種,一種在核心中之間通過對象位址來引用,通過ObReferenceObjectByPoint記錄一次新的引用,第二種,通過句柄來引用對象,通過ObpIncrementHandleCount檢查并記錄一次句柄引用。

在一個句柄上調用了ObReferenceObjectByHandle後,若該對象不在使用,必須調用ObDereferenceObject 函數。

程序唯一ID,即UniqueProcessId;線程有一個CLIENT_ID成員Cid,包含了所屬程序的唯一ID和線程的唯一ID。