PreviousMode

用户模式应用程序调用本机系统服务例程的 NtZw 版本时,系统调用机制会将调用线程捕获到内核模式。 为了指示参数值在用户模式下生成,系统调用的陷阱处理程序会将调用方的线程对象中的PreviousMode字段设置为UserMode。 本机系统服务例程检查调用线程的 PreviousMode 字段,以确定参数是否来自用户模式源。

如果内核模式驱动程序调用本机系统服务例程并将参数值传递给来自内核模式源的例程,则驱动程序必须确保将当前线程对象中的 PreviousMode 字段设置为 KernelMode

内核模式驱动程序可在任意线程的上下文中运行,此线程的 PreviousMode 字段可能设置为 UserMode。 在这种情况下,内核模式驱动程序可以调用本机系统服务例程的 Zw 版本来通知例程参数值来自受信任的内核模式源。 Zw调用将转到一个精简包装函数,该函数将重写当前 thread 对象中的PreviousMode值。 包装函数将 PreviousMode 设置为 KernelMode ,并调用例程的 Nt 版本。 从例程的 Nt 版本返回时,包装函数将还原 thread 对象的原始 PreviousMode 值,并返回。

内核模式驱动程序可以直接调用本机系统服务例程的 Nt 版本。 当内核模式驱动程序处理可在用户模式或内核模式下发出的 i/o 请求时,驱动程序可以调用例程的 Nt 版本,以便当前线程的 PreviousMode 值在调用期间保持不变。 NtXxx例程检查调用线程的PreviousMode值,以确定参数值是来自用户模式应用程序还是内核模式组件,并相应地对其进行处理。

如果内核模式驱动程序调用NtXxx例程,并且当前线程对象中的PreviousMode值不能准确地指示参数值是来自用户模式还是内核模式源,则会发生错误。

例如,假定内核模式驱动程序在任意线程的上下文中运行,并且此线程的 PreviousMode 值设置为 UserMode。 如果驱动程序将内核模式文件句柄传递到 NtClose 例程,此例程会检查 PreviousMode 值并确定该句柄必须是用户模式句柄。 当 NtClose 在用户模式句柄表中找不到句柄时,它将返回 STATUS_INVALID_HANDLE 错误代码。 同时,驱动程序会泄漏未关闭的内核模式句柄。

再举一个例子,如果NtXxx例程的参数包括输入或输出缓冲区,并且如果PreviousMode = UserMode,则例程将调用ProbeForReadProbeForWrite例程来验证缓冲区。 如果缓冲区是在系统内存而不是在用户模式内存中分配的,则ProbeForXxx例程将引发异常,并且NtXxx例程将返回 STATUS_ACCESS_VIOLATION 错误代码。

如果需要,驱动程序可以调用 ExGetPreviousMode 例程,从当前线程对象获取 PreviousMode 值。 或者,驱动程序可以从描述所请求的 i/o 操作的IRP结构读取irp->requestormode字段。 Irp->requestormode字段包含请求操作的线程的PreviousMode值的副本。