Windows對象管理

對象管理是Windows Executive的一個子系統實現，用於管理Windows資源。資源包括物理設備、文件、文件目錄、註冊表條目、正在運行的進程等等。所有子系統訪問資源都必須通過對象管理子系統。

## 體系結構

Windows NT作業系統體系結構中，對象管理子系統管理所有的資源。資源被表示為對象。對象管理子系統保持著對每個對象的引用計數。任何訪問對象的系統調用都必須通過對象管理子系統。Windows對象可分為內核對象、使用者對象、GDI對象：

- 使用者對象（User interface object）：支持窗口管理。每個對象僅有一個句柄，句柄不能複製或繼承，不能引用其他使用者會話中的進程的使用者句柄。任何進程只要有對某個使用者句柄的安全訪問權限，即可以訪問該使用者對象，即使用者對象在當前會話下是全局的。一個進程最多有 65536 個使用者對象句柄。使用者對象包括：快捷鍵表HACCEL、插入點HCaret、滑鼠指針HCURSOR、DDE 會話、窗口鉤子HOOK、圖標 HICON、菜單 HMENU、窗口 HWND、窗口位置Window position。
- GDI 對象：支持圖形。每個對象僅有一個句柄，句柄為進程私有。一個進程最多有 65536 個 GDI 對象句柄。GDI 對象包括：位圖 HBITMAP、畫刷 HBRUSH、設備環境HDC、增強型圖元文件（EMF）、EMF 設備環境、字體 HFONT、記憶體 DC、圖元文件Metafile、圖元文件 DC、調色板 HPALETTE、畫筆 HPEN、區域（Region）HRGN。
- 內核對象：支持記憶體管理、進程執行、進程間通信。內核對象句柄是進程私有的，必須創建或者打開內核對象以獲取其句柄。當進程創建或打開內核對象時，進程的句柄表中增加一個條目指向內核對象實例。進程的句柄表的索引稱為句柄（handle）。對象管理子系統使用句柄與命名兩種方式管理對象實例。句柄在一個進程內部是線程共享的，但在進程之間不是直接可復用，需要特別方式在進程間傳遞對象句柄。一個進程任何時刻最多擁有 224，即大約 16,000,000 個句柄。句柄按照對象的分類可分為文件句柄、事件句柄、進程句柄等。一個進程對一個對象可以有多個句柄，以便按照不同權限來訪問對象。

對象可分為內核對象（Kernel objects）與執行對象（Executive objects）。內核對象表示一些基本資源，如物理設備、同步服務等等。使用者態的程序不能訪問內核對象。使用者態的系統服務與應用程式使用執行對象，這是Windows Executive對外暴露的對象，用來封裝一個或多個內核對象。執行對象還用於實現 NT 子系統或 POSIX 子系統的一些功能。

Windows NT 暴露的執行對象包括:

類別｜描述｜創建 / 獲取句柄系統調用｜創建 / 獲取句柄函數｜釋放句柄函數｜未通知狀態｜通知狀態｜等待成功的副作用

目錄｜用來存放內核對象。多級嵌套的目錄將所有內核對象組織成一個樹形結構｜NtCreateDirectoryObjectNtOpenDirectoryObject｜無

進程｜線程的集合，擁有共同的虛擬內存空間與控制資訊｜NtCreateProcessNtOpenProcess｜CreateProcessOpenProcessGetCurrentProcess｜CloseHandleTerminateProcess｜進程仍然活動時｜進程終止運行時（TerminateProcessExitProcess）｜無

線程｜進程內部，執行程序的實體。｜NtCreateThreadNtOpenThread｜CreateThreadCreateThreadExOpenThreadGetCurrentThread｜CloseHandleTerminateThread｜線程仍然活動時｜線程終止運行時（TerminateThreadExitThread）｜無

作業｜進程的集合｜NtCreateJobObjectNtOpenJobObject｜CreateJobObject｜CloseHandle｜當作業的時間尚未結束時｜當作業的時間已經結束時｜無

文件｜一個打開的電腦文件或 I/O 設備。｜NtCreateFileNtOpenFile｜CreateFile｜CloseHandleDeleteFile｜當 I/O 請求正在處理時｜當 I/O 請求處理完畢時｜無

文件映射對象｜一塊記憶體區域，映射到一個文件。｜NtCreateSectionNtOpenSection｜CreateFileMapping｜CloseHandle

訪問令牌｜一個對象的訪問權。｜NtCreateTokenNtDuplicateTokenNtOpenProcessTokenNtOpenThreadToken｜CreateRestrictedTokenDuplicateTokenDuplicateTokenExOpenProcessTokenOpenThreadToken｜CloseHandle

事件｜封裝了某些資訊的一個對象，用於通知某些進程。｜NtCreateEventNtOpenEvent｜CreateEventCreateEventExOpenEvent｜CloseHandle｜ResetEvent，或 PulseEvent，或自動重置事件等待成功｜當調用 SetEvent，或 PulseEvent｜自動重置事件等待成功後將自動重置

信號量｜用於串行化訪問某些資源的對象。｜NtCreateSemaphoreNtOpenSemaphore｜CreateSemaphoreCreateSemaphoreExOpenSemaphore｜CloseHandle｜當數量 0 時（ReleaseSemaphore）｜數量減 1

互斥鎖｜用於串行化訪問某些資源的對象。｜無｜CreateMutexCreateMutexExOpenMutex｜CloseHandle｜被其他線程擁有時｜未被其他線程擁有時｜等待成功的線程獲得 CPU 所有權

臨界區域｜使得指定的代碼段被串行執行｜無｜InitializeCriticalSectionInitializeCriticalSectionAndSpinCount｜DeleteCriticalSection｜被其他線程擁有時（試圖 EnterCriticalSection）｜未被其他線程擁有時（LeaveCriticalSection）｜等待成功的線程獲得 CPU 所有權

定時器｜按照固定時間間隔通知某些進程的對象。｜NtCreateTimerNtOpenTimer｜CreateWaitableTimerCreateWaitableTimerEx｜CloseHandle｜CancelWaitableTimer 或自動重置定時器等待成功｜當時間到時（SetWaitableTimer）｜自動重置定時器等待成功將 reset

Timer queue｜無

Timer-queue timer｜無

註冊表鍵值｜Windows 註冊表條目的鍵值，數據類型不是 HANDLE 而是 HKEY｜RegCreateKeyExRegOpenKeyEx｜RegCloseKey

桌面｜包含 GUI 元素的一個邏輯顯示面，數據類型是 HDESK｜無｜CreateDesktopOpenDesktopGetThreadDesktop｜CloseDesktop

WindowStation｜包含一些桌面對象、一塊剪貼板對象、以及其他對象的對象，數據類型是 HWINSTA｜無｜CreateWindowStationOpenWindowStationGetProcessWindowStation｜CloseWindowStation

剪貼板｜用於其它對象的臨時存儲空間。｜無｜OpenClipboard｜CloseClipboard

符號連結｜對其他對象的引用｜NtCreateSymbolicLinkObjectNtOpenSymbolicLinkObject

事件日誌｜無｜OpenEventLogRegisterEventSourceOpenBackupEventLog｜CloseEventLog

目錄下更改通知｜若指定的目錄下發生了文件名、屬性等更改，則喚起本事件｜FindFirstChangeNotification｜FindCloseChangeNotification｜沒有發生指定監視類型的修改｜發生了指定監視類型的修改｜重置事件狀態；若需要監視下一次更改，使用循環搭配 FindNextChangeNotification

堆記憶體｜無｜HeapCreateGetProcessHeapGetProcessHeaps｜HeapDestroy不應釋放進程的預設堆

I/O 完成埠｜NtCreateIoCompletionNtOpenIoCompletion｜CreateIoCompletionPort｜CloseHandle

Mailslot｜NtCreateMailslotFile｜CreateMailslot｜CloseHandle

記憶體資源通知｜CreateMemoryResourceNotification｜CloseHandle

模塊｜只有自己 LoadLibrary 加載的 DLL 才需要釋放；數據類型為 HMODULE；WinMain 函數的 hInstance 參數是指向 EXE 主程序的 HMODULE（數據類型為 HINSTANCE）｜無｜LoadLibraryLoadLibraryExGetModuleHandleGetModuleHandleExWinMain 函數的 hInstance 參數｜FreeLibrary

管道｜管道可以是雙工（雙向傳輸）的；創建管道的一方稱為服務端，連接到已存在或將要存在的管道的一方稱為客戶端｜NtCreateNamedPipeFile｜CreateNamedPipeCreatePipeCreateFile｜CloseHandleDisconnectNamedPipe

套接字｜Unix 下的套接字只是普通 fd，而 Windows 下的套接字一般而言和普通（文件系統）文件不一樣，推薦使用專門的套接字 API 操作；數據類型是 SOCKET（UINT_PTR）｜無｜WSASocketWSAAccept｜closesocket｜與文件類似

資源更新｜使用 UpdateResource 更新某個 PE 模塊中的資源（Resource，包括字串、圖標等）｜無｜BeginUpdateResource｜EndUpdateResource

### 對象結構

每個被對象管理子系統所管理的對象，包含頭部和體部。頭部是對象管理子系統使用的狀態資訊。體部是對象相關的數據與暴露的服務。

對象頭部對外暴露的資訊稱為`Properties`, 包括：

- `Object Name`，用來標識對象
- `Object Directory`，對象所屬類別
- `Security Descriptors`，對象的訪問權限，一般在創建對象時傳入，大多數時候傳入值為NULL，表示採用默認安全屬性。
- `Quota Charges`，對象的資源使用資訊
- `Open handle count`，打開的句柄計數
- `Open handle list`，活動引用的進程列表
- `Reference count`，活動引用進程的計數
- `Type`，用來標識對象體部結構

對象管理子系統所管理的對象必須提供下屬服務:

- `Close`，關閉對象的一個句柄
- `Duplicate`，創建對象的另一個句柄，用來給另一個進程共享訪問該對象
- `Query object`，獲得對象的屬性與性質等資訊
- `Query security`，得到對象的安全描述資訊
- `Set security`，改變對象的安全訪問資訊
- `Wait`，同步一個或多個對象，通過特定事件。

同一類型的對象具有一些相同的屬性，如類型名、是否分配在非分頁記憶體、訪問權限、同步資訊等。這些由一個類型對象（type object）來表示。所有同一類型的對象實例共享這唯一的類型對象。可以創建新的對象類型，這通過把一個對象的屬性作為對外暴露的狀態，把其方法作為對外暴露的服務來實現。

對象名（`Object name`）是一個對象的描述性標識。對象管理子系統保持一個已經用於表示對象的名字列表，映射每個名字到對象實例。實際上大多數訪問對象的行為是通過句柄；通過對象名來查找對象實例僅發生在創建對象時、跨進程共享一個對象時。

`Object directories`用於按照類型來分類對象。預定義的`Object directories`包括：

- `\??` （Win32 設備名，其中只有符號連結）
- `\BaseNamedObjects` （互斥、事件、信號量、可等待計時器和段對象）
- `\Callback` （回調函數）
- `\Device` （設備）
- `\Drivers`
- `\FileSystem`
- `\KnownDlls`
- `\Nls` (language tables)
- `\ObjectTypes` （對象類型對象）
- `\RPC Controls` （RPC埠）
- `\Security` （安全子系統對象）
- `\Windows` （窗口子系統對象）

對象屬於命名空間（Namespace）. 每個使用者會話（user session）是一個名字空間。這使得多個客戶同時運行一個應用程式而不會發生干擾。在所有名字空間共享的對象屬於GLOBAL命名空間。例如，在Global命名空間中創建一個事件，名字叫CSAPP：

```
CreateEvent( NULL, FALSE, FALSE, "Global\\CSAPP" );
```

全局命名空間使得多個客戶會話間的進程可以通信。例如，一個客戶/伺服器使用互斥鎖來同步，伺服器模塊在全局命名空間創建一個互斥鎖對象，然後客戶進程使用"Global\"前綴來打開這個互斥鎖對象。客戶進程可以明示使用 "Local\"前綴來在客戶會話命名空間中創建對象。

OBJECT_ATTRIBUTES 結構:

```cpp
 typedef struct _OBJECT_ATTRIBUTES{
  ULONG Length;
  HANDLE RootDirectory;
  PUNICODE_STRING ObjectName;
  ULONG Attributes;
  PSECURITY_DESCRIPTOR SecurityDescriptor;
  PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService;
 }OBJECT_ATTRIBUTES;
```

Attributes 成員域可以是 0，或下述標誌的組合：

```
OBJ_INHERIT
OBJ_PERMANANT
OBJ_EXCLUSIVE
OBJ_CASE_INSENSITIVE
OBJ_OPENIF
OBJ_OPENLINK
OBJ_KERNEL_HANDLE
```

## 參加

- Windows NT體系結構

## 外部連結

- Object Manager Routines (Windows Drivers)
- Channel9 Interview