亚洲精品久久久中文字幕-亚洲精品久久片久久-亚洲精品久久青草-亚洲精品久久婷婷爱久久婷婷-亚洲精品久久午夜香蕉

您的位置:首頁技術文章
文章詳情頁

《Undocumented Windows 2000 Secrets》翻譯 --- 第四章(3)

瀏覽:64日期:2023-08-27 15:07:50

第四章 探索 Windows 2000 的內存管理機制

翻譯: Kendiv ( fcczj@263.net )

更新: Sunday, February 17, 2005

聲明:轉載請注明出處,并保證文章的完整性,本人保留譯文的所有權利。

Memory Spy Device 示例

微軟對 Windows NT 和 2000 說的最多的就是它們是 安全的操作系統 。它們不但在網絡環境中加入了用戶驗證系統,同時還加強了系統的穩健性( robustness ),以進一步降低錯誤應用程序危及系統完整性的概率,這些錯誤的程序可能使用了非法的指針或者在其內存數據結構以外的地方進行了寫入操作。這些在 Windows 3.x 上都是十分讓人頭疼得問題,因為 Windows 3.x 系統和所有的應用程序共享單一的內存空間。 Windows NT 為系統和應用程序內存以及并發的進程提供了完全獨立的內存空間。每個進程都有其獨立的 4GB 地址空間,如 4-2 所示。無論何時發生任務切換,當前的地址空間都會被換出( switch out ),同時另一個被映射進來,它們各自使用不同的段寄存器、頁表和其他內存管理結構。這種設計避免了應用程序無意中修改另一個程序所使用的內存。由于每個進程必然會要求訪問系統資源,所以在 4GB 空間中總是包含一些系統數據和代碼,并采用了一個不同的技巧來保護這些內存區域不被惡意程序代碼所覆寫( overwritten )。

Windows 2000 的內存分段

Windows 2000 繼承了 Windows NT 4.0 的基本內存分段模型,默認情況下,該模型將 4GB 地址空間劃分為相等的兩塊。低一半的地址范圍是: 0x00000000 ---- 0x7FFFFFFF ,其中包含運行于用戶模式(用 Intel 的術語來說是,是特權級 3 或 Ring 3 )的應用程序的數據和代碼。高一半的地址范圍是: 0x80000000 --- 0xFFFFFFFF ,默認全部保留給系統使用,位于這一范圍的代碼運行于內核模式(即特權級為 0 或 Ring 0 )。特權級決定了代碼可以執行什么操作以及可以訪問那一個塊內存。這意味著對于低特權級的代碼來說,會被禁止執行某些 CPU 指令或訪問某些內存區域。例如,如果一個用戶模式下的程序觸及了任何 0x80000000 (即 4GB 地址空間中的高一半)以上的地址,系統會拋出一個異常并同時終止該程序的運行,不會給其任何機會。

圖 4-5. 用戶模式下不能訪問 0x80000000 以上的地址

圖 4-5 展示了程序試圖讀取 0x80000000 地址時的情況。這種嚴格的訪問限制對于系統的完整性來說是好事,但對于調試工具就不是什么好消息了,因為調試工具需要訪問所有可用內存。幸運的是,存在著一個簡單的方法:采用內核驅動程序,和系統本身類似,它也運行于高特權級(即 Ring 3 ),因此它們可以執行所有的 CPU 指令,可訪問所有的內存區域。這其中的訣竅就是將一個 Spy 驅動程序注入系統,用它來訪問需要的內存,并將讀到的內容發送到它的搭檔程序,該搭檔程序會在用戶模式下等待。當然,內核驅動程序不能讀取虛擬內存地址,而且得不到分頁機制的支持。因此,這樣的驅動程序必須在訪問一個地址之前小心的檢查它,以避免出現藍屏死機( Blue Screen Of Death , BSOD )。相對于應用程序引發的異常(僅會終止出現問題的程序),驅動程序引發的異常會停止整個系統,并強迫進行重啟。

設備 I/O 控制 Dispatcher ( Device I/O Control Dispatcher

本書光盤上有一個通用 Spy Device 的源代碼,該 Spy Device 作為內核驅動程序實現。可以在 srcw2k_spy 目錄下找到它的源代碼。這個設備基于第三章的驅動向導所產生的驅動程序骨架。其用戶模式下的接口為 w2k_spy.sys , w2k_spy.sys 采用 Win32 的設備 I/O 控制( IOCTL ),在第三章中曾簡要的談過 IOCTL 。 Spy Device 定義了一個名為 Devicew2k_spy 的設備和一個符號鏈接 DosDevicesw2k_spy ,定義符號鏈接是為了能在用戶模式下訪問該設備。非常可笑的是符號鏈接的名字空間居然是 DosDevice ,而在這兒,我們使用的可不是一個 DOS 設備驅動。這就像歷史上有名的 root ,原本是叫做石頭的 J 。安裝好符號鏈接后,驅動程序就可以被用戶模式下的任何模塊打開了,方法是:使用 Win32 API 函數 CreateFile() ,路徑為 .w2k_spy 。字符串 . 是通用轉義符,表示本地設備。例如, .C : 指向本地硬盤上的 C :分區。從 SDK 的文檔中可了解 CreateFile() 的更多細節。

該驅動程序的頭文件有一部分已經由 列表 4-2 列表 4-5 給出。這個文件有些像 DLL 的頭文件:它包含在編譯過程中,模塊所需的定義,而且還為客戶端程序提供了足夠的接口信息。 DLL 和驅動程序以及客戶端程序都包含相同的頭文件,但每個模塊會取出各自所需的定義以完成正確的操作。不過,頭文件的這種兩面性給內核驅動程序帶來的麻煩要遠多于給 DLL 帶來的,這都是因為微軟給驅動程序提供的特殊開發環境所致。不幸的是, DDK 中的頭文件并不能和 SDK 中的 Win32 文件兼容。至少在 C 工程,二者的頭文件是不能混合使用的。這樣的結果就是陷入了僵局,此種情況下,內核驅動可以訪問的常量、宏和數據類型對于客戶端程序來說是卻是無法使用的。因此, w2k_spy.c 定義了一個名為 _W2K_SPY_SYS_ 的標志常量, w2k_spy.h 通過 #ifdef…..#else…..#endif 來檢查該常量是否出現,以決定需要補充哪些缺少的定義。這意味著,所有出現在 #ifdef _W2K_SPY_SYS_ 之后的定義僅可被驅動代碼看到,位于 #else 之后的則專用于客戶端程序。 w2k_spy.h 中條件語句之外的所有部分被這兩個模塊同時使用。

在第三章中,在討論我的驅動向導時,我給出了向導生成的驅動程序骨架,如 列表 3-3 所示。由該驅動向導生成的新的驅動工程均開始于 DeviceDispatcher() 函數。該函數接受一個設備上下文指針,以及一個指向 IRP ( I/O 請求包)的指針,該 IRP 隨后將會被分派。向導的樣板代碼已經處理了基本的 I/O 請求: IRP_MJ_CREATE 、 IRP_MJ_CLEANUP 和 IRP_MJ_CLSE ,當客戶要關閉一個設備時,會給該設備發送這些 I/O 請求。 DeviceDispatcher() 針對這些請求只是簡單的返回 STATUS_SUCCESS ,因此設備可以被正確的打開和關閉。對于某些設備,這種動作已經足夠,但有些設備還需要初始化和清理代碼,這些代碼多少都有些復雜。對于其他的請求,第三章中的驅動程序骨架總是返回 STATUS_NOT_IMPLEMENTED 。擴展該骨架代碼的第一步是修改默認的動作,以便處理更多的 I/O 請求。就像 w2k_spy.sys 的主要任務之一:通過 IOCTL 調用將在用戶模式下無法訪問的數據發送給 Win32 應用程序,因此首先需要在 DeviceDispatcher() 中添加處理 IRP_MJ_DEVICE_CONTROL 的函數。 列表 4-6 給出了更新后的代碼。

NTSTATUS DeviceDispatcher (PDEVICE_CONTEXT pDeviceContext,

PIRP pIrp)

{

PIO_STACK_LOCATION pisl;

DWord dInfo = 0;

NTSTATUS ns = STATUS_NOT_IMPLEMENTED;

pisl = IoGetCurrentIrpStackLocation (pIrp);

switch (pisl->MajorFunction)

{

case IRP_MJ_CREATE:

case IRP_MJ_CLEANUP:

case IRP_MJ_CLOSE:

{

ns = STATUS_SUCCESS;

break;

}

case IRP_MJ_DEVICE_CONTROL:

{

ns = SpyDispatcher (pDeviceContext,

pisl->Parameters.DeviceIoControl.IoControlCode,

pIrp->AssociatedIrp.SystemBuffer,

pisl->Parameters.DeviceIoControl.InputBufferLength,

pIrp->AssociatedIrp.SystemBuffer,

pisl->Parameters.DeviceIoControl.OutputBufferLength,

&dInfo);

break;

}

}

pIrp->IoStatus.Status = ns;

pIrp->IoStatus.Information = dInfo;

IoCompleteRequest (pIrp, IO_NO_INCREMENT);

return ns;

}

列表 4-6. 為 Dispatcher 增加處理的 IRP_MJ_DEVICE_CONTROL 函數

列表 4-6 中的 IOCTL 處理代碼非常簡單,它僅調用了 SpyDispatcher() ,并將一個擴展后的 IRP 結構和當前 I/O 堆棧位置作為參數傳遞給 SpyDispatcher() 。 SpyDispatcher() 在 列表 4-7 中給出,該函數需要如下的參數:

l pDeviceContext 一個驅動程序的設備上下文指針。驅動程序向導提供了的基本 Device_Context 結構,該結構中包含驅動程序和設備對象指針(參見 列表 3-4 )。不過, Spy 驅動程序在該結構中增加了一對私有成員。

l dCode 指定了 IOCTL 編碼,以確定 Spy 設備需要執行的命令。一個 IOCTL 編碼是一個 32 位整數,它包含 4 個位域,如 4-6 所示。

l pInput 指向一個輸入緩沖區,用于給 IOCTL 提供輸入數據。

l dInput 輸入緩沖區的大小。

l pOutput 指向用來接收 IOCTL 輸出數據的輸出緩沖區。

l dOutput 輸出緩沖區的大小

l pdInfo 指向一個 DWORD 變量,該變量保存寫入輸出緩沖區中的字節數。

圖 4-6. 設備 I/O 控制編碼的結構

根據所用的 IOCTL 使用的傳輸模式,輸入 / 輸出緩沖區會以不同的方式從系統傳遞給驅動程序。 Spy 設備使用已緩存的 I/O ( buffered I/O ),系統將輸入數據復制到一個安全的緩沖區(此緩沖區由系統自動分配)中,在返回時,將指定數目的數據從同樣的系統緩沖區中復制到調用者提供的輸出緩沖區中。一定要牢記:在這種情況下,輸入和輸出緩沖區是重疊的,因此 IOCTL 的處理代碼必須在向輸出緩沖區中寫入任何數據之前,保存所有它稍后可能需要使用的輸入數據。系統 I/O 緩沖區的指針保存在 IRP 結構中的 SystemBuffer 成員中(參見 ntddk.h )。輸入 / 輸出緩沖區的大小保存在一個不同的地方,它們是 IRP 的參數成員 DeviceIoControl 的一部分,分別為 InputBufferLength 和 OutputBufferLength 。 DeviceIoControl 子結構還通過其 IoControlCode 成員提供了 IOCTL 編碼。有關 Windows NT/2000 的 IOCTL 的傳輸模式的信息以及它們如何傳入 / 傳出數據,請參考我在 Windows Developer's Journal(Schreiber 1997) 發表的文章“ A Spy Filter Driver for Windows NT ”。

NTSTATUS SpyDispatcher (PDEVICE_CONTEXT pDeviceContext,

DWORD dCode,

PVOID pInput,

DWORD dInput,

PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

SPY_MEMORY_BLOCK smb;

SPY_PAGE_ENTRY spe;

SPY_CALL_INPUT sci;

PHYSICAL_ADDRESS pa;

DWORD dValue, dCount;

BOOL fReset, fPause, fFilter, fLine;

PVOID pAddress;

PBYTE pbName;

HANDLE hObject;

NTSTATUS ns = STATUS_INVALID_PARAMETER;

MUTEX_WAIT (pDeviceContext->kmDispatch);

*pdInfo = 0;

switch (dCode)

{

case SPY_IO_VERSION_INFO:

{

ns = SpyOutputVersionInfo (pOutput, dOutput, pdInfo);

break;

}

case SPY_IO_OS_INFO:

{

ns = SpyOutputOsInfo (pOutput, dOutput, pdInfo);

break;

}

case SPY_IO_SEGMENT:

{

if ((ns = SpyInputDword (&dValue,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputSegment (dValue,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_INTERRUPT:

{

if ((ns = SpyInputDword (&dValue,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputInterrupt (dValue,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_PHYSICAL:

{

if ((ns = SpyInputPointer (&pAddress,

pInput, dInput))

== STATUS_SUCCESS)

{

pa = MmGetPhysicalAddress (pAddress);

ns = SpyOutputBinary (&pa, PHYSICAL_ADDRESS_,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_CPU_INFO:

{

ns = SpyOutputCpuInfo (pOutput, dOutput, pdInfo);

break;

}

case SPY_IO_PDE_ARRAY:

{

ns = SpyOutputBinary (X86_PDE_ARRAY, SPY_PDE_ARRAY_,

pOutput, dOutput, pdInfo);

break;

}

case SPY_IO_PAGE_ENTRY:

{

if ((ns = SpyInputPointer (&pAddress,

pInput, dInput))

== STATUS_SUCCESS)

{

SpyMemoryPageEntry (pAddress, &spe);

ns = SpyOutputBinary (&spe, SPY_PAGE_ENTRY_,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_MEMORY_DATA:

{

if ((ns = SpyInputMemory (&smb,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputMemory (&smb,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_MEMORY_BLOCK:

{

if ((ns = SpyInputMemory (&smb,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputBlock (&smb,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_HANDLE_INFO:

{

if ((ns = SpyInputHandle (&hObject,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputHandleInfo (hObject,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_HOOK_INFO:

{

ns = SpyOutputHookInfo (pOutput, dOutput, pdInfo);

break;

}

case SPY_IO_HOOK_INSTALL:

{

if (((ns = SpyInputBool (&fReset,

pInput, dInput))

== STATUS_SUCCESS)

&&

((ns = SpyHookInstall (fReset, &dCount))

== STATUS_SUCCESS))

{

ns = SpyOutputDword (dCount,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_HOOK_REMOVE:

{

if (((ns = SpyInputBool (&fReset,

pInput, dInput))

== STATUS_SUCCESS)

&&

((ns = SpyHookRemove (fReset, &dCount))

== STATUS_SUCCESS))

{

ns = SpyOutputDword (dCount,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_HOOK_PAUSE:

{

if ((ns = SpyInputBool (&fPause,

pInput, dInput))

== STATUS_SUCCESS)

{

fPause = SpyHookPause (fPause);

ns = SpyOutputBool (fPause,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_HOOK_FILTER:

{

if ((ns = SpyInputBool (&fFilter,

pInput, dInput))

== STATUS_SUCCESS)

{

fFilter = SpyHookFilter (fFilter);

ns = SpyOutputBool (fFilter,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_HOOK_RESET:

{

SpyHookReset ();

ns = STATUS_SUCCESS;

break;

}

case SPY_IO_HOOK_READ:

{

if ((ns = SpyInputBool (&fLine,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputHookRead (fLine,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_HOOK_WRITE:

{

SpyHookWrite (pInput, dInput);

ns = STATUS_SUCCESS;

break;

}

case SPY_IO_MODULE_INFO:

{

if ((ns = SpyInputPointer (&pbName,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputModuleInfo (pbName,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_PE_HEADER:

{

if ((ns = SpyInputPointer (&pAddress,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputPeHeader (pAddress,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_PE_EXPORT:

{

if ((ns = SpyInputPointer (&pAddress,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputPeExport (pAddress,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_PE_SYMBOL:

{

if ((ns = SpyInputPointer (&pbName,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputPeSymbol (pbName,

pOutput, dOutput, pdInfo);

}

break;

}

case SPY_IO_CALL:

{

if ((ns = SpyInputBinary (&sci, SPY_CALL_INPUT_,

pInput, dInput))

== STATUS_SUCCESS)

{

ns = SpyOutputCall (&sci,

pOutput, dOutput, pdInfo);

}

break;

}

}

MUTEX_RELEASE (pDeviceContext->kmDispatch);

return ns;

}

列表 4-7. Spy 驅動程序的內部命令 Dispatcher

#define CTL_CODE (DeviceType, Function, Method, Access)

(( (DeviceType) << 16 ) | ( Access << 14 ) | ( (Function) << 2 ) (Method) )

列表 4-8. 用來構建 I/O 控制編碼的 CTL_CODE() 宏

DDK 的主要頭文件 ntddk.h 和 SDK 中的 Win32 文件 winioctl.h 均定義了一個簡單但非常有用的宏 ---- CTL_CLOSE() ,如 列表 4-8 所示。該宏可方便的建立 4-6 所示的 IOCTL 編碼。該編碼中的四個部分分別服務于以下四個目的:

1. DeviceType 這是一個 16 位的設備類型 ID 。 ntddk.h 列出了一對預定義的類型,由符號常量 FILE_DEVICE_* 表示。 0x0000 到 0x7FFF 保留給微軟內部使用,開發人員可使用 0x8000 到 0xFFFF 。 Spy 驅動程序定義了它自己的設備 ID : FILE_DEVICE_SPY ,其值為 0x8000 。

2. 2 位的訪問檢查值用來確定 IOCTL 操作所需的訪問權限。可能的值有: FILE_ANY_ACCESS (0) , FILE_READ_ACCESS (1) , FILE_WRITE_ACCESS (2) 和最后兩個的組合: FILE_READ_ACCESS | FILE_WRITE_ACCESS (3) 。詳見 ntddk.h 。

3. 12 個位的 ID 表示所選擇的操作函數,所選操作將由設備來執行。 0x0000 到 0x7FFF 保留給微軟內部使用,開發人員可使用 0x8000 到 0xFFFF 。 Spy 設備采用的 IOCTL 函數 ID 位于 0x8000 到 0xFFFF 。

4. 傳輸模式占用 2 個位,可在四個可用 I/O 傳輸模式中選擇一個,這四個模式為: METHOD_BUFFERED (0) , METHOD_IN_DIRECT (1) , METHOD_OUT_DIRECT (2) 和 METHOD_NETTHER (3) ,可在 ntddk.h 中找到這些定義。 Spy 設備針對所有請求使用 METHOD_BUFFERED ,這是一個非常安全但有些慢的模式,因為數據需要在客戶端和系統緩沖區之間進行復制。因為 Memory Spy 對 I/O 的處理速度并不敏感,所以選擇安全是一個不錯的注意。如果你希望知道其他模式的細節,請參考我在 Windows Developer's Journal(Schreiber 1997) 發表的文章“ A Spy Filter Driver for Windows NT ”

表 4-2 列出了 w2k_spy.sys 支持的所有 IOCTL 函數。 0 到 10 的函數 ID 為最基本的內存探測函數,絕大部分的任務都會用到它們;本章稍候將討論它們。剩余的函數 ID 從 11 到 23 分屬于不同的 IOCTL 組,在下一章我們將討論它們,在下一章,我們將討論 Native API hook 和在用戶模式下調用內核。注意某些 IOCTL 編碼需要寫入權限,由第 15 號位表示(參見 4-6 )。確切的說,所有形如 0x80006nnn 的 IOCTL 命令只需讀權限,而形如 0x8000Ennn 的命令需要讀 / 寫權限。典型的要求讀權限的例子是 CreateFile() ,它通過指定 dwDesiredAccess 參數為 GENERIC_READ 和 GENERIC_WRITE 的組合來打開設備。

表 4-2 最左面的函數名稱同樣出現在 SpyDispatcher() (見 列表 4-7 )中那個龐大的 switch/case 語句中。這些函數首先獲取設備的 dispatcher mutex ,這樣就能保證,如果一個以上的客戶端或一個多線程的程序和設備通訊時,在同一時間只有一個請求被執行。 MUTEX_WAIT() 是 KeWaitForMutexObject() 的外包宏( wrapper marco ), KeWaitForMutexObject() 至少需要 5 個參數。 KeWaitForMutexObject() 本身也是一個宏,它將傳入的參數向前傳遞給 KeWaitForSingleObject() 。 列表 4-9 給出了 MUTEX_WAIT() 以及它的伙伴 MUTEX_RELEASE() 和 MUTEX_INITIALIZE() 。在 mutex 對象變為有信號( signaled )狀態后,根據接收到的 IOCTL 編碼, SpyDispatcher() 會轉向不同的分支,每個分支都包含多種簡單的代碼序列。

表 4-2. w2k_spy.sys 支持的 IOCTL 函數

函數名稱

ID

IOCTL 編碼

SPY_IO_VERSION_INFO

0

0x80006000

返回 Spy 的版本信息

SPY_IO_OS_INFO

1

0x80006004

返回操作系統的版本信息

SPY_IO_SEGMENT

2

0x80006008

返回一個段的屬性

SPY_IO_INTERRUPT

3

0x8000600C

返回一個中斷門的屬性

SPY_IO_PHYSICAL

4

0x80006010

線性地址轉換為物理地址

SPY_IO_CPU_INFO

5

0x80006014

返回特殊 CPU 寄存器的值

SPY_IO_PDE_ARRAY

6

0x80006018

返回位于 0xC0300000 的 PDE 數組

SPY_IO_PAGE_ENTRY

7

0x8000601C

Return the PDE or PTE of a linear address

SPY_IO_MEMORY_DATA

8

0x80006020

返回內存塊中的內容

SPY_IO_MEMORY_BLOCK

9

0x80006024

返回內存塊中的內容

SPY_IO_HANDLE_INFO

10

0x80006028

從句柄中查找對象屬性

SPY_IO_HOOK_INFO

11

0x8000602C

返回有關 Native API Hook 的信息

SPY_IO_HOOK_INSTALL

12

0x8000E030

安裝 Native API Hook

SPY_IO_HOOK_REMOVE

13

0x8000E034

移除一個 Native API Hook

SPY_IO_HOOK_PAUSE

14

0x8000E038

暫停 / 恢復 Hook 協議

SPY_IO_HOOK_FILTER

15

0x8000E03C

允許 / 禁止 Hook 協議過濾器

SPY_IO_HOOK_RESET

16

0x8000E040

清除 Hook 協議

SPY_IO_HOOK_READ

17

0x8000E044

從 Hook 協議中讀取數據

SPY_IO_HOOK_WRITE

18

0x8000E048

向 Hook 協議中寫入輸入

SPY_IO_MODULE_INFO

19

0x8000E04C

返回已加載模塊的信息

SPY_IO_PE_HEADER

20

0x8000E050

返回 IMAGE_NT_HEADERS 數據

SPY_IO_PE_EXPORT

21

0x8000E054

返回 IMAGE_EXPORT_DirectorY 數據

SPY_IO_PE_SYMBOL

22

0x8000E058

返回導出的系統符號的地址

SPY_IO_CALL

23

0x8000E05C

調用已加載模塊中的一個函數

#define MUTEX_INITIALIZE(_mutex)

KeInitializeMutex

(&(_mutex), 0)

#define MUTEX_WAIT(_mutex)

KeWaitForMutexObject

(&(_mutex), Executive, KernelMode, FALSE, NULL)

#define MUTEX_RELEASE(_mutex)

KeReleaseMutex

(&(_mutex), FALSE)

列表 4-9. 管理 Kernel-Mutex 的宏

SpyDispatcher() 使 用一對幫助函數來讀取輸入參數,以獲取被請求的數據,并將產生的數據寫入調用者提供的輸出緩沖區中。就像前面提到的,內核模式的驅動程序總是過分挑剔的對 待它接受到的來自用戶模式的參數。以驅動程序的觀點來看,所有用戶模式下的代碼都是有害的,它們除了讓系統崩潰就什么都不知道了。這種多少有些多疑癥的觀 點并不是荒謬的 ---- 僅有很小的比率會導致整個系統立即終止,同時出現藍屏。因此,如果一個客戶端程序說:“這是我的緩沖區 ----- 它最多可容納 4,096 個字節”,驅動程序不會接受這個緩沖區 ---- 即使該緩沖區指向有效的內存,并且其大小也是正確的。在 IOCTL 的可緩沖的 I/O 模式( Buffered I/O )下(如果 IOCTL 編碼的模式部分為 METHOD_BUFFERED ),系統會很小心的檢查并分配一個足夠容納所有輸入 / 輸出數據的緩沖區。然而,其他的 I/O 傳輸模式,尤其是 METHOD_NETTHER ,驅動程序會接受原始的用戶模式的緩沖區指針。

標簽: Windows系統
主站蜘蛛池模板: 麻豆传媒网站入口直接进入免费版 | 亚洲一级毛片免费看 | 久久99精品久久久久久秒播放器 | 亚洲狠狠ady亚洲精品大秀 | 黄色录像欧美 | 精品无码久久久久久国产 | 国产三级毛片视频 | 伊人久久在线观看 | 狠狠色噜噜狠狠狠狠狠色综合久久 | 亚洲 欧美 日韩 在线 | 亚洲国产欧美日韩第一香蕉 | 国产系列欧美系列日韩系列在线 | 国产最强大片免费视频 | 特级免费毛片 | 久久综合九色综合国产 | 欧美一二三区在线 | 草草草在线观看 | 屁屁影院一区二区三区 | 日本九九热 | 成年人免费黄色 | 谁有免费黄色网址 | 天天看天天射天天碰 | 在线观看免费高清激情爱爱 | 国产永久免费高清动作片www | 欧洲色图亚洲色图 | 欧美级毛片 | 在线免费观看亚洲视频 | 成人精品国产亚洲 | 精品国产不卡一区二区三区 | 欧美女交| 国产挤奶水在线视频播放 | 午夜窝窝 | 黑人香蕉又粗又大视频免费 | 国产精品日本一区二区不卡视频 | 久热这里只精品99re8久 | 黄色网址免费看 | 老人与老人免费a级毛片 | 精品久久一区二区 | 久久黄色一级片 | 一级毛片免费 | 亚洲欧美一区二区三区久久 |