国产成人精品久久免费动漫-国产成人精品天堂-国产成人精品区在线观看-国产成人精品日本-a级毛片无码免费真人-a级毛片毛片免费观看久潮喷

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

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

瀏覽:103日期:2023-08-27 13:59:20

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

翻譯: Kendiv( fcczj@263.net )

更新: Tuesday, February 22, 2005

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

請求式分頁動作

在討論 Spy 設備的 SPY_IO_MEMORY_DATA 函數時,我提到過該函數可以讀取已被置換到頁面文件中的內存頁。要證明這一點,首先,必須讓系統處于低內存狀態,以強迫它將不馬上使用的數據置換到頁面文件中。我喜歡采用的方法如下:

1. 使用 PrintKey ,將 Windows 2000 的桌面復制到剪切板中。

2. 將該圖片粘貼到一個圖形處理程序中。

3. 將該圖片的尺寸放到最大。

現在,執行命令: w2k_mem +d #16 0xC02800000 0xA0000000 0xA0001000 0xA0002000 0xC0280000 ,察看它在屏幕上的輸出。你可能會驚訝。在觸及某些 PTE 所引用的頁之前,它會獲取這些 PTE 的快照。在地址 0xC0280000 處發現的四個 PTE 與地址范圍: 0xA0000000---0xA0003FFF 相關,這是內核模塊 win32k.sys 的一部分。如 示列 4-11 所示,該地址范圍已經被置換出去了,因為在地址 0xC0280000 的四個 DWord 都是偶數,這意味著它們的最低位(即 PTE 的 P 位)為零,這表示沒有存在于物理內存中的頁。接下來的三塊 16 進制 Dump 信息屬于 0xA0000000 、 0xA0001000 、 0xA0002000 , w2k_mem 可以毫無問題的訪問這些頁(系統會根據請求將它們再次換入內存)。

示列 4-11 觀察 PTE 的狀態變化

在開始下一節之前,請再次研究一下 示列 4-11 中的第一欄。位于地址 0xC0280000 的四個 PTE 看上去都很像。但事實上,它們僅有最低的三個位不同。如果你檢查所有位于頁面文件中的 PNPE ,你會發現它們的第 10 位都為 1 。這就是為什么我在 列表 4-3 中,將該位的名字取為 PageFile 。如果該位為 1 ,除 P 位外的所有位都將用來表示該頁在頁面文件中的位置。

更多的命令選項

示列 4-1 給出的某些命令選項還沒有解釋過。例如,系統狀態選項: +o 、 +c 、 +g 、 +i 和 +b ,我會在本章的最后一節介紹它們,在那兒我們將發現幾個 Windows 2000 內存系統的秘密。

Spy 設備的接口

現在你已經知道如何使用 w2k_mem 了,該是介紹它是如何工作的了。現在來看看這個程序是如何與 w2k_spy.sys 中的 Spy 設備通訊的。

回顧 ----- 設備 I/O 控制( Device I/O Control

IOCTL 通訊的內核模式端已經由 列表 4-6 列表 4-7 給出了。 Spy 設備只是簡單的等待 IRP 并處理其中的某些 IRP ,尤其是標識為 IPR_MJ_DEVICE_CONTROL ,其中的一些請求在用戶模式下是被禁止的。調用 Win32 API 函數 DeviceIoControl() , 列表 4-27 給出了該函數的原型。可能你已經熟悉了 dwIocontrolCode 、 lpInBuffer 、 nInBufferSize 、 lpOutBuffer 、 nOutBufferSize 和 lpBytesReturned 參數。事實上,它們一一對應于: SpyDispatcher() 的 dCode 、 pInput 、 dInput 、 pOutput 、 dOutput 和 pdInfo 參數, SpyDispatcher 定義于 列表 4-7 。剩下的參數很快就會解釋。 hDevice 是 Spy 設備的句柄, lpOverlapped (可選的)指向一個 OVERLAPPED 結構,異步 IOCTL 需要該結構。我們不需要發送異步請求,所以該參數總是 NULL 。

列表 4-28 列出了所有執行基本 IOCTL 操作的外包函數。最基本的一個是: IoControl() ,該函數調用 DeviceControl() 并測試返回的輸出數據的大小。因為 w2k_mem.exe 精確的提供了輸出緩沖區的大小,所以,輸出的字節數應該總是等于緩沖區的大小。 ReadBinary() 是 IoControl() 的簡單版本,它不需要輸入數據。 ReadCPUInfo() 、 ReadSegment() 和 ReadPhysical() 專用于 Spy 函數 SPY_IO_CPU_INFO 、 SPY_IO_SEGEMNT 和 SPY_IO_PHYSICAL ,因為它們會經常被用到。將它們封裝為 C 函數,可讀性會更好些。

BOOL WINAPI DeviceIoControl( HANDLE hDevice,

DWORD dwIoControlCode,

PVOID lpInBuffer,

DWORD nInBufferSize,

PVOID lpOutBuffer,

DWORD nOutBufferSize,

PDWORD lpBytesReturned,

POVERLAPPED lpOverlapped);

列表 4-27. DeviceIoControl 函數的原型

BOOL WINAPI IoControl (HANDLE hDevice,

DWORD dCode,

PVOID pInput,

DWORD dInput,

PVOID pOutput,

DWORD dOutput)

{

DWORD dData = 0;

return DeviceIoControl (hDevice, dCode,

pInput, dInput,

pOutput, dOutput,

&dData, NULL)

&&

(dData == dOutput);

}

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

BOOL WINAPI ReadBinary (HANDLE hDevice,

DWORD dCode,

PVOID pOutput,

DWORD dOutput)

{

return IoControl (hDevice, dCode, NULL, 0, pOutput, dOutput);

}

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

BOOL WINAPI ReadCpuInfo (HANDLE hDevice,

PSPY_CPU_INFO psci)

{

return IoControl (hDevice, SPY_IO_CPU_INFO,

NULL, 0,

psci, SPY_CPU_INFO_);

}

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

BOOL WINAPI ReadSegment (HANDLE hDevice,

DWORD dSelector,

PSPY_SEGMENT pss)

{

return IoControl (hDevice, SPY_IO_SEGMENT,

&dSelector, DWORD_,

pss, SPY_SEGMENT_);

}

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

BOOL WINAPI ReadPhysical (HANDLE hDevice,

PVOID pLinear,

PPHYSICAL_ADDRESS ppa)

{

return IoControl (hDevice, SPY_IO_PHYSICAL,

&pLinear, PVOID_,

ppa, PHYSICAL_ADDRESS_)

&&

(ppa->LowPart || ppa->HighPart);

}

列表 4-28 幾個 IOCTL 的外包函數

到目前為止,本節列出的所有函數都需要 Spy 設備的一個句柄。現在,我將介紹如何獲取該句柄。這實際上是一個非常簡單的 Win32 操作,和打開文件類似。 列表 4-29 展示了 w2k_mem.exe 的命令處理例程的實現細節。該代碼使用 API 函數 w2kFilePath() 、 w2kServiceLoad() 和 w2kServiceUnload() ,這幾個函數由 w2k_lib.dll 導出。如果你已經讀過第三章中關于 Windows 2000 服務控制管理器的介紹,你應該通過 列表 3-8 已了解了 w2kServiceLoad() 和 w2kServiceUnload() 。這些強大的函數可隨時加載或卸載內核模式的設備驅動,并且能處理一些良性的錯誤,如,妥善的處理加載一個已經載入內存的驅動程序。 w2kFilePath() 是一個幫助函數。 w2k_mem.exe 調用它來獲取 Spy 驅動程序的完整路徑。

WORD awSpyFile [] = SW(DRV_FILENAME);

WORD awSpyDevice [] = SW(DRV_MODULE);

WORD awSpyDisplay [] = SW(DRV_NAME);

WORD awSpyPath [] = SW(DRV_PATH);

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

void WINAPI Execute (PPWORD ppwArguments,

DWORD dArguments)

{

SPY_VERSION_INFO svi;

DWORD dOptions, dRequest, dReceive;

WORD awPath [MAX_PATH] = L'?';

SC_HANDLE hControl = NULL;

HANDLE hDevice = INVALID_HANDLE_VALUE;

_printf (L'rnLoading '%s' (%s) ...rn',

awSpyDisplay, awSpyDevice);

if (w2kFilePath (NULL, awSpyFile, awPath, MAX_PATH))

{

_printf (L'Driver: '%s'rn',

awPath);

hControl = w2kServiceLoad (awSpyDevice, awSpyDisplay,

awPath, TRUE);

}

if (hControl != NULL)

{

_printf (L'Opening '%s' ...rn',

awSpyPath);

hDevice = CreateFile (awSpyPath, GENERIC_READ,

FILE_SHARE_READ | FILE_SHARE_WRITE,

NULL, OPEN_EXISTING,

FILE_ATTRIBUTE_NORMAL, NULL);

}

else

{

_printf (L'Unable to load the spy device driver.rn');

}

if (hDevice != INVALID_HANDLE_VALUE)

{

if (ReadBinary (hDevice, SPY_IO_VERSION_INFO,

&svi, SPY_VERSION_INFO_))

{

_printf (L'rn%s V%lu.%02lu readyrn',

svi.awName,

svi.dVersion / 100, svi.dVersion % 100);

}

dOptions = COMMAND_OPTION_NONE;

dRequest = CommandParse (hDevice, ppwArguments, dArguments,

TRUE, &dOptions);

dOptions = COMMAND_OPTION_NONE;

dReceive = CommandParse (hDevice, ppwArguments, dArguments,

FALSE, &dOptions);

if (dRequest)

{

_printf (awSummary,

dRequest, (dRequest == 1 ? awByte : awBytes),

dReceive, (dReceive == 1 ? awByte : awBytes));

}

_printf (L'rnClosing the spy device ...rn');

CloseHandle (hDevice);

}

else

{

_printf (L'Unable to open the spy device.rn');

}

if ((hControl != NULL) && gfSpyUnload)

{

_printf (L'Unloading the spy device ...rn');

w2kServiceUnload (awSpyDevice, hControl);

}

return;

}

列表 4-29. 控制 Spy 設備

請注意 列表 4-29 頂部給出的四個全局字符串的定義。常量 DRV_FILENAME 、 DRV_MODULE 、 DRV_NAME 和 DRV_PATH 來自 Spy 驅動的頭文件 w2k_spy.h 。 4-4 列出了它們的當前值。你不會在 w2k_mem.exe 的源代碼中發現設備相關的定義, w2k_spy.h 提供了客戶端程序所需的一切。這非常重要:如果以后改變了任何設備相關的定義,就不需要更新任何程序文件了。只需要以新的頭文件編譯、鏈接程序即可。

列表 4-29 頂部調用的 w2kFilePath() 可以保證由全局變量 awSpyFile (見 4-4 )指定的 w2k_spy.sys 總是從 w2k_mem.exe 所在目錄中加載。接下來, 列表 4-29 中的代碼將全局字符串 awSpyDevice 和 awSpyDisplay ()傳遞給 w2kServiceLoad() ,以加載 Spy 設備的驅動。如果驅動沒有被加載,這些字符串將被保存在驅動的屬性列表中,可以由其他程序取出;否則,將保留當前的屬性設置。盡管 列表 4-29 中的 w2kServiceLoad() 調用可返回一個句柄,但這并不是一個可用于任何 IOCTL 函數的句柄。要獲取 Spy 設備的句柄,必須使用 Win32 的多用途函數 CreateFile() 。該函數可打開或創建 Windows 2000 中幾乎所有可被打開和創建的東西。如果提供了內核設備的符號鏈接名,形如 .<SymbolicLink > 給 CreateFile() 的 lpFileName 參數,那么該函數就可打開這個內核設備。 Spy 設備的符號鏈接名是: w2k_spy ,因此, CreateFile() 的第一個參數必須是 .w2k_spy ,這正是 4-4 中的 awSpyPath 的值。

表 4-4. 設備相關的字符串定義

w2k_spy 常量

w2k_mem 變量

DRV_FILENAME

awSpyFile

w2k_spy.sys

DRV_MODULE

awSpyDevice

w2k_spy

DRV_NAME

awSpyDisplay

SBS Windows 2000 Spy Device

DRV_PATH

awSpyPath

. w2k_spy

如果 CreateFile() 成功,它將返回一個設備的句柄,該句柄可傳遞給 DeviceIoControl() 。 列表 4-29 中的 Execute() 函數使用該句柄來查詢 Spy 設備的版本信息,如果 IOCTL 調用成功,該信息將會在屏幕上顯示出來。接下來, CommandParser() 函數將被調用兩次,第一次調用只是簡單的檢查命令行中是否有無效的參數,并顯示任何可能的錯誤。第二次調用則執行所有的命令。我不想討論該函數的細節。 列表 4-29 中的剩余代碼是為了進行清理工作,如關閉句柄和卸載 Spy 驅動(該功能是可選的)。 w2k_mem.exe 的源代碼中還有一些有趣的代碼片斷,但我不在這里討論它們了。請參考本書光盤的 srcw2k_mem 目錄下的 w2k_mem.c 和 w2k_mem.h 。

現在唯一需要注意的就是 gfSpyUnload 標志,該標志決定是否卸載 Spy 驅動。我已經將這個全局標志設為了 FALSE ,因此不會自動卸載該驅動。這提高 w2k_mem.exe 或 w2k_spy.sys 的任何客戶端的性能,因為加載一個驅動需要花費一定的時間。只有第一個客戶端會產生加載開銷。這種設置還可避免多個客戶端間的競爭,如,一個客戶試圖卸載該驅動而此時另一個還在使用這個驅動。當然, Windows 2000 不會卸載一個驅動,除非該驅動的所有句柄都被關閉了,但系統會將驅動置于 STOP_PENDING 狀態,這樣新的客戶端將無法訪問此設備。不過,如果你不在一個多客戶端的環境下運行 w2k_spy.sys ,而且你需要經常更新設備的驅動程序,你就應該將 gfSpyUnload 標志設為 TRUE 。

深入 Windows 2000 內存

引入用戶模式和內核模式的獨立 4GB 地址空間被再次劃分為多個更小的塊。正如你可能猜到的,它們中的大多數都包含未文檔化的結構,而且服務于未文檔化的地目的。其中某些東西對于任何開發系統診斷或調試軟件的人來說都是真正的金礦。

基本的操作系統信息

如果你注意過 示列 4-1 下半部分的幫助信息,你會發該節的標題是:“系統狀態選項”。現在試試名為“顯示操作系統信息”的選項: +o 。 示列 4-12 給出了在我的機器上使用該選項的輸出結果。這里顯示的信息都是 SPY_OS_INFO 結構的內容,該結構定義與 列表 4-13 ,由 Spy 設備函數 SpyOutputOsInfo() 實際創建該結構,此函數也包含在 列表 4-13 中。在 示列 4-12 中,你可以看到位于 4GB 地址空間中的進程的一些典型地址。例如,有效的用戶地址范圍是: 0x00010000 ---- 0x7FFFFFFF 。你可能閱讀過其他有關 Windows NT 或 2000 的程序設計書籍,用戶模式的第一個和最后一個 64KB 線性內存區域是“不能訪問區域”,訪問這一區域將引發一個錯誤(參見第五章, Solomon 1998 ), W2k_mem.exe 輸出證明了這一點。

示列 4-12. 顯示操作系統信息

示列 4-12 中的最后三行包含的信息非常有趣,它們都是有關系統的。這些信息大部分都取自位于地址 0xFFDF0000 處的 SharedUserData 區域中。系統在該處維護一個名為 KUSER_SHARED_DATA 的結構,該結構定義于 DDK 頭文件 ntddk.h 。

標簽: Windows系統
主站蜘蛛池模板: 亚洲第十色| 夜夜操夜夜爽 | 国产亚洲人成网站在线观看 | 久久综合免费视频 | 国产91精品露脸国语对白 | 美女网站在线 | 成年男女免费视频 | 欧美日韩一区二区三区四区在线观看 | 三级毛片在线免费观看 | 精品成人毛片一区二区视 | 另类专区 亚洲 | 91精品手机国产在线能 | 成人ab片 | 美女操男人 | 欧美日韩精品一区三区 | 成年美女黄网站色大 | 女高中生被cao到哭视频 | 成年人免费毛片 | 成年女人毛片免费视频 | 成人亚洲国产 | 美国三级在线观看 | 国产欧美日韩综合一区二区三区 | 国产成人女人视频在线观看 | 99精品国产成人一区二区 | 欧美成年 | 在线欧洲成人免费视频 | 一级毛片在线完整免费观看 | 91精品手机国产露脸 | 亚洲综合视频网 | 牛牛本精品99久久精品88m | 亚洲制服丝袜美腿亚洲一区 | 国产一区亚洲二区 | 国产在线观看一区二区三区四区 | 91久久99热青草国产 | 国产精品日韩欧美一区二区三区 | 女人张开双腿让男人桶爽免 | 欧美在线一级va免费观看 | 九九九九九九精品免费 | 国产精品午夜免费观看网站 | 欧美色老头oldvideo | 亚洲欧美一区二区三区国产精品 |