PreviousMode
當使用者模式應用程式呼叫原生系統服務常式的 Nt 或 Zw 版本時,系統呼叫機制會將呼叫執行緒設陷到核心模式。 為了指出參數值源自使用者模式,系統呼叫的設陷處理常式會將呼叫端執行緒物件中的PreviousMode欄位設定為UserMode。 原生系統服務常式會檢查呼叫執行緒的 PreviousMode 欄位,以判斷參數是否來自使用者模式來源。
如果核心模式驅動程式呼叫原生系統服務常式,並將參數值傳遞至來自核心模式來源的常式,驅動程式必須確定目前線程物件中的 PreviousMode 欄位已設定為 KernelMode。
核心模式驅動程式可以在任意執行緒的內容中執行,而且此執行緒的 PreviousMode 欄位可能會設定為 UserMode。 在此情況下,核心模式驅動程式可以呼叫原生系統服務常式的 Zw 版本,以通知常式參數值來自受信任的核心模式來源。 Zw呼叫會移至精簡包裝函式,以覆寫目前線程物件中的PreviousMode值。 包裝函式會將 PreviousMode 設定為 KernelMode ,並呼叫 Nt 版本的常式。 從 Nt 版本的常式傳回時,包裝函式會還原執行緒物件的原始 PreviousMode 值,並傳回 。
核心模式驅動程式可以直接呼叫原生系統服務常式的 Nt 版本。 當核心模式驅動程式處理可能源自于使用者模式或核心模式的 I/O 要求時,驅動程式可以呼叫 Nt 版本的常式,讓目前線程的 PreviousMode 值在呼叫期間維持不變。 NtXxx常式會檢查呼叫執行緒的PreviousMode值,以判斷參數值是否來自使用者模式應用程式或核心模式元件,並據以處理它們。
如果核心模式驅動程式呼叫NtXxx常式,而且目前線程物件中的PreviousMode值無法正確指出參數值是否來自使用者模式或核心模式來源,就會發生錯誤。
例如,假設核心模式驅動程式正在任意執行緒的內容中執行,而且此執行緒的 PreviousMode 值會設定為 UserMode。 如果驅動程式將核心模式檔案控制碼傳遞至 NtClose 常式,此常式會檢查 PreviousMode 值,並決定控制碼必須是使用者模式控制碼。 當 NtClose 在使用者模式控制碼資料表中找不到控制碼時,它會傳回STATUS_INVALID_HANDLE錯誤碼。 同時,驅動程式會洩漏從未關閉的核心模式控制碼。
例如,如果NtXxx常式的參數包含輸入或輸出緩衝區,而且如果PreviousMode = UserMode,則常式會呼叫ProbeForRead 或 ProbeForWrite常式來驗證緩衝區。 如果緩衝區配置在系統記憶體中,而不是在使用者模式記憶體中,ProbeForXxx常式會引發例外狀況,而 NtXxx常式會傳回STATUS_ACCESS_VIOLATION錯誤碼。
如有必要,驅動程式可以呼叫 ExGetPreviousMode 常式,以從目前的執行緒物件取得 PreviousMode 值。 或者,驅動程式可以從描述所要求 I/O 作業的IRP結構讀取RequestorMode欄位。 RequestorMode欄位包含來自要求作業之執行緒的PreviousMode值複本。