句柄管理
驱动程序中安全问题的重要来源是使用用户模式和内核模式组件之间传递的句柄。 在内核环境中处理使用情况存在许多已知问题,包括:
将错误类型的句柄传递给内核驱动程序的应用程序。 内核驱动程序可能会崩溃,尝试使用需要文件对象的事件对象。
将句柄传递给其没有必要访问权限的对象的应用程序。 内核驱动程序可能会执行运行操作,因为调用来自内核模式,即使用户没有足够的权限执行此操作。
一个应用程序,它传递的值在其地址空间中不是有效的句柄,但被标记为系统句柄以针对系统执行恶意操作。
一个应用程序,它传递的值不是设备对象的适当句柄(此驱动程序未创建的句柄)。
若要防止这些问题,内核驱动程序必须特别小心,以确保传递给它的句柄有效。 最安全的策略是在驱动程序的上下文中创建任何所需的句柄。 这些句柄(由内核驱动程序创建)应指定OBJ_KERNEL_HANDLE选项,该选项将在任意进程上下文中创建有效的句柄,以及只能从内核模式调用方访问的句柄。
对于使用应用程序程序创建的句柄的驱动程序,必须非常谨慎地使用这些句柄:
最佳做法是通过调用 ObReferenceObjectByHandle,指定正确的 AccessMode(通常来自 Irp-RequestorMode>)、DesiredAccess 和 ObjectType 参数(例如 IoFileObjectType 或 ExEventObjectType)将句柄转换为对象指针。
如果必须在调用中直接使用句柄,最好使用函数的 Nt 变体,而不是函数的 Zw 变体。 这将强制参数检查和处理操作系统的验证,因为以前的模式将是 UserMode,因此不受信任。 请注意,如果上一模式为 UserMode,传递给 Nt 函数的参数可能未能通过验证。 Nt 和 Zw 例程返回一个 IoStatusBlock 参数,其中包含错误检查的错误信息。
必须适当地捕获错误,并在必要时使用__try和__except。 发生错误时,许多缓存管理器(Cc)、内存管理器(Mm)和文件系统运行时库例程(FsRtl)都会引发异常。
任何驱动程序都不应依赖从用户模式应用程序传递的句柄或参数,而无需采取适当的预防措施。
请注意,如果 Nt 变体用于打开文件,则还必须使用 Nt 变量关闭文件。