標籤:
談windows中的控制代碼
每當一個進程開啟一個對象,系統就返回一個控制代碼作為憑證,由此可以想到,控制代碼是依賴於具體的進程的,換句話說,控制代碼一定屬於某個進程,以後在訪問這個對象時就要使用這個憑證! 所以控制代碼還可以認為是一個進程和一個對象之間建立的一種串連,一座橋樑,一個上下文,就像一個門一樣,已經開啟。這種串連就持續存在,直到關閉。一個進程可開啟對個對象,就會擁有多個控制代碼,所以每個進程都擁有一個控制代碼表,在進程式控制制塊EPROCESS中有個指標ObjectTable是_HANDLE_TABLE類型,指向本進程的控制代碼表!看下_HANDLE_TABLE結構:
1 kd> dt _handle_table 2 nt!_HANDLE_TABLE 3 +0x000 TableCode : Uint4B 4 +0x004 QuotaProcess : Ptr32 _EPROCESS 5 +0x008 UniqueProcessId : Ptr32 Void 6 +0x00c HandleLock : _EX_PUSH_LOCK 7 +0x010 HandleTableList : _LIST_ENTRY //控制代碼表雙向鏈表 8 +0x018 HandleContentionEvent : _EX_PUSH_LOCK 9 +0x01c DebugInfo : Ptr32 _HANDLE_TRACE_DEBUG_INFO10 +0x020 ExtraInfoPages : Int4B11 +0x024 Flags : Uint4B12 +0x024 StrictFIFO : Pos 0, 1 Bit13 +0x028 FirstFreeHandle : Uint4B14 +0x02c LastFreeHandleEntry : Ptr32 _HANDLE_TABLE_ENTRY15 +0x030 HandleCount : Uint4B16 +0x034 NextHandleNeedingPool : Uint4B17 +0x038 HandleCountHighWatermark : Uint4B
TableCode的低兩位被用作標誌位,用於表示當前控制代碼表的級數,0,1,2分別表示一級表,二級表,三級表。
一級表實際上是一個_HANDLE_TABLE_ENTRY 數組,每個_HANDLE_TABLE_ENTRY 8個位元組,而一級表是一個page的大小,所以一級表可以容納2^9個_HANDLE_TABLE_ENTRY
1 lkd> dt _HANDLE_TABLE_ENTRY 2 nt!_HANDLE_TABLE_ENTRY 3 +0x000 Object : Ptr32 Void//指向對象的一個指標 4 +0x000 ObAttributes : Uint4B 5 +0x000 InfoTable : Ptr32 _HANDLE_TABLE_ENTRY_INFO 6 +0x000 Value : Uint4B 7 +0x004 GrantedAccess : Uint4B 8 +0x004 GrantedAccessIndex : Uint2B 9 +0x006 CreatorBackTraceIndex : Uint2B10 +0x004 NextFreeTableEntry : Uint4B
而控制代碼以4為步進(
注0),因此最大控制代碼為0x200*4=0x800.其中可存放的最大控制代碼不超過0x800(最大為0x800-4),而每個一級表的第一個HANDLE_TABLE_ENTRY的Object總是為0,因為我們都知道0是一個無效的控制代碼,它不指向一個有效對象。因此,每個一級表實際存放的控制代碼數為511個!
_HANDLE_TABLE結構中有個TableCode欄位,該欄位有32位,低2位作為標記是幾級表,0為一級,1為2級,2為3級。當為0時,TableCode值就指向一個Page,此頁就是控制代碼表,每個表項8個位元組為一個entry,低4個位元組是對象地址,注意第一個entry不代表任何對象。若TableCode前兩位為1或者2,那麼TableCode&0xfffffffd就指向二級或者三級表,每個表項四個位元組,指向一個一級或者二級表,以此類推!!注意:由於對象體都是8位元組對齊的,所以對象地址的低3位總是0,可用於標記對象的某些屬性,所以在一級控制代碼表中的對象地址要&0xfffffff8才表示對象頭的地址,加上0x18後得到對象體(這裡涉及到windows核心中對象的管理,參見另一篇關於對象的文章)!控制代碼表架構:
至於為什麼控制代碼表的號都是4的倍數呢?
一個進程的控制代碼表包含了所有已被該進程開啟的那些對象的指標。物件控點是用來檢索控制代碼表的一個“虛擬索引”。對於控制代碼表機制,achillis <<Windows控制代碼表>>系列文章已經分析得很透徹了,只是對“控制代碼以4為步進”來源不明。經查,根源如下:
typedef struct _EXHANDLE
{
union
{
struct
{
ULONG TagBits:2;
ULONG Index:30;
}
HANDLE GenericHandleOverlay;
#define HANLE_VALUE_INC 4
ULONG_PTR Value;
}
}EXHANDLE,*PEXHANDLE;
此結構正是用來定義控制代碼類型。低2位TagBits為標誌位Windows用於其它用途,故控制代碼值低2位對其作為控制代碼表索引本身無意義,所以等於4的倍數。有了以上分析,自然,在用控制代碼值為索引取控制代碼表項時,控制代碼值必須/4。因此程式中用到的控制代碼值並不能直接用來索引控制代碼表,也就有了“虛擬索引”說法。
談windows中的控制代碼