读书频道 > 系统 > windows > Windows内核原理与实现
2.2.1 Windows内核结构
2013-05-18 13:59:26     我来说两句 
收藏    我要投稿   

本文所属图书 > Windows内核原理与实现

本书从操作系统原理的角度,详细解析了Windows如何实现现代操作系统的各个关键部件,包括进程、线程、物理内存和虚拟内存的管理,Windows中的同步和并发性支持,以及Windows的I/O模型。在介绍这些关键部件时,本...  立即去当当网订购

正如图2.2所示,Windows 内核分为三层,与硬件直接打交道的这一层称为硬件抽象层(Hardware Abstraction Layer ,简称 HAL),这一层的用意是把所有与硬件相关联的代码逻辑隔离到一个专门的模块中,从而使上面的层次尽可能做到独立于硬件平台。HAL之上是内核层,有时候也称为微内核(micro-kernel),这一层包含了基本的操作系统原语和功能,如线程和进程、线程调度、中断和异常的处理、同步对象和各种同步机制。在内核层之上则是执行体(executive )层,这一层的目的是提供一些可供上层应用程序或内核驱动程序直接调用的功能和语义。Windows 内核的执行体包含一个对象管理器,用于一致地管理执行体中的对象。执行体层和内核层位于同一个二进制模块中,即内核基本模块,其名称为ntoskrnl.exe 。

内核层和执行体层的分工是,内核层实现操作系统的基本机制,而所有的策略决定则留给执行体。执行体中的对象绝大多数封装了一个或者多个内核对象,并且通过某种方式(比如对象句柄)暴露给应用程序。这种设计体现了机制与策略分离的思想。图 2.3显示了Windows 内核的详细组成结构。


 

Windows 内核为用户模式代码提供了一组系统服务,供应用程序使用内核中的功能。应用程序通常并不直接调用这些系统服务,而是通过一组系统DLL ,最终通过 ntdll.dll切换到内核模式下的执行体 API 函数中,以调用内核中的系统服务。Ntdll.dll是连接用户模式代码和内核模式系统服务的桥梁。对于内核提供的每一个系统服务,该DLL 都提供一个相应的存根函数,这些存根函数的名称以“Nt ”作为前缀,例如 NtCreateProcess、NtOpenFile和NtSetTimer。另外,ntdll.dll还提供了许多系统级的支持函数,比如映像加载器函数(以“Ldr”为前缀)、Windows 子系统进程通信函数(以“Csr”为前缀)、调试函数(以“ Dbg”为前缀)、系统事件函数(以“Etw”为前缀),以及一般的运行支持函数(以“Rtl”为前缀)和字符串支持函数等。

执行体API 函数接收的参数来自于各种应用程序,因此,为了确保系统的健壮性,以及抵抗来自用户模式的恶意攻击,所有的执行体API 函数必须保证参数的有效性。这意味着它们必须在恰当的时刻检查参数的值,若是指针的话,还必须保证调用者可以访问指针所指的内存。通常,执行体系统服务函数会在其开始处,对所接收的参数逐一探查它们的可访问性。例如,以下代码就演示了这一做法:
PreviousMode = KeGetPreviousMode();
if (PreviousMode != KernelMode) {
    try {
        ProbeForWrite(InputInformation,
               InputInformationLength,
               sizeof(ULONG));
        if (ARGUMENT_PRESENT(ReturnLength)) {
            ProbeForWriteUlong(ReturnLength);
        }
    } except(EXCEPTION_EXECUTE_HANDLER) {
        return GetExceptionCode();
    }
}

这里InputInformation 和ReturnLength 是该系统服务的直接参数,InputInformation 是个指针参数,它的可用长度由另一个参数InputInformationLength 来指定,因此,这段代码通过ProbeForWrite来探查这一输入数据是否可写;另外,ReturnLength 是一个ULONG类型的输出参数,这段代码通过 ProbeForWriteUlong 来验证该参数是否可写。一旦探查函数发生访问违例,则说明这两个参数有问题,于是该系统服务就将直接返回违例异常代码。

正如前文所述,用户模式和内核模式代码所能访问的地址空间有所不同。在32位系统上,用户模式代码只能访问 2 GB以下的虚拟内存地址空间,而内核模式代码可以访问当前进程整个4 GB虚拟地址范围。2 GB以下称为进程地址空间,2 GB以上称为系统地址空间。实际上,在两者之间有一块特殊的 64 KB 地址空间,位于 0x7fff0000~0x7fffffff ,在两种模式下都不可访问。上述代码片段中的ProbeForWrite< Xxx> 函数首先检查目标内存地址是否越过了此特殊区域,若越过则访问违例;然后,试图将目标地址处的值赋回该地址,即触发一次该地址处的读和写操作,若该内存地址处当前线程不可写,则引发异常,从而使代码片段中的except 子句截获控制。Windows 通过这种方法来捕捉到“用户模式代码传递一个系统空间地址”或者“传递一个无效内存地址”的情形,从而确保执行体函数接收到的参数已被检验过。

然而,执行体API 函数并不总是要检验参数的有效性,如果在调用该API 函数以前的模式是内核模式,那么,它不需要检验参数的有效性。执行体不会用坏的参数来调用它自己的服务,只有当执行体API 函数接收到一个或多个来自用户模式的参数时,它才使用Probe 函数族检查参数的有效性。每个线程都维护着一个状态值,用以说明它以前的处理器模式。当从用户模式切换到内核模式时,该值将被设置为UserMode,从而满足上述代码中的if 条件。

点击复制链接 与好友分享!回本站首页
分享到: 更多
您对本文章有什么意见或着疑问吗?请到论坛讨论您的关注和建议是我们前行的参考和动力  
上一篇:2.2 Windows系统结构
下一篇:2.2.2 Windows内核中的关键组件
相关文章
图文推荐
3.4.4 进程生命期管
3.4.2 Windows应用商
3.4.1 Windows应用商
3.4 进程生命期管理
排行
热门
文章
下载
读书

关于我们 | 联系我们 | 广告服务 | 投资合作 | 版权申明 | 在线帮助 | 网站地图 | 作品发布 | Vip技术培训
版权所有: 红黑联盟--致力于做最好的IT技术学习网站