標籤:script hashtable desc uniq 核心 記錄 reserve int while
WINDOWS核心對象
一.前言
Windows中有很多像進程對象、線程對象、檔案對象等等這樣的對象,我們稱之為Windows核心對象。核心對象是系統地址空間中的一個記憶體塊,由系統建立並維護。核心對象為核心所擁有,而不為進程所擁有,所以不同進程可以訪問同一個核心對象。
二.核心對象結構
每個對象都有對象頭和對象體組成。所有類型的對象頭結構都是相同的,而結構體部分卻各不相同的。下面是核心對象的結構圖:
核心對象結構圖
圖中灰色部分是可能出現的。每個對象中是否存在這些部分主要由OBJECT_HEADER結構中的相關標誌來指定。上面的5個結構的格式是固定的;而OBJECT結構體部分卻是各個對象各不同的。需要注意的是:指向對象的指標POBJECT是指向對象體部分,而不是指向對象頭的。所以,若需要訪問OBJECT_HEADER,需要將POBJCECT減去0x18而獲得。
下面是OBJECT_HEADER的結構
typedef struct _OBJECT_HEADER { DWORD PointerCount; // 指標引用的數目 DWORD HandleCount; // 開啟控制代碼的數目 POBJECT_TYPE ObjectType; //指向類型對象的指標 BYTE NameOffset; //對象名的位移 BYTE HandleDBOffset; // HANDLE DB的位移 BYTE QuotaChargesOffset; //QUOTA CHARGES的位移 BYTE ObjectFlags; // 對象標誌 union { // 對象標誌中OB_FLAG_CREATE_INFO ? ObjectCreateInfo : QuotaBlock PQUOTA_BLOCK QuotaBlock; POBJECT_CREATE_INFO ObjectCreateInfo; }; PSECURITY_DESCRIPTOR SecurityDescriptor; }OBJECT_HEADER, *POBJECT_HEADER; |
三.目錄對象
WINDOWS中有20幾類無數的核心對象,它們都獨立地存在於系統地址空間中。系統利用目錄對象將所有的這些對象組織起來。目錄對象是一個有37個數組元素組成的雜湊(HASH)樹。資料結構如下:
Typedef struct _OBJECT_DIRECTORY_ENTY { Struct _OBJECT_DIRECTORY_ENTRY *NextEntry; POBJECT Object }OBJECT_DIRECTORY_ENTRY, *POBJECT_DIRECTORY_ENTRY,**PPOBJECT_DIRECTORY_ENTRY; Typedef struct _OBJECT_DIRECTORY { POBJECT_DIRECTORY_ENTRY HashTable[37]; POBJECT_DIRECTORY_ENTRY CurrentEntry; BOOLEAN CurrentEntryValid; BYTE Reserved1; WORD Reserved2; DWORD Reserved3; }OBJECT_DIRECTORY, *POBJECT_DIRECTORY; |
系統將對象名稱進行一定的演算法得出一個HASH值,演算法如下:
//根據名字計算HASH值。 hash = 0; p = (PSHORT)wStr; //存放名稱的一個WCHAR數組 while(*p) { Symb = (CHAR)*p; hash = hash * 3 + (hash >> 1); if (Symb < ‘a‘) //<a hash= hash + Symb; else if (Symb <= ‘z‘) //即 a~z hash = hash + Symb - 0x20; else // > z hash = hash + (CHAR)RtlUpcaseUnicodeChar((WCHAR)*p); p ++; } hash = hash % 37; //最終的hash值。 |
系統將所有相同HASH值的對象連結到響應的數組項中,於是系統中所有元素將排列成如下的結構圖:
系統根目錄的對象的指標由ObpRootDirectoryObject來指定。
按理說,系統中只需要一個目錄對象就夠了,系統中所有的核心對象都將連結在這個目錄對象上。但是不知什麼原因,系統中並不是這樣,系統中存在著多個目錄對象,它們以根目錄對象為根,組成一個“對象樹”。每個目錄對象中的雜湊樹的hash值的計算規則都是一樣的。
我們可以根據系統中“對象樹”的結構來遍曆系統中所有的對象。
四.類型對象
核心對象中還有一種比較特殊的對象——類型對象。系統中每種類型對象只有一個類型對象,也就是說,系統中最多隻有20幾個類型對象。每種類型的對象都在其對象體中存在一個指向其類型對象的指標,因為一種類型對象只有一個實體,所以每種類型對象的指標都是固定的,這樣我們就可以通過對象體中的類型對象指標來判斷和訪問對象的類型了。
各個類型對象的對象體內並沒有鏈表結構使得它們相互連結起來。但是假如對象頭部前面有OBJECT_CREATOR_INFO結構(見下表),則相同類型的對象就可以通過它的成員ObjectList相互連結起來了。但是,不幸的是:預設情況下,只有Port和WaitPort兩中類型的對象有這種結構。所以一般情況下,我們是不能通過類型對象來遍曆這個系統中所有對象的。
typedef struct _OBJECT_CREATOR_INFO { LIST_ENTRY ObjectList; // OBJECT_CREATOR_INFO HANDLE UniqueProcessId; WORD Reserved1; WORD Reserved2; }OBJECT_CREATOR_INFO, *POBJECT_CREATOR_INFO, **PPOBJECT_CREATOR_INFO; |
五.對象的遍曆
上面分析過了,下面可以目錄對象的遍曆,來進行系統中所有對象的遍曆。
//寫一個遞迴函式。用來分析樹型目錄。 void AnalyseDirectory(POBJECT_DIRECTORY pDirectory, ULONG DirectoryType, int Level) { POBJECT_DIRECTORY_ENTRY pDirectoryEntry; POBJECT_HEADER pObjectHeader; POBJECT_NAME pObjectName; PWCHAR wStr[200]; char Space[100]; //為產生空格用的。 int i, j; for(i = 0; i < 36; i ++) //DIR對象的對象體(BODY)是37個元素的數組。 { pDirectoryEntry = pDirectory->HashTable[i]; while(pDirectoryEntry) { pObjectHeader = (POBJECT_HEADER)((ULONG)pDirectoryEntry->pObject - sizeof(OBJECT_HEADER)); //產生空格 RtlZeroMemory(Space, 100); for(j = 0; j < 5 * Level; j ++) Space[j] = ‘ ‘; if (pObjectHeader->NameOffset) { pObjectName = (POBJECT_NAME)((ULONG)pObjectHeader - pObjectHeader->NameOffset); RtlZeroMemory(wStr, 200 * sizeof(WCHAR)); RtlCopyMemory(wStr, pObjectName->Name.Buffer, pObjectName->Name.Length); DbgPrint("%s pObject: 0x%08X Name: %S", Space, pDirectoryEntry->pObject, wStr); } else DbgPrint("%s pObject: 0x%08X Name: noname", Space, pDirectoryEntry->pObject); //pObject對象是屬性對象嗎 if ((ULONG)pObjectHeader->pObjectType == DirectoryType) AnalyseDirectory(pDirectoryEntry->pObject, DirectoryType, Level + 1); pDirectoryEntry = pDirectoryEntry->NextEntry; } }//end of 遍曆37個記錄 } |
六.對象的訪問
核心中知道了核心對象的地址就可以直接存取這個核心對象了,但是在使用者程式中卻不能這樣訪問。Windows為核心對象的訪問提供了一系列的函數。當調用一個用於建立核心對象的函數時,函數調用完便返回一個控制代碼值。控制代碼值是進程獨立的,一個進程中的控制代碼值在另一個進程中是無效的。
控制代碼值是一個進程控制代碼表的索引。每個進程都有一個進程控制代碼表,而所有進程的控制代碼表串成一個控制代碼錶鏈。這個鏈的頭部地址儲存在核心變數HandleTableListHead中。
下面具體看一下控制代碼表結構。系統將控制代碼表組織成和線性位址解析一樣的結構。控制代碼表是個三層的表結構,而控制代碼值也被分成三部分,用來分別索引這三個部分。下面是控制代碼解析圖:
七.總結
本文可以說是一個讀書筆記。在參考了很多文章的基礎上,然後作一些實驗才完成本文的。核心對象是Windows內部的重要資料結構。通過本文可以大致瞭解Windows是如何組織眾多的對象的。
八.參考
1.《Undocumented Windows 2000 Secrets》
2.Anathema《Inside Windows Nt Object Manager》
3.webcrazy《剖析Windows NT/2000核心對象組織》
4.《Inside Windows 2000》
5.《Windows核心編程》
注意:本節描述的控制代碼是再WIN2K下的控制代碼.WINXP下控制代碼表結構已經完全不同.
WINDOWS核心對象