【问题标题】:How does Windows protect transition into kernel mode?Windows 如何保护转换到内核模式?
【发布时间】:2010-11-06 17:50:18
【问题描述】:

Windows 如何防止用户模式线程任意将 CPU 转换为内核模式?

我明白这些事情是真的:

  1. 当通过 NTDLL 进行系统调用时,用户模式线程确实会转换为内核模式。
  2. 到内核模式的转换是通过特定于处理器的指令完成的。

那么这些通过 NTDLL 进行的系统调用有什么特别之处呢?为什么用户模式线程不能伪造它并执行特定于处理器的指令以转换到内核模式?我知道我在这里遗漏了 Windows 体系结构的一些关键部分......它是什么?

【问题讨论】:

  • 用户模式线程可以伪造它,但这与仅使用 ntdll.dll 有何不同?在问题中添加更多关于为什么这会引起您的关注的信息。
  • 我认为 OP 担心过渡到 ring 0,然后在 ring 0 中运行任意非 O/S 代码。
  • Windows 对其公开的(对用户模式)参数执行验证。你不能*在它不知道的情况下传递无效数据。是的,有一些被忽视的极端案例。只是,查找本地提权漏洞。有很多
  • ntdll 是您的进程顺便说一句,所以是的,您可以自己调用 CPU sysenter。旧病毒过去使用这些愚蠢的技巧来欺骗保护。

标签: windows winapi kernel


【解决方案1】:

您可能认为在用户模式下运行的线程正在调用 Ring 0,但实际情况并非如此。用户模式线程导致了 Ring 0 代码捕获的异常。用户模式线程停止,CPU 切换到内核/环 0 线程,然后它可以检查用户模式线程的上下文(例如,调用堆栈和寄存器)以确定要做什么。在 syscall 之前,它确实是一个异常,而不是专门用于调用 ring 0 代码的特殊异常。

如果您听取其他回复的建议并阅读the Intel manuals,您会看到 syscall/sysenter 不带任何参数 - 操作系统决定发生什么。你不能调用任意代码。 WinNT 使用函数编号来映射用户模式代码将执行的内核模式函数(例如,在我的 Windows XP 机器上,NtOpenFile 是 fnc 75h(数字一直在变化;NTDll 的工作之一就是映射一个函数)调用一个 fnc 号码,将其放入 EAX,将 EDX 指向传入参数,然后调用 sysenter)。

【讨论】:

    【解决方案2】:

    英特尔 CPU 使用所谓的“保护环”来加强安全性。

    其中有 4 个,从 0 到 3 编号。在 ring 0 中运行的代码具有最高权限;它可以(实际上)对您的计算机做任何事情。另一方面,环 3 中的代码始终受到严格控制。它影响事物的权力有限。并且环 1 和 2 目前根本没有用于任何目的。

    运行在较高特权环(例如环 0)中的线程可以随意转换到较低特权环(例如环 1、2 或 3)。但是,反向过渡受到严格监管。这就是维护高特权资源(如内存)等的安全性的方式。

    当然,您的用户模式代码(应用程序和所有)在环 3 中运行,而操作系统的代码在环 0 中运行。这样可以确保用户模式线程不会与操作系统的数据结构和其他关键资源发生冲突。

    有关这一切如何实际实现的详细信息,您可以阅读this 文章。此外,您可能还需要阅读英特尔手册,尤其是第 1 卷和第 3A 卷,您可以下载here

    这是英特尔处理器的故事。我确信其他架构也有类似的情况。

    【讨论】:

    • 大多数其他处理器只需要两个特权级别,实际上与 x86 环 0 和 3 等效。环 1 和 2 在当时似乎是个好主意,但结果却没有添加任何他们所花费的复杂性的价值。
    • IIRC Windows 仅使用 2 个环,因为这就是 RISC 架构支持的全部。由于他们想以相同的基本架构支持 RISC,因此只使用了极限 x86 环。
    【解决方案3】:

    我认为(我可能错了)它用于转换的机制很简单:

    • 用户模式代码执行软件中断
    • 此(中断)会导致跳转到中断描述符表 (IDT) 中指定的位置

    阻止用户模式代码篡夺此功能的原因如下:您需要有写入 IDT 的特权;所以只有内核能够指定执行中断时会发生什么。

    【讨论】:

    • 大克里斯回答小克里斯。
    • 这就是它使用的工作方式,但 Tony Lee 的答案更接近于 Windows 今天所做的。
    • 我跳过了关于 IDT / CPU 如何知道从哪里开始执行的部分,所以这也很有趣。
    【解决方案4】:

    在用户模式 ​​(Ring 3) 下运行的代码不能随意更改为内核模式 (Ring 0)。它只能使用特殊的路由来做到这一点——跳转门、中断和系统输入向量。这些路由受到高度保护,输入被清除,因此不良数据不会(不应该)导致不良行为。

    所有这些都是由内核设置的,通常在启动时。它只能在内核模式下配置,因此用户模式代码无法修改它。

    【讨论】:

      【解决方案5】:

      可以公平地说,它以与 Linux 的(相对)相似的方式进行。在这两种情况下,它将是特定于 CPU 的,但在 x86 上,可能是使用 INT 指令或通过 SYSENTER 指令的软件中断。

      了解 Linux 是如何做到这一点的好处是,您可以在没有 Windows 源代码许可证的情况下这样做。

      LXR 的 userspace source part is here herekernel space bit - 查看 entry_32.S 和 entry_64.S

      在 x86 上的 Linux 下存在三种不同的机制,int 0x80、syscall 和 sysenter。

      由内核在运行时构建的名为 vdso 的库由 C 库调用以实现 syscall 函数,该函数根据 CPU 和系统调用使用不同的机制。然后内核拥有这些机制的处理程序(如果它们存在于特定的 CPU 变体上)。

      【讨论】:

        猜你喜欢
        • 2013-06-05
        • 1970-01-01
        • 1970-01-01
        • 2014-10-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-24
        • 1970-01-01
        相关资源
        最近更新 更多