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

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

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

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

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

翻譯: Kendiv( fcczj@263.net )

更新: Tuesday, February 22, 2005

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

請求式分頁動作

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

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

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

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

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

示列 4-11 觀察 PTE 的狀態(tài)變化

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

更多的命令選項

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

Spy 設備的接口

現(xiàn)在你已經知道如何使用 w2k_mem 了,該是介紹它是如何工作的了?,F(xiàn)在來看看這個程序是如何與 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 需要該結構。我們不需要發(fā)送異步請求,所以該參數總是 NULL 。

列表 4-28 列出了所有執(zhí)行基本 IOCTL 操作的外包函數。最基本的一個是: IoControl() ,該函數調用 DeviceControl() 并測試返回的輸出數據的大小。因為 w2k_mem.exe 精確的提供了輸出緩沖區(qū)的大小,所以,輸出的字節(jié)數應該總是等于緩沖區(qū)的大小。 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 的外包函數

到目前為止,本節(jié)列出的所有函數都需要 Spy 設備的一個句柄。現(xiàn)在,我將介紹如何獲取該句柄。這實際上是一個非常簡單的 Win32 操作,和打開文件類似。 列表 4-29 展示了 w2k_mem.exe 的命令處理例程的實現(xiàn)細節(jié)。該代碼使用 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 的源代碼中發(fā)現(xiàn)設備相關的定義, 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() 。該函數可打開或創(chuàng)建 Windows 2000 中幾乎所有可被打開和創(chuàng)建的東西。如果提供了內核設備的符號鏈接名,形如 .<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() 函數將被調用兩次,第一次調用只是簡單的檢查命令行中是否有無效的參數,并顯示任何可能的錯誤。第二次調用則執(zhí)行所有的命令。我不想討論該函數的細節(jié)。 列表 4-29 中的剩余代碼是為了進行清理工作,如關閉句柄和卸載 Spy 驅動(該功能是可選的)。 w2k_mem.exe 的源代碼中還有一些有趣的代碼片斷,但我不在這里討論它們了。請參考本書光盤的 srcw2k_mem 目錄下的 w2k_mem.c 和 w2k_mem.h 。

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

深入 Windows 2000 內存

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

基本的操作系統(tǒng)信息

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

示列 4-12. 顯示操作系統(tǒng)信息

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

主站蜘蛛池模板: 亚洲福利精品一区二区三区 | 亚洲一区二区三区在线网站 | 一级做a爰片久久毛片唾 | 国产精品一区二区在线观看 | 亚洲成人偷拍自拍 | 国产三级毛片 | 亚洲成年人免费网站 | 久久中文亚洲国产 | 亚洲人欧洲日韩 | 欧美不卡一区二区三区 | 久久久久欧美情爱精品 | 久久99久久99精品免观看 | 日本在线视频观看 | 欧美色欧美色 | 韩国一级片视频 | 国产欧美日韩综合二区三区 | 亚洲高清一区二区三区久久 | 岛国毛片在线观看 | 91在线精品亚洲一区二区 | 久久久久久一级毛片免费野外 | 国产成人久久精品 | 亚洲欧洲日韩综合色天使不卡 | 天堂1在线观看 | 日本成年人视频网站 | 日韩国产欧美一区二区三区在线 | 99久久国产综合精品网成人影院 | 五月激激激综合网色播免费 | 全部孕妇毛片 | 日p免费视频 | 一级片日韩 | 久久国内精品自在自线观看 | 亚洲伊人色一综合网 | 免费a网 | 女人一级特纯黄大片色 | 欧美午夜不卡在线观看最新 | 精品亚洲成a人在线播放 | 黄色毛片国产 | 免费观看成年人视频 | 欧美毛片性视频区 | 欧美综合一区二区三区 | 亚洲区精品久久一区二区三区 |