色综合图-色综合图片-色综合图片二区150p-色综合图区-玖玖国产精品视频-玖玖香蕉视频

您的位置:首頁技術(shù)文章
文章詳情頁

《Undocumented Windows 2000 Secrets》翻譯 --- 第二章(1)

瀏覽:99日期:2023-08-27 11:57:12

本章對于 Windows 2000 Native API 的討論,主要集中在這些 API 和系統(tǒng)模塊之間的關(guān)系,將重點介紹 Windows 2000 采用的中斷機制。 Windows 2000 利用此機制將對內(nèi)核服務的請求從用戶模式向內(nèi)核模式傳遞。另外, Win32K 接口和一些與 Native API 相關(guān)的主要運行時庫也會被提及,同時還將介紹一些經(jīng)常使用的數(shù)據(jù)類型。

有關(guān) Windows 2000 架構(gòu)的詳細討論已經(jīng)很多。許多有關(guān) Windows NT 的討論同樣適用于 Windows 2000 。《 Inside Windows NT 》( Custer 1993, Solomon 1998 )的第一、二版都是有關(guān)此方面的好書,同樣的還有《 Inside Windows 2000 》( Solomon and Russinovich 2000 )。

NT*() Zw*() 函數(shù)集

有關(guān) Windows 2000 架構(gòu)的一個有趣的事實是:它模擬了多個操作系統(tǒng)。 Windows 2000 內(nèi)置三個子系統(tǒng)來支持 Win32 、 POSIX 和 OS/2 應用程序。 Win32 子系統(tǒng)是最流行的一個,因此它更多的被開發(fā)人員和操作系統(tǒng)所關(guān)照。在 Windows 9x 中, Win32 接口實際上是作為整個系統(tǒng)的基礎(chǔ)結(jié)構(gòu)來實現(xiàn)的。但是, Windows 2000 的設(shè)計卻有很大不同。盡管 Win32 子系統(tǒng)包含一個名為 kernel32.dll 的系統(tǒng)模塊,但這并不是實際的操作系統(tǒng)內(nèi)核。它僅僅是 Win32 子系統(tǒng)的一個基本組件。在很多編程書籍中, Windows NT/2000 的軟件開發(fā)被簡化為與 Win32 API 打交道的工作, NT 平臺暴露出的一個隱藏的事實是存在另一個更為基礎(chǔ)的調(diào)用接口: Native API 。相信編寫 kernel-mode driver 或 file system driver 的開發(fā)人員已經(jīng)對 Native API 非常熟悉了,因為 kernel-mode 模塊位于更低的系統(tǒng)層,在那里子系統(tǒng)是不可見的。然而,你并不需要到驅(qū)動程序一層才能訪問此接口 ---- 即使一個普通的 Win32 應用程序也可在任何時候調(diào)用 Native API 。這沒什么技術(shù)上的限制 ---- 僅僅是微軟不支持此種應用程序開發(fā)模式而已。因此,有關(guān)此話題的信息并不是很多, neither SDK nor the DDK make the Native API available to Win32 Application.

未文檔化的級別

本書中的多數(shù)東西都來自被稱為未文檔化的信息。這通常意味著微軟沒有公開發(fā)布這些信息。然而,未文檔化也存在幾個級別,這是因為可能被公布的有關(guān)龐大的操作系統(tǒng)(如 Windows 2000 )的信息非常的多。我個人的系統(tǒng)分類如下:

l 正式文檔 :這些信息來自微軟出版的書、文件或者開發(fā)工具。大多數(shù)重要信息來自 SDK 、 DDK 和 MSDN 。

l 半文檔化的( Semidocumented :盡管不是正式文檔,但這些信息還是可以從微軟正式發(fā)布的文件中挖掘出來的。例如, Windows 2000 的很多函數(shù)和結(jié)構(gòu)體并沒有在 SDK 或 DDK 文檔中提到,但出現(xiàn)在一些頭文件或示列程序中。以 Windows 2000 為例,很多重要的半文檔化信息都源自頭文件 ntddk.h 和 ntdef.h ,這兩個文件都是 DDK 的一部分。

l 未文檔化,但并沒有隱藏 :這些信息不能在任何官方文檔和開發(fā)文檔中找到,但其中的一部分對調(diào)試工具是可用的。可執(zhí)行文件或符號文件中的所有符號化信息都屬于這一部分。最好的例子是內(nèi)核調(diào)試器的 !processfIElds 和 !threadfields 命令,這兩個命令會給出兩個未文檔化的結(jié)構(gòu): EPROCESS 和 ETHREAD 的成員名稱及其偏移量。

l 完全未文檔化的 :微軟很好的隱藏了某些信息,要獲得它們只能通過逆向工程和推理。此類信息包含很多實現(xiàn)細節(jié)的信息,沒有人認為 Windows 2000 開發(fā)人員需要關(guān)注它們,但是這些信息對于系統(tǒng)開發(fā)人員和開發(fā)調(diào)試軟件的人來說卻非常寶貴。挖掘系統(tǒng)內(nèi)部的信息是非常困難的,但同樣是非常有趣的。

本書討論的 Windows 2000 的內(nèi)部細節(jié)覆蓋了上述系統(tǒng)分類的后三個。

系統(tǒng)服務分配器( System Service Dispatcher

Win32 子系統(tǒng)和 Native API 之間的關(guān)系可以由 Win32 核心模塊與 Windows 2000 內(nèi)核模塊之間的依賴關(guān)系很好的解釋。 2-1 展示了模塊間的依賴關(guān)系,方框表示系統(tǒng)模塊,箭頭表示模塊間的依賴關(guān)系。如果一個箭頭從模塊 A 指向模塊 B ,這表示 A 依賴于 B ,即,模塊 A 調(diào)用 B 中的函數(shù)。模塊由雙向箭頭連接,表示二者之間相互依賴。在 2-1 中,模塊: user32.dll 、 advapi32.dll 、 gdi32.dll 、 rpcrt4.dll 以及 kernel32.dll 實現(xiàn)了基本的 Win32 API 。當然,還有其他的 DLL (如 version.dll 、 shell32.dll 和 comctl32.dll )也為 Win32 API 提供支持,為了更清晰些,我省略了它們。 2-1 表現(xiàn)出的一個特性非常有趣,所有的 Win32 API 調(diào)用最后都轉(zhuǎn)移到了 ntdll.dll ,而 ntdll.dll 又將其轉(zhuǎn)移到了 ntoskrnl.exe 。

Ntdll.dll 是一個操作系統(tǒng)組件,它為 Native API 準確地提供服務, ntdll.dll 是 Native API 在用戶模式下的前端。 Native API 真正的接口在 ntoskrnl.exe 中實現(xiàn)。從其文件名可以猜出它就是 NT 操作系統(tǒng)內(nèi)核。事實上,內(nèi)核模式驅(qū)動程序?qū)ο到y(tǒng)服務的請求多數(shù)時候都會進入該模塊。 Ntdll.dll 的主要任務就是為運行于用戶模式的程序提供一個確定的內(nèi)核函數(shù)的子集,這其中就包括 Win32 子系統(tǒng) DLLs 。在 2-1 中,從 ntdll.dll 指向 ntoskrnl.exe 的箭頭旁標注的 INT 2eh 表示 Windows 2000 使用此中斷將 CPU 特權(quán)級從用戶模式切換到內(nèi)核模式。開發(fā)內(nèi)核( kernel-mode )模式程序的人員認為用戶模式的代碼是具有攻擊性的、充滿錯誤的和危險的。因此,必須讓這些代碼遠離內(nèi)核函數(shù)。而通過在調(diào)用 API 的過程中將特權(quán)級別從用戶模式切換到內(nèi)核模式是一種可控制這些問題的方式。調(diào)用程序從來不可能觸及內(nèi)核,它只能察看它們。

例如,由 kernel32.dll 導出的 Win32 API 函數(shù) DeviceIoControl() 最終會調(diào)用由 ntdll.dll 導出的 NtDeviceIoControlFile() 。通過反編譯該函數(shù)會發(fā)現(xiàn)此函數(shù)令人驚訝的實現(xiàn)方式 — 它是如此的簡單! 示列 2-1 展示了這些。首先, CPU 寄存器 EAX 被裝入了一個“魔術(shù)”數(shù)字 0x38 ,這是一個分派 ID 。接下來,寄存器 EDX 被設(shè)置指向堆棧中的某處,其地址為堆棧指針 ESP 加上 4 ,因此, EDX 將指向堆棧中返回地址的后面,該返回地址在進入 NtDeviceIoControlFile() 時將被立即保存下來。顯而易見, EDX 指向的位置是用來臨時存放傳遞進來的參數(shù)的。接下來的指令是一個簡單的 INT 2eh ,該指令將跳轉(zhuǎn)到中斷描述符表( Interrupt Descriptor Table,IDT )的 0x2e 位置上存放的中斷處理例程( interrupt handler )中。這看上去是不是很熟悉?事實上,這有些像 Dos 下的 INT 21h 調(diào)用。然而, Windows 2000 的 INT 2eh 接口要遠比一個簡單的 API 調(diào)用有用,分配器( dispatcher )利用它從用戶模式進入內(nèi)核模式。請注意,這種模式切換方式是 x86 處理器特有的。在 Alpha 平臺上,有不同的方式來實現(xiàn)此種功能。

NtDeviceIoControlFile:

mov eax, 38h

lea edx, [esp+4]

int 2Eh

ret 28h

示列 2-1. ntdll.NtDeviceIoControlFile() 的實現(xiàn)方式

Windows 2000 Native API 由 248 個函數(shù)組成,這些函數(shù)都采用上述方式進入內(nèi)核。與 Windows NT 4.0 相比多出了 37 個。你很容易在 ntdll.dll 的導出列表中通過 Nt 前綴來認出它們。 Ntdll.dll 總共導出了 249 個這樣的符號。多出的那個函數(shù)是 NtCurrentTeb() ,該函數(shù)是一個純粹的用戶模式函數(shù),它無需進入內(nèi)核。 附錄 B 中的 B-1 列出了所有可用的 Native API 。該表同時還指出那個函數(shù)是由 ntoskrnl.exe 導出的。令人奇怪的是,在處于內(nèi)核模式的模塊中,只能調(diào)用 Native API 的一個子集。另一方面, ntoskrnl.exe 導出了兩個 ntdll.dll 沒有提供的 Nt* 符號(指以 Nt 開頭的符號): NtBuildNumber 和 NtGlobalFlag 。這兩個符號都沒有指向函數(shù)的入口地址,而是指向 ntoskrnl.exe 中的變量。驅(qū)動模塊( driver module )可以使用 C 編譯器的 extern 關(guān)鍵字來導入這些變量。 Window 2000 采用此種方式導出了很多變量,稍后我將給出一個示例代碼來使用其中的幾個。

你可能會奇怪為什么 B-1 (位于附錄 B 中)分別為 ntdll.dll 和 ntoskrnl.exe 提供了兩列,其名稱分別為: ntdll.Nt* 、 ntdll.Zw* 和 ntoskrnl.Nt* 、 ntoskrnl.Zw* 。原因是,這兩個模塊導出了兩組相互關(guān)聯(lián)的 Native API 符號。在 B-1 (位于附錄 B 中)的最左列給出了所有名字中包含 Nt 前綴的符號。另一個集合包含相似的名字,不過由 Zw 前綴代替了 Nt 。反編譯 ndll.dll 可看出每對符號都指向相同的代碼。這看起來似乎是浪費內(nèi)存。然而,如果你反編譯 ntoskrnl.exe ,你就會發(fā)現(xiàn) Nt* 符號指向?qū)嶋H的代碼而 Zw* 指向 INT 2eh stubs (如 示列 2-1 列出的)。這意味著 Zw* 函數(shù)集合將從用戶模式轉(zhuǎn)入內(nèi)核模式,而 Nt* 符號直接指向的代碼會在模式切換后被執(zhí)行。

表 B-1 (位于附錄 B 中)中有兩件事需要特別注意。首先, NtCurrentTeb() 函數(shù)沒有對應的 Zw* 函數(shù)。這不是什么大問題,因為 ntdll.dll 以相似的方式導出 Nt* 和 Zw* 函數(shù)。其次, ntoskrnl.exe 不再一貫的成對的導出 Nt/Zw 函數(shù)。其中的一些僅以 Nt* 或 Zw* 的形式出現(xiàn)。我不知道為什么會這樣,我猜測 ntoskrnl.exe 僅導出了在 Windows 2000 DDK 中有文檔記錄的函數(shù)以及其它系統(tǒng)模塊必須的那些函數(shù)。注意,保留的 Native API 函數(shù)仍然實現(xiàn)于 ntoskrnl.exe 的內(nèi)部。這些函數(shù)并沒有公開的進入點,但可通過 INT 2eh 到達他們。

服務描述符表( The Service Descriptor Tables

示例 2-1 給出的反編譯代碼可看出, INT 2eh 隨同傳入 CPU 寄存器 EAX 和 EDX 的兩個參數(shù)一起被調(diào)用。我已經(jīng)提到過 EAX 中的“魔術(shù)”數(shù)字是一個分派 ID 。除 NtCurrentTeb() 之外的所有 Native API 都采用此種方式,處理 INT 2eh 的代碼必須確定每個調(diào)用將被分配到那個函數(shù)。這就是提供分派 ID 的原因。位于 ntoskrnl.exe 中的中斷處理例程將 EAX 中的數(shù)值作為一個索引來查詢一個特定的表。這個表被稱作系統(tǒng)服務表( System Service Table, SST )該表對應的 C 結(jié)構(gòu)體 ---SYSTEM_SERVICE_TABLE 的定義在 列表 2-1 中給出。在該列表中還包含 SERVICE_DESCRIPTOR_TABLE 結(jié)構(gòu)的定義,該結(jié)構(gòu)共有四個 SST 類型的數(shù)組,其中的前兩個用于特定目的。

盡管上述的兩個表是系統(tǒng)基本的數(shù)據(jù)類型,但他們在 Windows 2000 DDK 中 并沒有相應的文檔記載,本書中出現(xiàn)的許多代碼片斷都包含未文檔化的數(shù)據(jù)類型和函數(shù)。因此,不能保證這些信息是完全真實可信的。所有符號化的信息,如結(jié)構(gòu)名 稱、結(jié)構(gòu)成員和參數(shù)都是如此。在創(chuàng)建這些符號時,我試圖使用適當?shù)拿Q,這些名稱基于從已知符號的一個很小的子集(包括從符號文件中得到的那些)中得出的 命名方案。然而,在很多場合這種啟發(fā)式方法并不成功。只有在原始的代碼中包含所有的信息,但我無法得到它們。實際上,我并不打算閱讀這些源代碼,因為這需 要和微軟簽訂一個 NDA ( Non-Disclosure Agreement, ,不可泄漏協(xié)議),由于該 NDA 的限制,將很難寫出一本有關(guān)非文檔化信息的書。

typedef NTSTATUS (NTAPI*NTPROC)();

typedef NTPROC* PNTPROC;

#define NTPROC_ sizeof(NTPROC)

typedef struct _SYSTEM_SERVICE_TABLE

{

PNTPROC ServiceTable; // array of entry points

PDOWRD CounterTable; // array of usage counters

DWord ServiceLimit; // number of table entries

PBYTE ArgumentTable; // array of byte counts

}

SYSTEM_SERVICE_TABLE,

*PSYSTEM_SERVICE_TABLE,

**PPSYSTEM_SERVICE_TABLE;

//-----------------------------------------------------------------------------------------------------------

typedef struct _SERVICE_DESCRIPTOR_TABLE

{

SYSTEM_SERVICE_TABLE ntoskrnl; // ntoskrnl.exe ( native api )

SYSTEM_SERVICE_TABLE win32k; // win32k.sys (gdi/user support)

SYSTEM_SERVICE_TABLE Table3; // not used

SYSTEM_SERVICE_TABLE Table4; // not used

}

SYSTEM_DESCRIPTOR_TABLE,

*PSYSTEM_DESCRIPTOR_TABLE,

**PPSYSTEM_DESCRIPTOR_TABLE;

列表 2-1 系統(tǒng)服務描述符表的結(jié)構(gòu)定義

現(xiàn)在,回到 SDT ( Service Descriptor Table )的秘密上來。從 列表 2-1 給出的該結(jié)構(gòu)的定義可看出該結(jié)構(gòu)的頭兩個數(shù)組保留給了 ntoskrnl.exe 和 Win32 子系統(tǒng)(位于 win32k.sys )中的內(nèi)核模式( kernel-mode )部分。來自 gdi32.dll 和 user32.dll 的調(diào)用都通過 Win32k 的系統(tǒng)服務表( SST )進行分派。 Ntolkrnl.exe 導出了一個指針(符號為 KeServiceDescriptorTable )指向其主服務描述符表( Main SDT )。內(nèi)核還維護了一個替代的 SDT ,其名稱為: KeServiceDescriptorTableShadow ,但這個 SDT 并沒有被導出。從處于內(nèi)核模式的模塊中訪問主服務描述符表( SDT )非常容易,你只需要兩個 C 指令,如 列表 2-2 所示。首先是由 extern 關(guān)鍵字修飾的變量說明,這告訴鏈接器該變量并不包含在此模塊中,而且不需要在鏈接時解析相應的符號名稱。當該模塊被加載到進程的地址空間后,針對該符號的引用才會動態(tài)連接到相應的模塊中。 列表 2-2 中第二個 C 指令就是這樣的一個引用。將類型為 PSERVER_DESCRIPTOR_TABLE 的變量賦值為 KeServiceDescriptorTable 時,就會和 ntoskrnl.exe 建立一個動態(tài)連接。這很像調(diào)用一個 DLL 中的 API 函數(shù)。

// Import SDT pointer

extern PSERVICE_DESCRIPTOR_TABLE KeServiceDescriptorTable;

// Create SDT reference

PSERVICE_DESCRIPTOR_TABLE psdt = KeServiceDescriptorTable;

列表 2-2 訪問系統(tǒng)服務描述符表

SDT 中的每個 SST 的 ServiceTable 成員都是一個指針,指向一個由函數(shù)指針構(gòu)成的數(shù)組,此函數(shù)指針的類型為: NTPROC ,這為 Native API 提供了占位符,這種方式和在 Win32 編程中使用的 PROC 類型很相似。 NTPROC 的定義在前面的 列表 2-1 中給出。 Native API 函數(shù)通常返回一個 NTSTATUS 類型的代碼并且使用 NTAPI 調(diào)用方式, NTAPI 實際上就是 _stdcall 。 ServiceLimit 成員保存在 ServieTable 數(shù)組中發(fā)現(xiàn)的入口地址的個數(shù)。在 Windows 2000 中,其默認值為 248 。 ArgumentTable 成員是一個 BTYE 類型的數(shù)組,它和 ServiceTable 所指的數(shù)組一一對應,并給出其中每個函數(shù)指針所需的參數(shù)在調(diào)用者的堆棧中的字節(jié)數(shù)。此信息隨 EDX 寄存器提供的指針一起使用。當內(nèi)核從調(diào)用者的堆棧中復制參數(shù)到自己的堆棧時就需要這些信息。 CounterTable 成員在 Windows 2000 的 Free Build 版中不被使用。在 Debug Build 版中,該成員指向一個 DWORD 類型的數(shù)組,作為每個函數(shù)的使用計數(shù)器( usage counters )。 This information can be used for profiling purposes.

使用 Windows 2000 的內(nèi)核調(diào)試器可方便的顯示 SDT 中的內(nèi)容。如果你還沒有設(shè)置好這個有用的程序,那請參考第一章。在 示列 2-2 中,我首次使用了 dd KeServiceDescriptorTable 命令。調(diào)試器會將此公開符號解析為 0x8046AB80 ,同時顯示該地址之后的 32 個 DWORD 的 16 進制轉(zhuǎn)儲。不過僅有前面的四行才是有意義的,它們分別對應 列表 2-1 中的四個 SDT 成員。為了更清晰些,它們都將以黑體顯示。如果你仔細觀察,你會發(fā)現(xiàn)第五行與第一行十分相像,這是另一個 SDT 嗎?這是測試內(nèi)核調(diào)試器的 ln 命令的好機會。在示列 2-2 中,在顯示完 KeServiceDescriptorTable 的十六進制 dump 之后,我輸入 ln 8046abc0 命令。顯然,調(diào)試器知道地址 0x8046abc0 ,它將此地址轉(zhuǎn)化為對應的符號 KeServiceDescriptorTableShadow 可以看出,這是內(nèi)核維護的第二個 SDT 。二者之間的顯著區(qū)別是:第二個 SDT 包含 Win32k.sys 的入口地址。這兩個表的的第三和第四個成員都是空的。 Ntoskrnl.exe 提供了一個函數(shù) KeAddSystemServiceTabel() 來填充這兩個成員。

注意,我截斷了 ln 命令的輸出信息,僅保留了基本的信息。

從地址 0x8046ab88 開始,是 KeServiceDescriptorTable 的十六進制轉(zhuǎn)儲,在那兒可以找到 ServiceLimit 成員,可看到其值為 0xF8 (十進制 248 ),這和我們預期的一樣。 ServiceTable 和 ArgumentTable 的值分別指向地址 0x804704d8 和 0x804708bc 。用 ln 命令察看著兩個地址,可得到其符號: KiServiceTable 和 KiArgumentTable 。這兩個符號都沒有從 ntoskrnl.exe 中導出,但是調(diào)試器可通過察看 Windows 2000 的符號文件識別它們。 ln 命令還可應用到 Win32k SST 指針上,針對其 ServiceTable 和 ArgumentTable 成員,調(diào)試器分別給出了其對應的符號 w32pServiceTable 和 W32pArgumenTable 。這兩個符號都來自 Win32k.sys 的符號文件。如果調(diào)試器無法解析這些地址,可使用 .reload 命令強制重新加載所有可用符號文件,然后再進行解析。

示例 2-2 的剩余部分是 KiServiceTable 和 KiArgumentTable 最前面的 128 個字節(jié)的十六進制轉(zhuǎn)儲。到目前為止,如果我說的有關(guān) Native API 的東西都是正確的,那么 NtClose() 函數(shù)的地址應位于 KiServiceTable 數(shù)組的第 24 個位置上,其地址為 0x80470538 。在該地址處,可發(fā)現(xiàn)其值為 0x8044c422 ,在 dd KiServiceTable 的輸出中,該地址以黑體標記。用 ln 察看 0x8044c422 ,會看到其對應的符號正是 NtClose() 。

kd> dd KeServiceDescriptorTable

8046ab80 804704d8 00000000 000000f8 804708bc

8046ab90 00000000 00000000 00000000 00000000

8046aba0 00000000 00000000 00000000 00000000

8046abb0 00000000 00000000 00000000 00000000

8046abc0 804704d8 00000000 000000f8 804708bc

8046abd0 a0186bc0 00000000 0000027f a0187840

8046abe0 00000000 00000000 00000000 00000000

8046abf0 00000000 00000000 00000000 00000000

kd> ln 8046abc0

(8046abc0) nt!KeServiceDescriptorTableShadow

kd> ln 804704d8

(804704d8) nt!KiServiceTable

kd> ln 804708bc

(804708bc) nt!KiArgumentTable

kd> ln a0186bc0

(a0186bc0) win32k!W32pServiceTable

kd> ln a0187840

(a0187840) win32k!W32pArgumentTable

kd> dd KiServiceTable

804704d8 804ab3bf 804ae86b 804bdef3 8050b034

804704e8 804c11f4 80459214 8050c2ff 8050c33f

804704f8 804b581c 80508874 8049860a 804fc7e2

80470508 804955f7 8049c8a6 80448472 804a8d50

80470518 804b6bfb 804f0cef 804fcb95 8040189a

80470528 804d06cb 80418f66 804f69d4 8049e0cc

80470538 8044c422 80496f58 804ab849 804aa9da

80470548 80465250 804f4bd5 8049bc80 804ca7a5

kd> db KiArgumentTable

804708bc 18 20 2c 2c 40 2c 40 44-0c 18 18 08 04 04 0c 10 . ,,@,@D........

804708cc 18 08 08 0c 08 08 04 04-04 0c 04 20 08 0c 14 0c ........... ....

804708dc 2c 10 0c 1c 20 10 38 10-14 20 24 1c 14 10 20 10 ,... .8.. $... .

804708ec 34 14 08 04 04 04 0c 08-28 04 1c 18 18 18 08 18 4.......(.......

804708fc 0c 08 0c 04 10 00 0c 10-28 08 08 10 00 1c 04 08 ........(.......

8047090c 0c 04 10 00 08 04 08 0c-28 10 04 0c 0c 28 24 28 ........(....($(

8047091c 30 0c 0c 0c 18 0c 0c 0c-0c 30 10 0c 0c 0c 0c 10 0........0......

8047092c 10 0c 0c 14 0c 14 18 14-08 14 08 08 04 2c 1c 24 .............,.$

kd> ln 8044c422

(8044c422) nt!NtClose

示例 2-2 檢查服務描述符表

譯注:

在 Windows XP 中, KeServiceDescriptorTable 和 KeServiceDescriptorTableShadow 和 Windows 2000 有所區(qū)別。在 XP 中,后者位于前者的前面,而在 W2K 中,后者位于前者的后面。

INT 2eh 系統(tǒng)服務處理例程( System Service Handler

隱藏在內(nèi)核模式中的 INT 2eh 中斷處理例程為 KiSystemService() 。再強調(diào)一次,這是一個內(nèi)部符號, ntoskrnl.exe 并沒有導出該符號,不過,它卻包含在 Windows 2000 的符號文件中。因此,內(nèi)核調(diào)試器可以正確的解析該符號。從本質(zhì)上來看, KiSystemService() 將執(zhí)行如下操作:

1. 從當前線程的控制塊( thread's control block )中檢索 SDT 指針。

2. 通過測試 EAX 寄存器中的分派 ID 的第 12 、 14 位來確定使用 SDT 中的那個 SST ( SDT 中有四個 SST )。如果分派 ID 位于 0x0000-0x0FFF ,將選擇 ntoskrnl 表;位于 0x1000-0x1FFF 則選擇 Win32k 表。 0x2000-0x2FFF 和 0x3000-0x3FFF 由 SDT 的 Table3 和 Table4 保留。如果分配 ID 超過了 0x3FFF ,在分派前多余的位將被屏蔽掉。

3. 通過檢查分派 ID 的 0 到 11 位來確定該 ID 在所選 SST 中對應的 ServiceLimit 成員。如果 ID 超出了范圍,將返回錯誤代碼: STATUS_INVALID_SYSTEM_SERVICE 。在一個未使用的 SST 中, ServiceLimit 成員始終是 0 ,從而為所有可能的分派 ID 產(chǎn)生一個錯誤代碼。

4. 通過檢查 EDX 中保存的參數(shù)堆棧指針,來取得 MmUserProbeAddress 的值。這是由 ntoskrnl.exe 導出的一個公開變量。參數(shù)指針通常會與 0x7FFF0000 進行比較。如果沒有低于該地址,那么將返回 STATUS_ACCESS_VIOLATION 。

5. 根據(jù)在 SST 的 ArgumentTable 中查找到的參數(shù)堆棧的字節(jié)數(shù),將所有函數(shù)參數(shù)從調(diào)用者堆棧中復制到當前的內(nèi)核堆棧中。

6. 在從服務調(diào)用( Service Call )中返回后,將控制權(quán)傳遞給內(nèi)部函數(shù) KiServiceExit()

非常有趣的是 INT 2eh 中斷處理例程并不使用全局 SDT (即 KeServiceDescriptorTable ),而是使用線程專屬的指針替代之。顯然,每個線程可以擁有不同的 SDT 。在線程初始化時, KeInitializeThread() 會將 KeServiceDescriptorTable 的指針寫入線程控制塊( Thread Control Block )中。不過,此默認值在稍后可能會改變,如改為指向 KeServiceDescriptorTableShadow 。

Win32 內(nèi)核模式接口( Win32 Kernel-mode Interface

從前面對 SDT 的討論,可看出存在著與 Native API 相關(guān)的第二個主內(nèi)核模式接口( main Kernel-mode Interface )。該接口將 Win32 子系統(tǒng)的圖形設(shè)備接口( Graphics Device Interface, GDI )、窗口管理器(即 User 模塊)連接至內(nèi)核組件 ---Win32K (即 Win32k.sys ) . ,該組件隨同 Windows NT 4.0 引入。引入該組件是為了克服 Win32 圖形引擎固有的性能限制(由于 Windows NT 子系統(tǒng)的最初設(shè)計導致)。在 Windows NT 3.x 中, Win32 子系統(tǒng)采用的是客戶 - 服務器模式( Client-Server model ),這樣就必須從用戶模式切換到內(nèi)核模式才能進行內(nèi)核調(diào)用( Kernel Involved )。通過將圖形引擎的絕大部分移至內(nèi)核組件 ---Win32k.sys ,從而避免了大部分因內(nèi)核切換導致的性能損失。

Win32K 分派 ID Win32K Dispatch IDs

現(xiàn)在該介紹 Win32k.sys 了,也是該更新 2-1 的時候了。 2-2 基于 2-1 ,但在 ntoskrnl.exe 左面加入了 Win32k.sys 。同時我還加入了從 GDI32.DLL 和 USER32.DLL 指向 Win32k.sys 的箭頭。當然,這不是百分之百正確,因為這些模塊中的 INT 2eh 調(diào)用實際上指向 ntoskrnl.exe ,在 ntoskrnl.exe 中才有該中斷的處理例程。然而,調(diào)用最后還是由 Win32k.sys 管理,這也是箭頭這樣指的原因。

稍早提到過, Win32K 接口同樣基于 INT 2eh 分派器( INT 2eh Dispatcher ),這與 Native API 非常相似。僅有的區(qū)別在于 Win32K 使用另一區(qū)段的分派 ID 。盡管與所有 Native API 調(diào)用相關(guān)的分派 ID 都位于 0x0000----0x0FFF ,而 Win32K 分派 ID 位于 0x1000---0x1FFF 之間。如 2-2 所示, Win32K 的主要客戶端是 GDI32.DLL 和 USER32.DLL 。因此,通過反編譯這些模塊(指 gdi32.dll 和 user32.dll )可能會找到與 Win32K 分派 ID 相關(guān)的符號化名稱。通過反編譯可發(fā)現(xiàn)在這些模塊( gdi32.dll 和 user32.dll )的導出節(jié)( export sections )中僅包含 INT 2eh 調(diào)用的一個很小的子集,看來是時候再次使用內(nèi)核調(diào)試器了。如 示例 2-3 所示,我通過使用 dd W32pServiceTable 命令,來確定 Win32k.sys 的符號是可用的,在此之前請先使用 .reload 命令以加載所有可用符號文件。

示例 2-3 的最后三行中,我使用 ln 命令顯示與 W32pServiceTable 的第一個入口地址相關(guān)的符號。顯然,可看到分派 ID 為 0 的 Win32K 函數(shù)為 NtGdiAbortDoc() 。你可以針對所有 639 個 ID 來重復此過程,但是最好能自動進行符號的查找。現(xiàn)在,我已經(jīng)為你完成了這項工作,所有分派 ID 對應的符號名稱都收錄在 附錄 B B-2 中。符號從 gdi32.dll 和 user32.dll 映射到 win32k.sys 十分簡單: GDI 符號可通過在其前面添加 NtGdi 前綴就可轉(zhuǎn)換為 Win32K 符號, USER 符號則添加 NtUser 前綴。然而,有一少部分例外。例如,如果一個 GDI 符號以 Gdi 開始,那么其前綴就減少為 Nt ,這可能是為了避免出現(xiàn) NtGdiGdi 這樣的字符序列。在其他的一些例子中,字符的大小寫會有些不同(比如 EnableEUDC() 轉(zhuǎn)化后則變成了 NtGdiEnableEudc() ),或者用符號名稱尾部的 W 來表示沒有對應的 Unicode 函數(shù)(如, CopyAcceleratorTableW() 轉(zhuǎn)化后成為 NtUserCopyAcceleratorTable() )。

提供 Win32K API 的詳細文檔需要很大的努力。這些函數(shù)幾乎是 Native API 的三倍。或許某天有人會為這些 API 編寫一本不錯的參考手冊,就像 Gary Nebbett 編寫的 Native API 手冊。不過,在本書范圍內(nèi),有關(guān)這些 API 的信息已經(jīng)足夠了。

主站蜘蛛池模板: 国产精品一在线观看 | 国产中文字幕视频在线观看 | 久久99国产精品久久 | 午夜宅宅宅影院在线观看 | 国产区一区二区三区 | 国产精品久久国产三级国电话系列 | 99爱视频在线观看 | 亚洲日本欧美在线 | 国产高清免费不卡观看 | 欧美午夜不卡 | 精品三级国产 | 欧美成人午夜做爰视频在线观看 | 亚洲天堂最新网址 | japanese色系tube护士 | 99国产精品视频久久久久 | 久久亚洲精品国产精品777777 | 成人午夜性视频欧美成人 | 亚洲精品综合一区二区三区在线 | 国产精品亚洲一区二区三区久久 | 久久久久久毛片免费播放 | 亚洲国产精品一区二区三区久久 | 日本国产在线 | 亚洲第一成人在线 | 久久综合久久综合九色 | 亚洲孕交 | 成人免费公开视频 | 成人免费在线观看视频 | 深爱激情五月网 | 一级做a爰性色毛片免费 | 香蕉成人在线 | 欧美俄罗斯一级毛片激情 | 99视频在线观看高清 | 18成人免费观看网站入口 | ririai99在线视频观看 | 无内丝袜透明在线播放 | 久久精品在现线观看免费15 | 欧美另类精品 | 欧美精品99 | 拍拍拍又黄又爽无挡视频免费 | 午夜精品同性女女 | 久污|