日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

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

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

瀏覽:174日期:2023-08-27 15:06:14

第四章 探索 Windows 2000 的內(nèi)存管理機制

翻譯: Kendiv ( fcczj@263.net )

更新: Sunday, February 17, 2005

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

盡管 Spy 設(shè)備使用可緩沖的 I/O ,但它還是會檢查輸入 / 輸出緩沖區(qū)的有效性。因為客戶端程序傳入的數(shù)據(jù)可能比所需的少或者提供的緩沖區(qū)不夠容納輸出數(shù)據(jù)。系統(tǒng)不能捕獲這些語意錯誤,因為它不知道在一次 IOCTL 傳輸中所傳輸?shù)臄?shù)據(jù)的類型。因此, SpyDispatcher() 調(diào)用幫助函數(shù) SpyInput*() 和 SpyOutput*() 來從 I/O 緩沖區(qū)中復(fù)制或?qū)懭霐?shù)據(jù)。這些函數(shù)僅在緩沖區(qū)大小與操作的需求相匹配時才執(zhí)行。 列表 4-10 給出了基本的輸入函數(shù), 列表 4-11 給出了基本的輸出函數(shù)。 SpyInputBinary() 和 SpyOutputBinary() 被廣泛的使用,它們測試緩沖區(qū)的大小,如果 OK ,則使用 Windows 2000 運行時庫函數(shù) RtlCopyMemory() 復(fù)制被請求的數(shù)據(jù)。剩余的函數(shù)只是上述兩個基本函數(shù)的簡單外包,用來操作常見的數(shù)據(jù)類型 DWord , BOOL , PVOID 和 HANDLE 等。 SpyOutputBlock() 復(fù)制由調(diào)用者在 SPY_MEMORY_BLOCK 結(jié)構(gòu)中指定的數(shù)據(jù)塊,當(dāng)然這需要首先驗證請求范圍內(nèi)的字節(jié)都是可讀的。如果傳入的輸入緩沖區(qū)的大小不正確, SpyInput*() 函數(shù)將返回 STATUS_INVALID_BUFFER_SIZE ,如果輸出緩沖區(qū)比需要的小, SpyOutput*() 函數(shù)將返回 STATUS_BUFFER_TOO_SMALL 。

NTSTATUS SpyInputBinary (PVOID pData,

DWORD dData,

PVOID pInput,

DWORD dInput)

{

NTSTATUS ns = STATUS_INVALID_BUFFER_SIZE;

if (dData <= dInput)

{

RtlCopyMemory (pData, pInput, dData);

ns = STATUS_SUCCESS;

}

return ns;

}

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

NTSTATUS SpyInputDword (PDWORD pdValue,

PVOID pInput,

DWORD dInput)

{

return SpyInputBinary (pdValue, DWORD_, pInput, dInput);

}

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

NTSTATUS SpyInputBool (PBOOL pfValue,

PVOID pInput,

DWORD dInput)

{

return SpyInputBinary (pfValue, BOOL_, pInput, dInput);

}

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

NTSTATUS SpyInputPointer (PPVOID ppAddress,

PVOID pInput,

DWORD dInput)

{

return SpyInputBinary (ppAddress, PVOID_, pInput, dInput);

}

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

NTSTATUS SpyInputHandle (PHANDLE phObject,

PVOID pInput,

DWORD dInput)

{

return SpyInputBinary (phObject, HANDLE_, pInput, dInput);

}

列表 4-10. 從 IOCTL 緩沖區(qū)中讀取輸入數(shù)據(jù)

NTSTATUS SpyOutputBinary (PVOID pData,

DWORD dData,

PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

NTSTATUS ns = STATUS_BUFFER_TOO_SMALL;

*pdInfo = 0;

if (dData <= dOutput)

{

RtlCopyMemory (pOutput, pData, *pdInfo = dData);

ns = STATUS_SUCCESS;

}

return ns;

}

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

NTSTATUS SpyOutputBlock (PSPY_MEMORY_BLOCK psmb,

PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

NTSTATUS ns = STATUS_INVALID_PARAMETER;

if (SpyMemoryTestBlock (psmb->pAddress, psmb->dBytes))

{

ns = SpyOutputBinary (psmb->pAddress, psmb->dBytes,

pOutput, dOutput, pdInfo);

}

return ns;

}

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

NTSTATUS SpyOutputDword (DWORD dValue,

PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

return SpyOutputBinary (&dValue, DWORD_,

pOutput, dOutput, pdInfo);

}

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

NTSTATUS SpyOutputBool (BOOL fValue,

PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

return SpyOutputBinary (&fValue, BOOL_,

pOutput, dOutput, pdInfo);

}

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

NTSTATUS SpyOutputPointer (PVOID pValue,

PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

return SpyOutputBinary (&pValue, PVOID_,

pOutput, dOutput, pdInfo);

}

列表 4-11. 向 IOCTL 的緩沖區(qū)中寫入數(shù)據(jù)

你可能注意到 列表 4-7 中的 SpyDispatcher() 還引用了其他的 SpyInput*() 和 SpyOutput*() 函數(shù)。盡管這些函數(shù)最終還是調(diào)用 SpyInputBinary() 和 SpyOutputBinary() ,但它們還是比 列表 4-10 4-11 中的基本函數(shù)要復(fù)雜些,因此,稍后我們在討論它們。現(xiàn)在,讓我們從 SpyDispatcher() 開始,一步步的分析它的 switch/case 語句。

IOCTL 函數(shù) SPY_IO_VERSION_INFO

IOCTL 的 SPY_IO_VERSION_INFO 函數(shù)用有關(guān) Spy 驅(qū)動自身的數(shù)據(jù)填充調(diào)用者提供的 SPY_VERSION_INFO 結(jié)構(gòu)。該功能不需要輸入?yún)?shù),需要使用 SpyOutputVersionInfo() 幫助函數(shù)。 列表 4-12 給出了該函數(shù)和 SPY_VERSION_INFO 結(jié)構(gòu),該函數(shù)很簡單,它將 dVersion 成員設(shè)置為 SPY_VERSION 常量(當(dāng)前是 100 ,表示 V1.00 ),該常量定義于 w2k_spy.h 中。然后復(fù)制驅(qū)動程序的符號化名稱,即字符串常量 DRV_NAME (“ SBS Windows 2000 Spy Device ”)到 awName 成員。通過整除 dVersion 可獲取主版本號,剩下的是次版本號。

typedef struct _SPY_VERSION_INFO

{

DWORD dVersion;

WORD awName [SPY_NAME];

}

SPY_VERSION_INFO, *PSPY_VERSION_INFO, **PPSPY_VERSION_INFO;

#define SPY_VERSION_INFO_ sizeof (SPY_VERSION_INFO)

NTSTATUS SpyOutputVersionInfo (PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

SPY_VERSION_INFO svi;

svi.dVersion = SPY_VERSION;

wcscpyn (svi.awName, USTRING (CSTRING (DRV_NAME)), SPY_NAME);

return SpyOutputBinary (&svi, SPY_VERSION_INFO_,

pOutput, dOutput, pdInfo);

}

列表 4-12. 獲取 Spy 驅(qū)動程序的版本信息

IOCTL 函數(shù) SPY_IO_OS_INFO

該函數(shù)比上一個有趣的多。它是另一個只有輸出的函數(shù),不需要輸入?yún)?shù),使用幾個操作系統(tǒng)的內(nèi)部參數(shù)來填充調(diào)用者提供的 SPY_OS_INFO 結(jié)構(gòu)。 列表 4-13 列出了該結(jié)構(gòu)的定義,和 Dispatcher 調(diào)用的 SpyOutputOsInfo() 幫助函數(shù)。有些結(jié)構(gòu)體成員只是被簡單的設(shè)為定義于 DDK 頭文件和 w2k_spy.h 中的常量;其他的將被設(shè)為從幾個內(nèi)部的內(nèi)核變量和結(jié)構(gòu)體中讀取的當(dāng)前值。在第二章中,你已經(jīng)了解了變量 NtBuildNumber 和 NtGlobalFlag (由 ntoskrnl.exe 導(dǎo)出,參見 附錄 B 中的 B-1 )。和其他的 Nt* 符號不同,這兩個符號不指向 API 函數(shù),而是指向位于內(nèi)核的 .data section 中的變量。在 Win32 世界里,導(dǎo)出變量是十分罕見的。不過, Windows 2000 的幾個內(nèi)核模塊都使用了這一技術(shù)。 Ntoskrnl.exe 導(dǎo)出了至少 55 個變量, ntdll.dll 提供了 4 個, hal.dll 提供了 1 個。 SpyOutputOsInfo() 將從 ntoskrnl.exe 導(dǎo)出的變量中復(fù)制 MmHighestUserAddress 、 MmUserProbeAddress 、 MmSystemRangeStart 、 NtGlobalFlag 、 KeI386MachineType 、 KeNumberProcessors 和 NtBuildNumber 到輸出緩沖區(qū)中。

當(dāng)一個模塊從另一個模塊中導(dǎo)入數(shù)據(jù)時,它需要使用 extern 關(guān)鍵字來通知編譯器和鏈接器。這會使鏈接器生成一個進(jìn)入模塊導(dǎo)出節(jié)的入口,并會解析符號名以確定其地址。有些 extern 聲明已經(jīng)包含在 ntddk.h 。 列表 4-13 給出了缺失的那些 extern 聲明。

extern PWORD NlsAnsiCodePage;

extern PWORD NlsOemCodePage;

extern PWORD NtBuildNumber;

extern PDWORD NtGlobalFlag;

extern PDWORD KeI386MachineType;

typedef struct _SPY_OS_INFO

{

DWORD dPageSize;

DWORD dPageShift;

DWORD dPtiShift;

DWORD dPdiShift;

DWORD dPageMask;

DWORD dPtiMask;

DWORD dPdiMask;

PX86_PE PteArray;

PX86_PE PdeArray;

PVOID pLowestUserAddress;

PVOID pThreadEnvironmentBlock;

PVOID pHighestUserAddress;

PVOID pUserProbeAddress;

PVOID pSystemRangeStart;

PVOID pLowestSystemAddress;

PVOID pSharedUserData;

PVOID pProcessorControlRegion;

PVOID pProcessorControlBlock;

DWORD dGlobalFlag;

DWORD dI386MachineType;

DWORD dNumberProcessors;

DWORD dProductType;

DWORD dBuildNumber;

DWORD dNtMajorVersion;

DWORD dNtMinorVersion;

WORD awNtSystemRoot [MAX_PATH];

}

SPY_OS_INFO, *PSPY_OS_INFO, **PPSPY_OS_INFO;

#define SPY_OS_INFO_ sizeof (SPY_OS_INFO)

NTSTATUS SpyOutputOsInfo (PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

SPY_SEGMENT ss;

SPY_OS_INFO soi;

NT_PRODUCT_TYPE NtProductType;

PKPCR pkpcr;

NtProductType = (SharedUserData->ProductTypeIsValid

? SharedUserData->NtProductType

: 0);

SpySegment (X86_SEGMENT_FS, 0, &ss);

pkpcr = ss.pBase;

soi.dPageSize = PAGE_SIZE;

soi.dPageShift = PAGE_SHIFT;

soi.dPtiShift = PTI_SHIFT;

soi.dPdiShift = PDI_SHIFT;

soi.dPageMask = X86_PAGE_MASK;

soi.dPtiMask = X86_PTI_MASK;

soi.dPdiMask = X86_PDI_MASK;

soi.PteArray = X86_PTE_ARRAY;

soi.PdeArray = X86_PDE_ARRAY;

soi.pLowestUserAddress = MM_LOWEST_USER_ADDRESS;

soi.pThreadEnvironmentBlock = pkpcr->NtTib.Self;

soi.pHighestUserAddress = *MmHighestUserAddress;

soi.pUserProbeAddress = (PVOID) *MmUserProbeAddress;

soi.pSystemRangeStart = *MmSystemRangeStart;

soi.pLowestSystemAddress = MM_LOWEST_SYSTEM_ADDRESS;

soi.pSharedUserData = SharedUserData;

soi.pProcessorControlRegion = pkpcr;

soi.pProcessorControlBlock = pkpcr->Prcb;

soi.dGlobalFlag = *NtGlobalFlag;

soi.dI386MachineType = *KeI386MachineType;

soi.dNumberProcessors = *KeNumberProcessors;

soi.dProductType = NtProductType;

soi.dBuildNumber = *NtBuildNumber;

soi.dNtMajorVersion = SharedUserData->NtMajorVersion;

soi.dNtMinorVersion = SharedUserData->NtMinorVersion;

wcscpyn (soi.awNtSystemRoot, SharedUserData->NtSystemRoot,

MAX_PATH);

return SpyOutputBinary (&soi, SPY_OS_INFO_,

pOutput, dOutput, pdInfo);

}

列表 4-13. 獲取有關(guān)操作系統(tǒng)的信息

SPY_OS_INFO 結(jié)構(gòu)的剩余成員會由位于內(nèi)存中的系統(tǒng)數(shù)據(jù)結(jié)構(gòu)填充。例如, SpyOutputOsInfo() 將內(nèi)核的進(jìn)程控制區(qū)域( Kernel's Processor Control Region, KPCR )的基地址賦值給 pProcessorControlRegion 成員。 KPCR 是一個非常重要的數(shù)據(jù)結(jié)構(gòu),該結(jié)構(gòu)包含很多線程相關(guān)的數(shù)據(jù)項,因此,它位于自己的內(nèi)存段中,該內(nèi)存段的地址由 CPU 的 FS 寄存器給出。 Windows NT 4.0 和 Windows 2000 都將 FS 指向處于內(nèi)核模式的線性地址 0xFFDFF000 。 SpyOutputOsInfo() 調(diào)用 SpySegment() 函數(shù)(稍后討論它)來查詢 FS 段在線性地址空間中的基地址。這個段中還包含內(nèi)核的進(jìn)程控制塊( Kernel's Processor Control Block, KPRCB ), KPCR 結(jié)構(gòu)的 Prcb 成員指向 KPRCB 結(jié)構(gòu)的首地址,緊隨其后的是一個 CONTEXT 結(jié)構(gòu),該結(jié)構(gòu)包含當(dāng)前線程的底層 CPU 信息。 KPCR 、 KPRCB 和 CONTEXT 結(jié)構(gòu)定義在 ntddk.h 頭文件中。

列表 4-13 中引用的另一個內(nèi)部數(shù)據(jù)結(jié)構(gòu)是 SharedUserData 。該結(jié)構(gòu)實際上是一個由一個“眾所周知的地址”通過類型轉(zhuǎn)化( TypeCast )得來的結(jié)構(gòu)體指針。 列表 4-14 給出了它在 ntddk.h 中的定義。那個“眾所周知的地址”位于線性地址空間中,它會在編譯時被設(shè)置,因此不需要花費額外的時間或進(jìn)行配置。顯然, SharedUserData 是一個指向 KUSER_SHARED_DATA 結(jié)構(gòu)的指針,該結(jié)構(gòu)的基地址在 0xFFDF0000 (這是一個線性地址)。這個內(nèi)存區(qū)域由系統(tǒng)和用戶模式的應(yīng)用程序共享,它包含像操作系統(tǒng)版本號這樣的數(shù)據(jù), SpyOutputOsInfo() 將該版本數(shù)據(jù)復(fù)制到 SPY_OS_INFO 結(jié)構(gòu)(由調(diào)用者提供)的 dNtMajorVersion 和 dNtMinorVersion 成員。就像我稍后要展示的那樣, KUSER_SHARED_DATA 結(jié)構(gòu)將被映射到 0x7FFE0000 ,這樣用戶模式的代碼就可以訪問它了。

在對 Spy 設(shè)備的 IOCTL 函數(shù)的講解之后還將提供了一個示例程序,該示例程序會把返回的數(shù)據(jù)顯示在屏幕上。

#define KI_USER_SHARED_DATA 0xFFDF0000

#define SharedUserData ((KUSER_SHARED_DATA *const)KI_USER_SHARED_DATA)

列表 4-14. SharedUserData 結(jié)構(gòu)定義

IOCTL 函數(shù) SPY_IO_SEGMENT

到現(xiàn)在討論以變得更加有趣了。 SPY_IO_SEGMENT 函數(shù)通過一些更底層的操作來查詢指定段的屬性,調(diào)用者需要首先給出一個選擇器( selector )。 SpyDispatcher() 首先調(diào)用 SpyInputDword() 來獲取由調(diào)用程序傳入的選擇器的值。你可能還記得選擇器( selector )是一個 16 位的數(shù)。不過,只要可能,我就會嘗試避免使用 16 位的數(shù)據(jù)類型,這是因為原生的 WORD 在 i386 CPU 的 32 位模式下是 32 位的 DWORD 類型。因此,我將選擇器參數(shù)擴展為 DWORD ,不過其高 16 位總是 0 。如果 SpyInputDword() 報告操作成功,接下來就會調(diào)用 SpyOutputSegemnt() 函數(shù)( 列表 4-15 給出了此函數(shù))。不管 SpySegment() 幫助函數(shù)如何, SpyOutputSegemnt() 總是返回到調(diào)用者。基本上來說, SpySegment() 將填充 SPY_SEGMENT 結(jié)構(gòu),該結(jié)構(gòu)定義于 列表 4-15 的頂部。它以 X86_SELECTOR 結(jié)構(gòu)(參見 列表 4-2 )的形式給出選擇器的值,緊隨其后的是 64 位的 X86_DESCRIPTOR ,以及相應(yīng)的段基址,段的大小限制以及一個名為 fOk 的標(biāo)志,該標(biāo)志用來指出 SPY_SEGMENT 結(jié)構(gòu)是否有效。在稍后的一些函數(shù)中需要一次返回多個段的屬性,利用 fOk 成員,調(diào)用者就可以將無效的段信息從輸出數(shù)據(jù)中篩選出來。

typedef struct _SPY_SEGMENT

{

X86_SELECTOR Selector;

X86_DESCRIPTOR Descriptor;

PVOID pBase;

DWORD dLimit;

BOOL fOk;

}

SPY_SEGMENT, *PSPY_SEGMENT, **PPSPY_SEGMENT;

#define SPY_SEGMENT_ sizeof (SPY_SEGMENT)

NTSTATUS SpyOutputSegment (DWORD dSelector,

PVOID pOutput,

DWORD dOutput,

PDWORD pdInfo)

{

SPY_SEGMENT ss;

SpySegment (X86_SEGMENT_OTHER, dSelector, &ss);

return SpyOutputBinary (&ss, SPY_SEGMENT_,

pOutput, dOutput, pdInfo);

}

BOOL SpySegment (DWORD dSegment,

DWORD dSelector,

PSPY_SEGMENT pSegment)

{

BOOL fOk = FALSE;

if (pSegment != NULL)

{

fOk = TRUE;

if (!SpySelector (dSegment, dSelector,

&pSegment->Selector))

{

fOk = FALSE;

}

if (!SpyDescriptor (&pSegment->Selector,

&pSegment->Descriptor))

{

fOk = FALSE;

}

pSegment->pBase =

SpyDescriptorBase (&pSegment->Descriptor);

pSegment->dLimit =

SpyDescriptorLimit (&pSegment->Descriptor);

pSegment->fOk = fOk;

}

return fOk;

}

列表 4-15. 查詢段的屬性

SpySegment() 函數(shù)依賴其他幾個幫助函數(shù),以構(gòu)建 SPY_SEGMENT 結(jié)構(gòu)的某些部分。首先, SpySelector() 復(fù)制一個選擇器的值到傳入的 X86_SELECTOR 結(jié)構(gòu)中。如果 SpySelector() 函數(shù)的第一個參數(shù) dSegment 被設(shè)置為 X86_SEGMENT_OTHER (即 0 ), dSelector 參數(shù)將假定已經(jīng)指定了一個有效的選擇器值,因此該值將被簡單的附給輸出結(jié)構(gòu) X86_SELECTOR 的 wValue 成員。否則, dSelector 將被忽略, dSegment 會被用于一個 switch/case 結(jié)構(gòu)中以便選擇一個段寄存器或任務(wù)寄存器 TR 。注意,這種請求需要少量的嵌入式匯編, C 語言沒有提供標(biāo)準(zhǔn)的方法訪問處理器相關(guān)的特性,如段寄存器。

#define X86_SEGMENT_OTHER 0

#define X86_SEGMENT_CS 1

#define X86_SEGMENT_DS 2

#define X86_SEGMENT_ES 3

#define X86_SEGMENT_FS 4

#define X86_SEGMENT_GS 5

#define X86_SEGMENT_SS 6

#define X86_SEGMENT_TSS 7

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

BOOL SpySelector (DWORD dSegment,

DWORD dSelector,

PX86_SELECTOR pSelector)

{

X86_SELECTOR Selector = {0, 0};

BOOL fOk = FALSE;

if (pSelector != NULL)

{

fOk = TRUE;

switch (dSegment)

{

case X86_SEGMENT_OTHER:

{

if (fOk = ((dSelector >> X86_SELECTOR_SHIFT)

<= X86_SELECTOR_LIMIT))

{

Selector.wValue = (WORD) dSelector;

}

break;

}

case X86_SEGMENT_CS:

{

__asm mov Selector.wValue, cs

break;

}

case X86_SEGMENT_DS:

{

__asm mov Selector.wValue, ds

break;

}

case X86_SEGMENT_ES:

{

__asm mov Selector.wValue, es

break;

}

case X86_SEGMENT_FS:

{

__asm mov Selector.wValue, fs

break;

}

case X86_SEGMENT_GS:

{

__asm mov Selector.wValue, gs

break;

}

case X86_SEGMENT_SS:

{

__asm mov Selector.wValue, ss

break;

}

case X86_SEGMENT_TSS:

{

__asm str Selector.wValue

break;

}

default:

{

fOk = FALSE;

break;

}

}

RtlCopyMemory (pSelector, &Selector, X86_SELECTOR_);

}

return fOk;

}

列表 4-16. 獲取選擇器( selector )的值

SpyDispatcher() 將從一個 64 位的描述符中讀取數(shù)據(jù),段選擇器指向該描述符(見 列表 4-17 )。像你記得的那樣,所有的選擇器都包含一個表指示符( Table Indicator, TI )位,以確定選擇器引用的描述符是位于 GDT ( TI=0 )中還是 LDT ( TI=1 )中。 列表 4-17 的上半部分處理了是 LDT 的情況。首先,使用匯編指令 SLDT 和 SGDT 分別讀取 LDT 選擇器的值以及段的大小限制和 GDT 的基地址。還記得 GDT 的線性基地址是顯示指定的,而 LDT 是由 GDT 中的選擇器間接引用的嗎?所以, SpyDispatcher() 會首先驗證 LDT 選擇器的值。如果段選擇器不為空并且沒有超過 GDT 的限制,就會調(diào)用 SpyDescriptorType() 、 SpyDescriptorLimit() 和 SpyDescriptorBase()( 列表 4-17 給出了這些函數(shù) ) 來獲取 LDT 的基本屬性:

l SpyDescriptorType() 返回描述符的類型數(shù)據(jù)及其 S 位域(參見 列表 4-2 )。 LDT 選擇器必須指向一個類型為 X86_DESCRIPTOR_SYS_LDT 的系統(tǒng)描述符。

l SpyDescriptorLimit() 從描述符的 Limit1 、 Limit2 這兩個位域中匯總段的大小限制。根據(jù)描述符的 G 標(biāo)志指定的內(nèi)存分配粒度的不同,其處理方式也會不同。

l SpyDescriptorBase() 只是簡單的通過適當(dāng)?shù)慕M織描述符的 Base1 、 Base2 和 Base3 位域以獲取一個 32 位的線性地址。

BOOL SpyDescriptor (PX86_SELECTOR pSelector,

PX86_DESCRIPTOR pDescriptor)

{

X86_SELECTOR ldt;

X86_TABLE gdt;

DWORD dType, dLimit;

BOOL fSystem;

PX86_DESCRIPTOR pDescriptors = NULL;

BOOL fOk = FALSE;

if (pDescriptor != NULL)

{

if (pSelector != NULL)

{

if (pSelector->TI) // ldt descriptor

{

__asm

{

sldt ldt.wValue

sgdt gdt.wLimit

}

if ((!ldt.TI) && ldt.Index &&

((ldt.wValue & X86_SELECTOR_INDEX)

<= gdt.wLimit))

{

dType = SpyDescriptorType (gdt.pDescriptors +

ldt.Index,

&fSystem);

dLimit = SpyDescriptorLimit (gdt.pDescriptors +

ldt.Index);

if (fSystem && (dType == X86_DESCRIPTOR_SYS_LDT)

&&

((DWORD) (pSelector->wValue

& X86_SELECTOR_INDEX)

<= dLimit))

{

pDescriptors =

SpyDescriptorBase (gdt.pDescriptors +

ldt.Index);

}

}

}

else // gdt descriptor

{

if (pSelector->Index)

{

__asm

{

sgdt gdt.wLimit

}

if ((pSelector->wValue & X86_SELECTOR_INDEX)

<= gdt.wLimit)

{

pDescriptors = gdt.pDescriptors;

}

}

}

}

if (pDescriptors != NULL)

{

RtlCopyMemory (pDescriptor,

pDescriptors + pSelector->Index,

X86_DESCRIPTOR_);

fOk = TRUE;

}

else

{

RtlZeroMemory (pDescriptor,

X86_DESCRIPTOR_);

}

}

return fOk;

}

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

PVOID SpyDescriptorBase (PX86_DESCRIPTOR pDescriptor)

{

return (PVOID) ((pDescriptor->Base1 ) |

(pDescriptor->Base2 << 16) |

(pDescriptor->Base3 << 24));

}

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

DWORD SpyDescriptorLimit (PX86_DESCRIPTOR pDescriptor)

{

return (pDescriptor->G ? (pDescriptor->Limit1 << 12) |

(pDescriptor->Limit2 << 28) | 0xFFF

: (pDescriptor->Limit1 ) |

(pDescriptor->Limit2 << 16));

}

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

DWORD SpyDescriptorType (PX86_DESCRIPTOR pDescriptor,

PBOOL pfSystem)

{

if (pfSystem != NULL) *pfSystem = !pDescriptor->S;

return pDescriptor->Type;

}

列表 4-17. 獲取描述符的值

如果選擇器的 TI 位指定了一個 GDT 描述符,事情就簡單了。再次使用 SGDT 指令來取出 GDT 在線性內(nèi)存中的位置和大小,如果選擇器指定的描述符索引位于適當(dāng)?shù)姆秶?pDescriptors 變量將被設(shè)置為指向 GDT 的基地址。對于 LDT 和 GDT 來說, pDescriptors 變量都不會為空。如果調(diào)用者傳入的選擇器是有效的, 64 位的描述符值將被復(fù)制到調(diào)用者提供的 X86_DESCRIPTOR 結(jié)構(gòu)中。否則,該結(jié)構(gòu)的所有成員都會被 RtlZeroMemory() 設(shè)為 0 。

我們?nèi)匀辉谟懻?列表 4-15 中的 SpySegment() 函數(shù)。 SpySelector() 和 SpyDescriptor() 調(diào)用已經(jīng)解釋了。只剩下最后的 SpyDescriptorBase() 和 SpyDescriptorLimit() 調(diào)用,不過你應(yīng)該已經(jīng)知道這些函數(shù)作了些什么(見 列表 4-17 )。如果 SpySelector() 和 SpyDescriptor() 成功,返回的 SPY_SEGMENT 結(jié)構(gòu)將是有效的。 SpyDescriptorBase() 和 SpyDescriptorLimit() 不會返回出錯標(biāo)志。因為它們不可能失敗,如果提供的描述符無效,只是會讓它們返回錯誤的數(shù)據(jù)而已。

標(biāo)簽: Windows系統(tǒng)
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
亚洲欧美视频| 国产一区丝袜| 国产a亚洲精品| 亚洲一级少妇| 欧美日韩国产综合网| 国产99精品一区| 国产美女一区| 亚洲精品视频一二三区| 国产日韩欧美一区二区三区| 免费在线亚洲欧美| 国产精品久久久久蜜臀| 亚洲国产一区二区三区在线播放| 在线精品视频在线观看高清| 亚洲三级观看| 精品视频免费| 模特精品在线| 亚洲精品一级| 精品一区电影| 日韩一级欧洲| 精品国产亚洲日本| 亚洲香蕉久久| 波多野结衣久久精品| 性欧美精品高清| 日韩av在线播放网址| 中文一区一区三区免费在线观 | 欧美日韩免费观看一区=区三区| 亚洲一区二区三区无吗| 国产v日韩v欧美v| 欧美一区网站| 欧美精品一卡| 九九九精品视频| 久久亚洲国产精品尤物| 国产精品国码视频| 欧美黄色精品| 午夜久久影院| 美女久久久精品| 欧美综合二区| 欧美日韩视频网站| 日韩av网站在线免费观看| 国产理论在线| 欧美欧美黄在线二区| 日韩精品视频在线看| 免费在线观看一区| bbw在线视频| 亚洲麻豆一区| 成人午夜国产| 日韩激情啪啪| 精品网站999| 亚洲午夜天堂| 亚洲欧洲日韩精品在线| 国语精品一区| 日韩精品欧美大片| 久久麻豆精品| 热久久久久久| 99精品网站| 国产欧美69| 在线日韩一区| 群体交乱之放荡娇妻一区二区| 日韩1区2区日韩1区2区| 99国产一区| а√在线中文在线新版| 亚洲+小说+欧美+激情+另类| 婷婷激情一区| 国产精品久久免费视频| 国产亚洲毛片| 久久影院一区| 国产成人精品一区二区免费看京| 日本欧美韩国一区三区| 中文一区一区三区免费在线观 | 五月天综合网站| 国产欧美自拍| 石原莉奈一区二区三区在线观看| 特黄特色欧美大片| 久久久国产亚洲精品| 国产一区三区在线播放| 国产欧美另类| 日本精品一区二区三区在线观看视频| 成人久久一区| 久久精品电影| 夜夜精品视频| 免费看欧美美女黄的网站| 麻豆精品网站| 午夜精品福利影院| 日韩激情综合| 欧美天堂在线| 日韩精品永久网址| 六月天综合网| 午夜精品一区二区三区国产| 久久男人av| 日韩精品久久久久久久电影99爱 | av日韩中文| 日韩不卡免费高清视频| 亲子伦视频一区二区三区| 国产一区清纯| 蜜臀av亚洲一区中文字幕| 日韩中文字幕一区二区高清99| 国产精品亚洲欧美日韩一区在线| 精品一区视频| 国产婷婷精品| 中文字幕av一区二区三区四区| 久久精品超碰| 国产精品国产一区| 视频一区二区三区中文字幕| 欧美色综合网| 日韩av片子| 日韩av午夜在线观看| 都市激情国产精品| 三级在线观看一区二区 | 亚洲欧洲av| 动漫av一区| 亚洲二区三区不卡| 日韩福利一区| 日本少妇精品亚洲第一区| 久久中文视频| 国产欧美一区二区三区国产幕精品| 激情欧美日韩一区| 精品黄色一级片| 神马午夜在线视频| 日本视频一区二区| 亚洲天堂久久| 中文字幕人成乱码在线观看| 日本久久二区| 97精品国产福利一区二区三区| 日韩中文字幕| 玖玖玖国产精品| 亚洲最新无码中文字幕久久| 久久99久久久精品欧美| 首页国产欧美日韩丝袜| 国产不卡精品| 日本麻豆一区二区三区视频| 黄色av日韩| 九九久久婷婷| 精品一区二区三区的国产在线观看| 在线日韩成人| 午夜一级久久| 亚洲中字黄色| 亚洲电影在线一区二区三区| 五月天av在线| 在线天堂资源www在线污| 91精品视频一区二区| 91精品国产自产精品男人的天堂| 亚洲一区二区三区免费在线观看| 亚洲黑丝一区二区| 久久中文字幕二区| 亚洲激情五月| 婷婷亚洲精品| 国产成人免费| 婷婷成人基地| 久久久成人网| 久久精品欧美一区| 久久99蜜桃| 日韩在线观看一区| 国产一区二区三区91| 福利一区和二区| 午夜欧美精品久久久久久久| 欧美在线综合| 国产一区二区三区久久| 国产精品久久久久久模特 | 国产视频久久| 亚洲性色视频| 亚洲精品美女91| 国产免费av国片精品草莓男男| 91成人精品在线| 你懂的网址国产 欧美| 伊人久久在线| 美国三级日本三级久久99| 久久久国产精品入口麻豆| 日本高清不卡一区二区三区视频| 电影天堂国产精品| 亚洲精品无吗| 欧美日韩精品免费观看视完整 | 在线综合亚洲| 日本不卡视频一二三区| 91免费精品国偷自产在线在线| 美女久久久精品| 香蕉成人久久| 伊人久久视频| 国产精品久久久久久妇女| 日韩视频二区| av在线最新| 亚洲综合色婷婷在线观看| 亚洲久久视频| 亚洲国产不卡| 日韩欧美另类一区二区| 国产精品最新自拍| 色狠狠一区二区三区| 国产一区二区三区四区| 在线观看视频免费一区二区三区| 神马日本精品| 国产激情精品一区二区三区| 国产亚洲毛片| 一区在线视频观看| 久久久久久一区二区| 麻豆精品视频在线观看| 伊人久久一区| 欧美日韩国产亚洲一区| 国产黄色一区| 奇米狠狠一区二区三区| 国产精品日本欧美一区二区三区| 日本精品不卡|