Windows系统架构

2019年11月06日 阅读数:41
这篇文章主要向大家介绍Windows系统架构,主要内容包括基础应用、实用技巧、原理机制等方面,希望对大家有所帮助。

系统架构html

 

 

 

关键组件
环境子系统和子系统DLL
  环境子系统向应用程序提供环境和应用程序编程接口(Appplication Programming Interface, API)。Windows 2000/XP支持三种环境子系统:Win3二、POSIX和OS/2,其中最重要的环境子系统是Win32子系统,其余子系统都要经过Win32子系统接收用户的输入和显示输出。环境子系统的做用是将基本的执行体系统服务的某些子集提供给应用程序。 用户应用程序调用系统服务时必须经过一个或多个子系统动态连接库做为中介才能够完成。前端

  子系统由会话管理器(Session Manager)(Smss.exe)进程启动。node

Ntdll.dll
  Ntdll.dll是一个特殊的系统支持库,主要用于子系统DLL。包含两种类型的函数:c++

系统服务分发存根(stub),在用户模式下可经过这些函数调用windows执行体的系统服务。
内部支持函数,供子系统、子系统DLL及其余的原生镜像文件使用。
执行体
  是Ntoskrnl.exe中的上层,包含了基本的操做系统服务,好比内存管理、进程和线程管理、安全性、I/O、网络和跨进程通讯等。程序员

内核
  由Ntoskrnl.exe的一组函数以及对于硬件体系架构的低层支持(如中断和异常分发)构成。这些函数提供了一些最基本的机制,如线程调度和同步服务供执行体组件使用,可是全部的策略决定都留给了执行体,除了线程调度和分发。算法

硬件抽象层(HAL)
  Windows内部组件以及用户编写的驱动程序经过hal.dll访问硬件。
  Ntoskrnl与hal相互连接。shell

设备驱动程序
硬件设备驱动程序
文件系统驱动程序
文件系统过滤驱动程序
网络重定向器和服务器
协议驱动程序
内核流式驱动程序数据库

  安装驱动程序是在系统中添加用户编写的内核模式代码的惟一方法。编程

系统进程
Idle进程(空闲进程,无实际的用户模式映像文件)
System进程
会话管理器(Smss.exe,第一个用户模式进程)
本地会话管理器(Lsm.exe)
Windows子系统(Csrss.exe)
会话0初始化(Wininit.exe)
登陆进程(Winlogon.exe)
服务控制管理器(Services.exe)和它建立的子服务进程(如Svchost.exe)
本地安全认证服务器(Lsass.exe)windows

深刻解析Windows操做系统笔记——CH1概念和术语

1.概念和工具

本章主要介绍Windows操做系统的关键概念和术语

1.概念和工具

1.1操做系统版本

1.2基础概念和术语

1.2.1Windows API

1.2.2 服务、函数和例程

1.2.3 进程、线程和做业

1.2.3.1 进程

1.2.3.2 线程

1.2.3.3 虚拟地址描述符

1.2.3.4 做业

1.2.4 虚拟内存

1.2.5 内核模式和用户模式

1.2.6 终端服务及多个会话

1.2.7 对象和句柄

1.2.8 安全性

1.2.9 注册表

1.2.10 UNICODE

1.3 挖掘Windows内部机理

参考

 

1.1操做系统版本

Windows操做系统版本已经不少了

 

1.2      基础概念和术语

1.2.1    Windows API

Windows API(应用程序接口),是针对Windows操做系统的系统编程接口。

Windows API有几个分类:

n  基本服务

n  组件服务

n  用户界面服务

n  图形和多媒体服务

n  消息和协议

n  Web服务

本书重点介绍基本服务(好比,进程和线程,内存管理,I/O,安全性)。

关于.Net和WinFX

.NET FrameWork由框架类库(FCL)和一个提供托管代码运行环境的(CLR)组成。

CLR提供即时编译,类型检查,垃圾回收和代码访问安全性等。

托管代码:在最初编译时,将源代码编译成中间代码(IL),而后在运行时,使用运行库编译器在受控的环境下,将中间代码编译成机器码。

在微软体系下,认为不是托管代码就是非托管代码。

CLR是一个典型的COM服务器,创建在Windows API之上。

 

而WinFX就是新的Windows API(为vista特别设计的),也提供了托管代码的功能,可是缺容易混淆,后来改成.Net FrameWork 3。(关于WinFX的介绍在第6版中已经没有了)。

.NET FrameWork是对API的一种扩展。

1.2.2 服务、函数和例程

主要介绍一些书中提到的专业术语:

n  Windows API函数:主要是指已经被文档化的可调用的子例程

n  原生的系统服务:指操做系统中未文档化的,能够在用户模式下调用的底层服务,如NtCreateProcess

n  内核支持函数(例程):值操做系统内部且只能被内核调用的子例程

n  Windows服务:由Windows服务管理器启动的进程(在注册表中,认为驱动定于为服务,可是书中并不这样引用)

n  DLL:一组可调用的子例程,合起来被连接成一个二进制文件,应用程序能够动态加载这些二进制文件。

1.2.3 进程、线程和做业

1.2.3.1 进程

程序是指一个静态的指令序列,而进程是程序的实例化,拥有各类资源。一个进程由如下元素组成:

n  私有的虚拟地址空间

n  程序定义的代码和数据,被映射到进程的虚拟地址空间中

n  一个已打开的句柄列表,这些句柄指向各类资源

n  称为访问令牌的安全环境,标示了改进程关联的用户,安全组和特权

n  进程ID,能够惟一识别一个进程

n  至少一个线程

每一个进程都指向一个父进程或者建立者进程,可是若是父进程被关闭,进程就会指向一个不存在的父进程。

1.2.3.2 线程

线程是在进程中的实体,也是Windows执行此进程的调度实体,没有线程进程是不可能运行的。

线程的基本部件:

n  一组表明处理器状态的CPU寄存器中的内容

n  2个栈,一个用于线程在内核模式下执行,一个用于线程在用户模式下执行

n  线程局部存储区(TLS),线程私有存储区域,各个子系统,运行库,DLL都会用到这个区域

n  惟一表示线程的线程ID

n  线程本身的安全环境

易失的寄存器,栈,私有存储区域合起来称为线程的环境。

虽然线程有本身的环境,可是同一个进程内的线程共享该进程的虚拟地址空间及其余属于该进程的资源。

也就是说线程能够读写进程内其余线程的内存,可是不能跨进程的访问,除非另一个进程把虚拟地址空间变成共享内存区。

1.2.3.3 虚拟地址描述符

虚拟地址描述符是一些数据结构,内存管理器使用这个数据结构来记录一个进程所使用的虚拟地址。

1.2.3.4 做业

做业是指,一组进程当一个总体来维护管理。

1.2.4 虚拟内存

Windows 实现了平面地址空间的虚拟内存系统,每一个进程感受本身独立拥有一个很大的私有地址空间。虚拟内存提供了内存逻辑视图,并不对应于内存物理布局。运行的时候,内存管理器借助硬件支持,讲虚拟地址翻译成真正的物理地址。

进程之间就隔离了,一个进程不会访问到另一个进程的东西。

大多数系统拥有的物理内存比虚拟地址小,因此当内存不够的时候,内存管理器会把内存移动到磁盘,释放内存,让被的进程使用。

在32bit下,4GB的地址空间,其中2GB是内核地址空间,2GB是用户模式地址空间,在起用3gb参数,用户模式地址空间时3GB,内核模式地址空间时1GB

还有AWE地址窗口扩展,可让32bit系统访问64GB的内存。缺点是程序员本身解决映射关系。

 

在64bit下地址空间能够达到8T,在Itanium系统上能够达到7T

 

1.2.5 内核模式和用户模式

为了不用户程序读写关键操做系统数据,Windows使用了2中处理器访问模式:用户模式,内核模式。用户程序代码运行在用户模式,系统代码运行在内核模式。内核模式容许访问全部系统内存和cpu指令。用内核模式来保护操做系统稳定。

虽然Windows 进程都有本身的地址空间,可是内核模式的操做系统和驱动都是使用同一个虚拟地址空间。

系统空间中的页面只有在内核模式下能够访问,用户空间中的页面在用户模式下均可以访问。

内核模式下运行的代码能够访问全部系统空间中的内存。

由于进入内核模式就缺乏保护,因此第三方设备驱动程序加载时要当心。

当用户模式调用系统服务的时候,会切换到内核模式下,当要将cpu控制权返回给用户的时候要先切换到用户模式。

1.2.6 终端服务及多个会话

1.2.7 对象和句柄

内核对象是某一个静态定义的对象类型的单个运行时的实例。对象类型包含了一个系统定义的数据类型,在该对象上可用的函数,及一组对象属性。如全部的进程是进程对象类型的一个实例。

对象和普通数据结构的区别是,对象的内部结构是被隐藏的。必需要调用对象服务才能读写对象内部数据。

对象技术的实现了操做系统4个系统任务:

n  提供了可供人读的名称

n  进程间共享资源和数据

n  保护资源,避免未受权访问

n  引用跟踪,若是再也不使用能够释放掉。

1.2.8 安全性

Windows的核心安全功能包含:针对全部可共享对象的自主保护,安全审计,登陆时密码认证,以及一个资源被一个进程释放后,其余进程看不到上一个进程留下的资源。

1.2.9 注册表

注册表是系统数据库,包含了引道和配置系统全部的信息。也反映了内存中易失的数据窗口,好比当前的硬件状态,性能计数器。

1.2.10 UNICODE

1.3 挖掘Windows内部机理

主要介绍了一些调试工具,和Windows SDK

 

 

 深刻解析Windows操做系统笔记——CH2系统结构

2.系统结构

本章主要介绍系统的整体结构,关键部件之间的交互,以及运行在什么环境。

2.系统结构

2.1 需求和设计目标

2.2 操做系统模型

2.3 整体结构

2.3.1 可移植性

2.3.2 对称多处理

2.3.3 可伸缩性()

2.3.4 客户和服务器版本的区别

2.3.5 版本检查

2.4 关键的系统组件

2.4.1 环境子系统和子系统dll

2.4.1.1 Windows子系统

2.4.1.2 POSIX子系统

2.4.1.3 OS/2子系统

2.4.2 NTDLL.DLL

2.4.3 执行体

2.4.4 内核

2.4.5 内核对象

2.4.6 硬件支持

2.4.7 硬件抽象层(HAL)

2.4.8 设备驱动程序

2.4.9 系统进程

2.4.9.1 空闲进程

2.4.9.2 中断和DPC

2.4.9.3 system进程和系统进程

2.4.9.4 会话管理器

2.4.9.5 Winlogon,lsass和Userinit

2.4.9.6 服务控制器管理

2.5 总结

 

2.1 需求和设计目标

2.2 操做系统模型

在大多数用户操做系统中,应用程序与操做系统自己是隔离的:操做系统代码在内核模式下执行,能够访问系统数据和硬件,应用程序代码运行在用户模式下,只有有限的接口可使用,对系统数据访问受限,没法直接访问硬件。

 

和unix同样,windows系统大部分代码和驱动程序都是共享相同的受保护的内核模式空间。意味着操做系统任何组件,均可以破坏其余组件的数据。

 

固然用户程序和操做系统全部组件是隔离的。应用程序没法直接访问系统中特权部分的数据和代码。

 

windows内核模式组件也体现了基本的面向对象设计原则。如他们不会直接进入另外一个组件的数据结构来访问该组件维护的数据。相反是利用正式的接口来传递参数,访问和修改相应的数据接口。

 

可是严格上来讲windows并非一个面向对象系统。windows内部使用c语言,并非面向对象系统,c语言对象实现,只是借用了面向对象语言的特性。

2.3 整体结构

本节介绍windows的设计目标和包装方式,以下图windows整体结构中的关键系统组件。

 

 

 

有4中用户模式进程:

1.固定的系统支持进程,如登录进程,会话管理器进程。

2.服务进程,宿纳了windows服务,如进程管理器和假脱机服务。

3.用户应用程序,有6个类型:windows32位,windows64位,windows3.1 16位,ms-dos 16位,posix32位或者OS/2 32位。

4.环境子系统服务进程,实现了操做系统环境的部分支持。这里的环境是指操做系统展现给用户或者程序员的个性化部分。

在windows下,用户程序不能直接访问原始的windows服务,要经过一个或者多个子系统动态连接库。

 

windows内核组件包含:

1.windows执行体,包含基本的操做系统服务,如内存管理,进程和线程管理,安全性,I/O,网络,跨进程通讯。

2.windows内核,是由一组底层的操做系统功能构成,如线程调度,终端和异常处理分发。以及处理器同步。提供了一组例程和基础对象。执行体的其余部分利用这些例程和对象实现更高层次的功能。

3.设备驱动程序,硬件设备驱动程序,也包含文件系统和网络驱动程序。其中硬件设备驱动程序将用户的I/O函数调用转化为特定的硬件设备请求。

4.硬件抽象层,指一层特殊代码,它把内核,设备驱动程序和windows执行体其余部分跟与平台相关的硬件差别隔离开来。

5.窗口和图形系统:实现了图形用户界面函数。

文件名

组件

Ntoskrnl.exe

执行体和内核

Ntkrnlpa.exe

执行体和内核,支持物理地址扩展,是的系统可寻址64GB物理内存

Hal.dll

硬件抽象层

Win32k.sys

Windows子系统的内核模式部分

Ntdll.dll

内部支持函数,以及执行体函数和系统服务分发存根(stub)

Kernerl32.dll,Advapi32.dll,User32.dll,Gdi32.dll

Windows的核心子系统DLL

2.3.1 可移植性

windows的一个设计目标是要可以运行在各类不一样的硬件体系结构上。

windows有2中方式支持可移植性以支持多种硬件体系结构和平台:

1.windows有一个分层设计,系统底层部分与处理器体系结构相关,或与平台相关的,这些部分被隔离到独立的模块中,因此搞成不须要考虑体系结构的区别。有2个组件为系统提供了可移植性:内核和硬件抽象层。

2.windows的绝大多数代码是由c语言编写的,少部分是使用c++编写的,只有那些须要直接与系统硬件通讯的部分或者对性能极端敏感的操做系统部分,才是用汇编语言编写的。

2.3.2 对称多处理

多任务是值多个执行线程之间共享同一个处理器的操做技术。

 

可以很好的在多处理器运行是windows 的设计目标。windows是一个对称多处理(SMP)操做系统。没有主处理器,操做系统和用户线程能够被调度到任何一个处理器上运行,并且全部的处理器共享惟一的内存空间。

 

对称处理和非对称处理不一样,操做系统选一个处理器运行系统内核代码。而其余处理器运行用户代码。

 

 

 

xp和2003支持2中新的多处理器系统:超线程(hyperthreading),NUMA(非一致性的内存结构)。

超线程是intel一个技术,能够一个物理处理器上有多个逻辑处理器,是的一个逻辑cpu能够在其余逻辑cpu正在忙着的时候继续运行。

 

在非一致性内存结构NUMA系统中,处理器被组织成更小的单元,成为node,每一个结点都有本身的处理器和内存,并同一个一个缓存一致(cache-cohernet)的互联总线链接到更大的系统上。NUMA系统上的windows仍然做为一个smp系统运行。全部的处理器能够访问全部内存。不过本地结点比其余节点速度要快,系统想要提升性能作法是,根据现场用到的内存所在的节点,讲现场调度到同一个处理器上。

 

在windows的最初设计上32位最多只支持32个cpu,64位支持64个cpu。并无本质的因素来限制处理器个数。注册表LocensedProcessors能够限制处理器个数。

 

考虑到性能问题内核和HAL分为2个版本,单处理器和多处理器版本。

在系统磁盘上的文件名

在发布介质上单处理器版本的名称

在发布介质上多处理器版本的名称

Ntoskrnl.exe

Ntoskrnl.exe

Ntkrnlmp.exe

Ntkrnlpa.exe

Ntkrnlpa.exe in \windows\<arch>\Driver.cab

Ntkrpamp.exe in \windows\<arch>\Driver.cab

Hal.dll

取决于系统类型

取决于系统类型

如下只针对2000系统

 

 

Win32.sys

\I386\UNIPROC\Win32k.sys

\I386\Driver.cab中Win32.sys

Ntdll.dll

\I386\UNIPROC\Ntdll.dll

\I386\Ntdll.dll

Kernel32.dll

\I386\UNIPROC\Kernel32.dll

\I386\Kernel32.dll

2.3.3 可伸缩性()

多处理器系统下,管家你的问题是可伸缩性。windows有如下功能这些功能对windows做为一个多处理器起到关键性的做用:

1.能一个处理器上运行系统代码,也能够在多个处理器上运行。

2.在单个进程内执行多个线程,这些线程能够在不一样的处理器上运行。

3.内核内部(如自旋锁,排队自旋锁以及压栈锁)以及设备驱动程序和服务器进程内部的细粒度同步,是的多个组件能够并行在多个处理器上运行。

4.如I/O完成端口之类的编程机制,是的能够实现高效的多线程进程,而且这样的程序再多处理系统上有很好的伸缩性。

2.3.4 客户和服务器版本的区别

客户版和服务器版主要区别是有:

支持的处理器个数不一样。

支持的物理内存不一样。

所支持的并发网络链接数不一样。

2.3.5 版本检查

2.4 关键的系统组件

已经看过上面的简易的结构图,了解了高层的结构体系。

以后都会围绕这个图展开,第三章解释windows使用的主要控制机制(如中断,对象管理器)。第五章启动和关闭windows的过程。第四章介绍各个管理机制(注册表,服务进程,WMI)。剩余的章节更加详细的讨论各个关键区域内存结构和操做(进程,线程,内存管理,安全性,I/O,存储管理,高速缓存管理器,windos文件系统和网络)。

 

2.4.1 环境子系统和子系统dll

如上图,最初windows有3个子系统,os/2,posix,wondows。os/2最后一次发布和Windows2000。到了xp posix也不发布了。3个子系统中windows子系统比较特别,是必须启动的。

查看注册表HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems下面有子系统的信息。

 

其中Required值表示了启动要加载的子系统,如上图,值为Debug和Windows。Window值包含了windows子系统的文件规范,csrss.exe它表明了客户/服务器运行时的子系统。Debug为空。Optional值为Os2,Posix表示这2个子系统,被按需启动。Kmode表示windows子系统的内核环境下运行的部分为win32k.sys。

 

环境子系统角色是将windows基础系统服务暴露给应用程序。每一个子系统都提供了对于windows原生服务不一样部分的访问能力。也就是说创建在某个子系统上的应用程序能够作到的,是另外一个创建在不一样子系统的应用程序没法作到的。如posix的fork。

 

每一个exe能够执行映像被绑定到一个子系统上,如VC++ link命令/SUBSYSTEM能够指定类型代码,可使用Exetype工具查看此类型代码。

 

用户程序不能直接调用windows服务而是经过dll来调用如windows子系统dll(kernel32.dll,advapi32.dll,user32.dll,Gdi32.dll),POSIX子系统DLL(psxdll.dll)。当一个应用程序调用子系统可能会发生3中状况:

1.函数彻底在该子系统dll中实现的,在用户模式下运行。

2.该函数要求调用windows执行一次或屡次。

3.改函数要求在环境子系统中完成某个工做。

2.4.1.1 Windows子系统

Windows子系统有一下几个主要组件构成:

1.环境子系统进程(Csrss.exe),包含下列支持:

         a.控制台(文本)窗口

         b.建立或删除进程和线程

         c.对16为虚拟DOS机(VDM)进程的一部分支持。

d.其余一些函数,好比GetTempFile,DefineDosDevice,ExitWindowsEx,以及几个天然语言函数支持。

2.内核模式驱动程序(win32k.sys)包含:

a.窗口管理器,它控制窗口显示管理屏幕输出,采集来自键盘,鼠标,和其余设别的输入,同时也负责将用户的消息传递给应用程序。

         b.图形设备接口,他是专门正对图形输出设备的函数库。

3.子系统dll

子系统dll,如Kernel32.dll,Advapi32.dll,User32.dll,Gdi32.dll,将windows api文档化,对应到Ntoskrnl.exe和Win32k.sys大多数未文档化的系统服务调用。

4.图形设备驱动

         指硬件香瓜你的图形显示器驱动程序,答应及驱动程序和视频微端口驱动程序。

2.4.1.2 POSIX子系统

posix能够当作是一个基于unix的可移植的操做系统接口。值的是正对unix风格的操做系统接口的一组国际标准。posix鼓励厂商实现unix风格,编译在系统之间迁移。

须要使用posix子系统,要求使用platform sdk中使用posix的头文件和库文件。posix是按需启动的当第一次启动posix,psxss.exe要运行起来。posix的映像文件不是直接运行的。一个特殊的称为posix.exe的支持映像文件被启动起来,而后再建立一个子程序来运行posix应用程序。

2.4.1.3 OS/2子系统

和posix同样,有用性颇有限,并且OS/2已经不在适用于windows了。

2.4.2 NTDLL.DLL

NTDLL.DLL是一个特殊的系统支持库,主要用于子系统DLL。包含两个类型函数:

1.系统服务分发存根(stubs),他们会调用Windows执行体系服务。

2.内部支持函数,供子系统,子系统DLL以及其余的原生映像文件使用。

 

第一组函数是为windows执行体系服务提供接口,在用户模式下能够经过接口函数调用windows执行体的系统服务,如(NtCreatefile,NtSetEvent)

 

对于每一个这样的函数,ntdll包含了一个同名入口,函数内部的代码包含了与处理器体系接口相关的模式切换指令,经过该指令可转换到内核模式下,从而调用系统服务分发器。分发器检查某些参数后,再调用真正的内核模式系统服务,其中包含ntoskrnl.exe内部实现代码。

 

NTDLL.DLL也包含了许多支持函数,好比映像文件加载器(以ldr开头的函数)、对管理器、Windows子系统进程通讯函数(Csr开头的函数)、以及通常运行库(Rtl开头的函数)、也包含了异步调用(APC)分发器和异常分发器。

2.4.3 执行体

Windows执行体是Ntoskrnl.exe中的上层,内核是其下层。执行体包含如下几类函数:

1.可在用户模式下调用的导出函数。这些函数成为(系统服务)并经过ntdll导出。还有一些未文档化的如LPC、NtQueryInformationProcess

2.可经过DeviceIoControl函数调用设备驱动器函数。

3.只能在内核模式下导出的函数,而且这儿写函数在Windows DDK或者Windows IFS Kit已经文档化。

4.在内核模式下调用,未在Windows DDK或者IFS Kit中文档化的导出函数。

5.定义为全局符号,可是未被导出的函数。如以Iop或者Mi开头的函数(分别是内部IO管理器支持函数和内部内存管理器支持函数)。

6.未定义为全局符号,而是在一个模块内容的函数。

 

Windows执行体还包含如下组件:

1.配置管理器,复制系统注册表的实现和管理

2.进程和线程管理器,建立或者终止进程和线程。

3.安全应用监视器,强制在本地计算机上实行安全策略,它守护着系统资源执行对运行时对象的保护和审计。

4.I/O管理器:实现了设备无关的I/O,负责将这些操做分发到恰当的设备驱动程序作进一步处理。

5.即插即用(pnp)管理器:为了支持一个特定的设备,肯定驱动,并加载这些驱动。

6.电源管理器:负责协调事件,而且向设备驱动程序产生电源管理I/O通知。如电源管理器设备为系统空间,经过将cpu置于睡眠来下降电源电耗。

7.WDM Windows管理规范例程:容许设备驱动发布有关性能和配置信息以及接受来自用户模式的WMI服务命令。

8.高速缓存管理器:提升了以文件为基础的I/O操做的性能,其作法是让最近引用过磁盘数据留在主内存中以便快速访问。(而且延迟了写操做,在将更新数据发送到磁盘前先在内存中停留一小段时间。)

9.内存管理器:实现了虚拟内存

10.逻辑预取器:加速系统和进程启动过程

 

另外Windows执行提还包含了4组主要支持函数:

1.对象管理器,建立,管理,删除Windows执行体对象和抽象数据类型,这些对象和数据类型表明了操做系统资源。

2.LPC设施,在同一台机器上用户进程和服务器进程之间传递消息。

3.公共运行库,字符串处理,算术操做等函数。

4.执行体支持例程:如系统内存分配,互锁的内存访问,以及2中特殊的同步对象:资源和快速互斥体。

2.4.4 内核

内核是由Ntoskrnl.exe中的一组函数以及对硬件体系结构的低层支持构成的。Ntoskrnl.exe中的这组函数提供了一些最基本的机制。内核代码使用C编写,并不容易在C中访问的任务,则保留使用汇编。大部分函数都已经文档化,以Ke开头。

2.4.5 内核对象

内核给高层作支持。内核实现了操做系统最基本的机制(调度,分发)。把各类策略决定留给了执行体。

内核外看来,执行体将线程和其余可共享资源都表示为对象。这些对象要求一些策略开销。这些开销在内核中不存在,内核实现了一组更简单的对象,称为内核对象,帮助内核控制好中心处理过程,而且支持执行体对象的建立工做。执行体层的绝大多数对象包装了一个或者多个内核对象,把他们的内核属性合并起来。

一组内核对象创建了有关控制各类操做系统功能叫作控制对象,另外一组内核对象融合了同步的能力,改变或者影响线程调度叫分发器对象。分发器对象包含了内核线程,互斥体,事件,内核事件对,信号量,定时器,等待定时器。

执行体经过内核函数建立内核对象实例,维护对象实例。构建更加复杂的对象提供给用户。

2.4.6 硬件支持

内核的另外一个主要功能是将执行体和设备驱动程序从windows所支持的各类硬件体系结构中抽象出来,或者隔离出来变化的差别。

在内核设计是竟可能的使用公共代码最大化。内核支持的可移植性接口,在不一样的体系结构上是等同的。并且实现这组接口的大部分代码,在不一样的结构体系上也是相同的。可是有些代码和体系结构有关,如上下文切换。

从高层看线程选择和上下文切换可使用相同的算法(上一个线程的执行上下文被保存起来,新线程的环境被加载进来),但在不一样的处理器上,实现仍是有差别的。执行上下文是由处理器的寄存器来描述的,因此要保存和加载哪些数据仍是有差异的。

2.4.7 硬件抽象层(HAL)

硬件抽象层是系统可移植的关键。HAL是一个可加载的,内模式模块提供了windows当前运行平台的低层接口。它隐藏了与硬件相关的细节,如I/O接口,中断控制器,以及多处理器通讯机制等,体系结构或者机器相关的功能。

windows内部组件以及用户编写的设备驱动并不直接访问硬件,当它们须要得到与平台相关的信息时,它们能够经过调用HAL例程来保存可移植性。DDK中能找到不少有关HAL在驱动中的用法。

虽然windows带了几个HAL,可是安装时只能有一个被选中,而且copy到系统磁盘,其文件名为hal.dll。

2.4.8 设备驱动程序

设备驱动程序是可加载的内核模式(以.sys结尾),他们在I/O管理器和相应的硬件之间创建连接。驱动在内核模式下,位于如下3个环境之一:

1.在发起I/O功能的用户线程环境中

2.在内核模式系统线程的环境中

3.做为一个中断的结果(所以不存在任何特定的进程或者线程执行环境中)

驱动也是调用HAL,所以驱动程序能够在windows支持的cpu体系结构上代码级移植,在同一个体系结构族内是二进制可移植的。

设备驱动有如下几类:

1.硬件设备驱动程序,经过HAL操做硬件,从而输出到设备或者网络,或者从设备或者网络中输入。硬件设备驱动也有不少类型如,总线驱动,人机界面驱动等。

2.文件系统驱动程序是指能够接受面向文件的I/O请求,并将这些请求转化成针对某一特定设备的I/O请求。

3.文件系统过滤器驱动程序:如截取了I/O请求而且执行某些增值处理以后再传递给下一层驱动(执行磁盘镜像,加密的驱动程序)。

4.网络重定向器和服务器指文件系统I/O请求传递给网络上的某一台机器。或者从网络上接收此类请求的文件系统驱动程序。

5.协议驱动程序,如TCP/IP,NetBEUI,IPX/SPX之类的网络协议

6.内核流式过滤器驱动程序:这样的驱动被串接起来,以便对流数据进行信号处理。

驱动程序是内核模式中添加代码的惟一方式。

2.4.9 系统进程

如下系统进程会出如今每一个windows系统中(其中空闲进程,system进程并非完整的过程,由于它们不是运行在用户模式的可执行文件):

1.空闲进程

2.system进程

3.会话管理器(smss.exe)

4.windows子系统(csrss.exe)

5.登录进程(winlogon.exe)

6.服务控制管理器(services.exe)和它建立的子服务进程(如系统提供通用服务宿主进程svrhost.exe)

7.本地安全认证服务器(lsass.exe)

2.4.9.1 空闲进程

空闲进程是第一个进程,并无在用户模式下的实际映像文件。

2.4.9.2 中断和DPC

标记为中断和DPC(分发过程调用)用于中断和延迟过程调用的时间,他们并非进程,列在这里是由于他们都会消耗cpu,并无计算在任何一个进程中,而是被算在系统空闲中。

2.4.9.3 system进程和系统进程

system进程是一种特殊线程的母体。这些特殊线程只能运行在内核模式哦。系统线程有普通线程全部属性和环境,可是只运行系统空间中加载的代码。系统线程没有地址空间,所以动态存储空间,都必须从系统中内存堆分配,好比换页或者非换页池。

系统线程是由PsCreateSystemThread来建立的,这个函数只能在内核环境下才能被调用。

内核会建立一个称为平衡集管理器的系统线程,每秒没唤醒一次,可能发出调度和内存管理相关事件。告诉缓存管理器也使用系统线程来实现“预读”和”延迟写”功能。

在排查问题是,知道系统线程映射到某个驱动程序中,甚至映射到包含改代码的子例程中,必定很是有用。

因此若是system进程中的线程正在运行,首先要肯定哪些线程在运行。经过线程看哪一个驱动开始的或者检查调用栈,得知在运行到哪里了。

2.4.9.4 会话管理器

会话管理器(smss.exe)是系统中第一个建立的用户模式进程,由负责完成执行体和内核初始化工做的内核模式系统线程最后建立实际的smss.exe进程。

在windows启动过程当中,会话管理器负责许多比较重要的步骤,如打开页面文件,执行延迟文件更名,删除操做,建立环境变量。将子系统程序(csrss.exe)和winlogon.exe启动起来。winlogon进程依次启动其余系统进程。

smss.exe的主线程执行以上步骤后,一直在csrss.exe和winlogon的进程上等待。若是这2个进程中任何一个非正常终止了,则ssms.exe让系统崩溃,(崩溃代码:status_system_process_terminated或0xc000021a)由于windows依赖这2个进程才能运行。

 

smss等待加载子系统的请求,调式事件,以建立新的终端服务器会话的请求。

终端服务会话是由smss来完成的。当smss接到一个建立会话的请求时,先调用NtSetSystemInformation,请求创建内核模式数据结构。又调用内部的内存管理函数MmSessionCreate该函数创建起会话虚拟地址空间,改地址空间包含会话中的换页池以及由win32子系统的内核模式部分和其余的会话空间设备驱动程序所分配,属于某个会话的数据结构,而后会为该会话建立winlogon和csrss实例。

 

2.4.9.5 Winlogon,lsass和Userinit

winlogon登录进程处理交互式用户的登录和注销,当sas被按下(ctrl+atl+del),winlogon接到一个用户登录请求。

登录过程的身份识别和认证是在一个名为GINA(图形识别和认证)的可替换DLL中,windows的标准为GINA为Msgina.dll实现了默认的windows登录界面。然而开发人员能够提供他们本身的GINA DLL来实现其余的身份识别和认证机制如:基于声波的方法。

一旦用户名和口令捕捉到了就能够送到本地安全认证服务器进程(lsass.exe)进行认证。lsass调用适当的认证包,以执行实际的验证操做,好比口令是否符合存储在活动目录或者sam中的口令信息。

在成功完成验证后,lsass调用安全引用监视器中的一个函数(如:NtCreateToken)建立一个访问令牌对象。对象包含当前用户的安全范围。winlogon利用此访问令牌来建立该用户会话中的初始进程默认为userinit.exe。

userinit执行该用户环境的一些初始化工做,而后再查找注册表winlogon下的shell而且建立一个进程来运行系统定义的外壳程序(默认explorer.exe)

而后userinit退出,这就是explorer.exe没有父进程的缘由。winlogon在注销,登录,sas winlogon是活动的。关于登录过程各个步骤的完整秒死能够看第5章。有关安全认证能够查看第八章。

2.4.9.6 服务控制器管理

windows中的服务能够自一个服务器进程,也能够是一个驱动程序。这一指的是用户模式进程(如:unix的守护进程),这些进程能够在系统引导是自动启动起来,而无需交互式的登录过程。也能够被配置为手动启动。

服务控制器是一个特殊的系统进程,用于启动,中止服务进程也复制服务进程之间的交互。服务有3个民粹:运行中进程名,注册表内名称以及管理器的显示名。

在服务进程和所运行的服务之间并非一一对应的,由于有些服务和其余共享一个进程。注册表服务类型代码指明了共享仍是独占进程。

许多windows组件使用系统服务实现如Spooler,event log,Task Scheduler和多个网络组件。

2.5 总结

本章主要归纳的介绍了一遍windows体系结构,检查了一遍关键的组件,他们之间是如何联系起来的。

深刻解析Windows操做系统笔记——CH3系统机制

3.系统机制

微软提供了一些基本组件让内核模式的组件使用:

1.陷阱分发,包括终端,延迟的过程调用(DPC),异步过程调用(APC),异常分发以及系统服务分发

2.执行体对象管理器

3.同步,包括自旋锁,内核分发器对象,以及等待是如何实现的。

4.系统辅助线程

5.其余的机制,好比Windows全局标记

6.本地过程调用

7.内核事件跟踪

8.Wow64

3.系统机制

3.1陷阱分发

3.1.1 中断分发

3.1.1.1 硬件中断

3.1.1.2 软中断请求级别(IRQL)

3.1.1.3 软中断

3.1.2 异常分发

3.1.3 系统服务分发

3.1.3.1 32位系统服务分发

3.1.3.2 64位系统服务分发

3.1.3.3 内核模式的系统服务分发

3.1.3.4 服务描述符表

3.2 对象管理器

3.2.1 执行体对象

3.2.2 对象结构

3.2.2.1 对象头和对象体

3.2.2.2 对象类型

3.2.2.3 对象方法

3.2.2.4 对象句柄和进程句柄表

3.2.2.5 对象安全性

3.2.2.6 对象保持力

3.2.2.7 资源记帐

3.2.2.8 对象名称

3.2.2.9 会话名称空间

3.3 同步

3.3.1 高IRQL的同步

3.3.1.1 互锁操做

3.3.1.2 自旋锁

3.3.1.3 排队自旋锁

3.3.1.4 栈内排队自旋锁

3.3.1.5 执行体的互锁操做

3.3.2 低IRQL的同步

3.3.2.1 内核分发对象

3.3.2.2 快速互斥体和受限互斥体

3.3.2.3 执行体资源

3.3.2.4 压栈锁

3.4 系统辅助线程

3.5 windows全局标志

3.6 本地过程调用(LPC)

3.7 内核事件跟踪

3.8 Wow64

3.8.1 Wow64进程地址空间布局结构

3.8.2 系统调用

3.8.3 异常分发

3.8.4 用户回调

3.8.5 文件系统重定向

3.8.6 注册表重定向和反射

3.8.7 I/O请求

3.9总结

 

3.1陷阱分发

中断和异常是致使处理器转向正常控制流以外代码的两种系统条件。陷阱(trap)是指当异常或者中断发生时,处理器捕捉到一个执行线程,并将控制权转移到操做系统中某处固定地址处的机制。

在Windows中处理器将控制权转给一个陷阱处理器 (trap handle)。所谓陷阱处理器是指与某个特殊的中断或者一场相关的一个函数

 

 

 

内核对待中断和异常是有区别的,中断是异步事件,而且与当前正在运行的任务毫无关系。中断主要由I/O设备,处理器时钟,定时器产生。中断能够容许和禁止。异常是一个同步过程,它是一个特殊指令执行的结果。

异常能够在一样数据在一个程序里重现。异常的例子:内存访问违例,特定的调试器指令,以及除0错误。内核把系统服务调用异常(从技术上讲,他们是系统陷阱(trap))。

当一个硬件异常或者中断产生的时候,处理器在被中断的线程的内核栈中记录机器状态信息,当它能够回到控制流中该点处继续执行。若是该线程在用户模式下执行,那么windows就切换到该线程的内核模式栈。而后windows在被中断的线程的内核栈上建立一个陷阱帧(trap frame),并把线程的执行状态保存在陷阱帧里。在内核调试器中输入dtnt!_ktrap_frame就能够看到陷阱定义。

 

多数状况下内核安装了前端陷阱处理函数,在内核将控制权交给与改陷阱香瓜的其余函数以后或者以前,由这些前段陷阱来执行一些常规的陷阱任务。

如陷阱条件是一个设备中断,则内核硬件中断陷阱处理器将控制权转交给一个由设备驱动程序提供给改中断设备的中断服务例程(ISR)。

若陷阱条件是由于调用了一个系统服务引起,那么通用的系统服务陷阱处理器将控制前交给执行体中指定的系统服务。内核不会为不处理的陷阱安装陷阱处理器。陷阱处理器通常使用KeBugCheckEx,当内核检测到可能致使数据被破坏的行为时,改函数会中止计算机。

3.1.1 中断分发

硬件产生的中断每每是有I/O设置激发的。当设备须要服务就会以中断的方式通知处理器。中断驱动的设置能够一步的进行I/O处理。

系统能够产生软中断,如内核可能触发一个软中断,触发线程分发过程,同时也以异步的方式打断一个线程的执行。

内核安装了中断陷阱处理器来响应设备中断,中断陷阱处理器将控制权递给一个负责该中断的外部例程(ISR)或者传递给一个响应中断的内部内核例程。

下面介绍硬件如何向处理器通知中断,内核支持中断类型,设备驱动如何与内核交互,以及内核如何识别软中断。

3.1.1.1 硬件中断

在windows锁支持的平台上,外部I/O中断进入中断控制器的一个引脚,该控制器在cpu的引脚上中断cpu。中断控制器将IRQ(中断请求)翻译成中断号,利用该中断号做为中断分发表的索引。并将控制权传递给恰当的中断分发例程。

在引导时,windows填充IDT(中断分发表),其中包含了指向内核中负责处理每一个中断和异常的指针。

windows将硬件IRQ映射到IDT上,同时它利用IDT来为异常配置陷阱处理器。虽然windows支持最多256个IDT项,可是支持的IRQ数据量由中断控制机设计决定。

 

3.1.1.2 软中断请求级别(IRQL)

虽然中断控制器已经实现一层中断优先级,可是windows仍然强迫使用它本身的中断优先级方案,称为中断请求级别(IRQL)。

X86,X64,IA64中断请求级别:

 

 

 

中断是按优先级别来处理的高优先会抢占低优先级中断的执行权,当一个高优先级中断发送,处理器会把中断线程上下文保存起来,并调用与中断相关的陷阱分发器,陷阱分发器提高IRQL,并调用中断服务例程,调用完成后下降IRQL,回到中断发送前,被中断线程运行。可是当有其余,低优先级中断时,当IRQL下降,低优先级中断出现。这样,内核会恢复到上述过程来处理中断。

 

线程优先是线程的属性,IRQL是中断源的属性。每一个处理器的IRQL设置能够随系统代码的执行变化。

每一个处理器的IRQL设置决定了该处理器能够接收哪些中断。当一个内核模式线程运行时,能够经过KeRaiseIrql和KeLowerIrql来提高和下降处理器IRQL或经过调用内核同步对象的函数间接提升或者下降IRQL。当处理器的IRQL高于中断源则被屏蔽,不然被中断打断。

访问。

由于访问PIC(中断控制器)比较慢因此引入了优化技术延迟IRQL以免访问PIC。当IRQL被提高,HAL记下新的IRQL而不是去修改中断屏蔽值。当一个较低中断发生则HAL将中断屏蔽值设置为对于第一个中断正常的值。这样当IRQL被提高的时候没有更低优先级中断,则HAL须要修改PIC。

一个内核模式线程根据请求,来下降和升高处理器IRQL。当中断发生时,陷阱处理器(或处理器自己)将改处理器的IRQL提高到中断源的IRQL.这样会把等于或者低于它的全部中断都屏蔽。保证了不被低级中断截掉。被屏蔽的中断由其余处理器处理或者被保存下来知道IRQL降低。

所以系统组件包括内核和设备驱动,都试图让IRQL保持在被动级别。这样能够提升设备启动能够更加及时的响应硬件中断。

每一个中断级别都有特定的目的,如内核发出一个处理器间的中断,以请求另一个处理器执行一个动做。

将中断映射到IRQL:IRQL级别和中断控制器定义的中断请求并不相同,在hal中决定一个中断分配给那个IRQL。而后调用HAL函数HalGetSystemInterruptVector把中断映射到对应的IRQL。

预约义的IRQL:如下介绍一下预约义的IRQL

1.只有当内核在KeBugCheckEx中中止了系统并屏蔽全部中断的时候,内核才会使用高级别的IRQL。

2.电源失败,出如今NT文档中,可是历来没有使用过。

3.处理器间的中断,用于向另一个处理器请求执行一个动做。

4.时钟,主要用于系统时钟,内核利用该黄总段级别来跟踪具体时刻,以及现场测量或者分配cpu时间。

5.性能剖析(Profile),当内核的性能剖析功能被打开的时候,内核性能剖析陷阱处理器会记录下中断发生时被执行的代码的地址。(性能剖析器Kernrate)

6.设备IRQL,用来对设别中断优先级分区

7.DPC/Dispath级别和APC级别是由内核和设备驱动程序产生的软中断。

8.被动级别,最低的IRQL优先级别,它不是一个中断级别,它是普通线程运行时设置的,容许全部中断发生。

对于DPC/Dispatch级别或者更高级别上的代码,一个重要的限制是它不能等待一个对象。另一个限制DPC/Dispatch或者更高级别的IRQL只能访问非换出页内存。若2个限制都违反了系统会崩溃,代码为IRQL_NOT_LESS_OR_EQUAL。在驱动上违反限制是一种常见的错误。在驱动上违反限制上一种建立的错误。

中断对象,内核提供了一种可移植的机制使得设备驱动程序能够为它们的设备注册ISR。这是一个称为中断对象的内核控制对象。

中断对象包含了全部“供内核将一个设别的ISR与一个特定级别的中断关联起来的全部信息”,包含该ISR的地址,该设备中断时所在的IRQL级别,以及内核中该ISR关联的IDT项。

驻留在中断对象中的代码调用了实际的中断分发器,通用是内核的KiInterruptDispatch或者KiChainedDispatch例程,并将指向中断对象的指针传递给它。

下图显示了中断控制流:

 

 

 

将ISR与特定中断级别关联起来的称为链接一个中断对象,将ISR与IDT项断开关联称为断开一个中断对象。这些操做经过内核函数IoconnectInterrupt和IoDisconnectInterrupt完成。

3.1.1.3 软中断

虽然大多数中断都是硬件产生,可是windows内核也为各类各样的任务产生软中断。包括:

1.激发线程分发

2.非时间紧急中断处理

3.处理器定时到期

4.特定线程的环境中异步执行一个过程

5.支持异步I/O操做

分发或者延迟过程调用(DPC)中断,当一个线程不能继续执行的时候,好比由于线程已经终止了或者主动进入等待状态,内核就会直接调用分发器,从而当即致使一个环境切换。可是有时检测到线程已深刻到许多层代码中,这时应该进行从新调度,这种状况下内核请求分发,可是将它推迟到完成了当前的行为以后再进行。

当啮合对共享的内核数据访问,会把IRQL拉到DPC/Dispatch级别当内核检查到须要分发的时候,请求一个DPC/Dispatch中断。因此只有当内核完成了当前的活动,把IRQL拉低,分发中断才能处理。

延迟事务也在这个IRQL上运行,DPC是完成一项系统任务,可是不是那么紧迫,这些函数被称为延迟的,是由于不会了当即执行。

DPC赋予操做系统一种能力,产生一个中断而且在内核模式下执行系统函数。内核利用dpc来处理定时到期,以及一个线程的时限到期之后从新调度处理器。为了给硬件中断提供及时的服务,windows视图把IRQL保持在低于设备IRQL之下。为了达到这个目的,让设备驱动程序ISR执行最少必要的工做来响应他们的设备,将异变的中断状态保存起来,并将数据传输非时间紧迫的中断处理推迟到 DPC/Dispatch IRQL级别上的DPC中在执行。

DPC是经过DPC对象来表示的,DPC对象是内核控制对象,对于用户模式不可见,对于设备驱动和内核代码是可见的。DPC对象包含最重要的信息是DPC中断将要调用哪一个系统函数地址。正在等待的DPC被存放在队列中,每一个处理器都有一个队列称为DPC队列。要想请求一个DPC,系统会初始化DPC对象,而后放入DPC队列中。

默认状况下内核把DPC对象放在发生该DPC请求的处理器的DPC队列末尾。在设备驱动程序只需指定一个DPC优先级别和指定特定CPU,就能够改变这种默认方式。指定在某个CPU上叫定向DPC。若是一个DPC的优先级为低级或者中级则放入队列尾,不然放入队列头部。

当处理器的IRQL从DPC/Dispatch或更高降到某个更低的级别时,内核处理DPC。在处理DPC是IRQL在DPC/Dispatch级别上,而且将DPC来出来运行直到队列为空。当队列为空内核才让IRQL下降到DPC/Dispatch如下。让正常的线程执行过程继续执行。

 

 

 

DPC优先级能够以另外一种方式影响到系统行为。内核一般经过一个DPC/Dispatch级别的中断来激发队列“抽干”的动做。只有当一个DPC被定为在ISR所在的处理器上,且改DPC的优先级是高级或者中级时,内核才产生一个中断,若为低级只有当DPC请求到一个阀值或一段时间后,内核才会请求中断。

若DPC被定为在一个不一样于其ISR运行的CPU上,并DPC为高级。内核当即用一个信号通知CPU,以便”抽干”它的DPC队列。若优先级为中级或者低级则DPC数据超过阀值,内核才会激发一个DPC/Dispatch中断。

DPC中断产生的规则:

DPC优先级别

DPC被定为在ISR的处理器上

DPC被定为在另外一个处理器上

低级

DPC队列长度超过最大的DPC队列长度值,或者DPC请求率小于最小的DPC请求率。

DPC队列长度超过最大的DPC队列长度或者系统空闲

中级

老是激发

DPC队列长度超过最大的DPC队列长度或者系统空闲

高级

老是激发

老是激发

DPC主要为设备驱动提供的,可是内核也使用DPC,内核使用DPC来处理限时到期事件。在系统时钟每一个”嘀嗒”点上,就发生一个时钟IRQL级别的中断。时钟中断处理器对系统时间进行更新,将一个记录了当前线程运行多长时间的计数器递减。当计数器减到0,线程到期,内核可能须要从新调度该处理器,这个任务在DPC/Dispatch IRQL上完成。

时钟中断处理器将一个DPC插入到队列中以便激发分发过程。而后结束他的工做而且下降IRQL,由于DPC中断级别较低,因此在时钟中断完成前出现还没有处理的设备中断,都在DPC中断以前被处理。

APC异步调用,异步过程调用提供了一种在特定用户线程环境中执行用户程序和系统代码的途径。APC通过排队以便在特定线程的环境中执行。

APC是由一个内核控制对象(APC对象)来描述的,正在等待执行的APC驻留在一个由内核管理的APC队列中。APC队列是特定线程相关的,即每一个线程有它本身的APC队列,当内核请求要将APC排队时,它将一个APC排队,她将APC插入到未来执行此APC例程的那个线程的队列中。当内核请求APC级别中断,当该线程最终开始执行的时候,会执行此APC。

有2种APC:内核和用户模式。内核模式的APC并不要求从目标获取许可就能够运行在改线程的环境中,而用户模式必须先获取许可。内核模式的APC有普通和特别2种,将IRQL提高到APC级别或调用KeEnterGuardRegion,就能够静止这两种类型的内核模式APC。

执行体使用内核模式的APC来完成那些必需要在特定线程的地址空间(执行环境)中才能完成的操做系统任务。它能够利用特殊的内核模式APC来指示某个线程中止执行一个可中断的系统服务。

用户模式APC(ReadFileEX,WriteFileEx和QueueUserApc),如ReadfileEx,WritefileEx容许调用者指定一个完成例程,当I/O完成是例程就会被调用。I/O完成机制是经过I/O的线程插入一个APC来实现的。内核APC运行在APC级别上,用户模式APC运行在被动级别上。

APC交付会致使等跌队列从新排序,如APC用来把等待资源的线程挂起,那么该线程就会进入等待访问这个资源队列的末尾。

3.1.2 异常分发

中断能够在任什么时候候发生,异常则是直接由当前正在运行的程序产生。windows引入了一种称为结构化异常处理的设施,应用程序能够在异常发生时得到控制,而后应用程序能够修正条件,并返回到异常发生处,将栈展开(使引起异常的子例程执行过程当中止),或想系统报告,改异常不可识别,由于系统应该继续搜索一个有可能处理此异常的异常处理器。

x86上全部异常都在预约义的中断号,这些中断号对应IDT项。每一个项指向了某个特定异常的陷阱处理器。

全部异常,除了简单的经过陷阱处理器,能够解决的以外,其余都由异常分发器的内核模块服务。异常分发器就是找到一个异常处理器,处理要处理的异常。

异常处理对用户来讲都是透明的,有些异常也容许原封不动的回到用户模式。如内存访问违例,算法溢出,操做系统不对他们处理。环境子系统能够创建起基于帧的异常处理器来处理异常。

基于帧是将一个异常处理与一个特定的过程激活动做关联起来。当一个过程被调用,表明该过程的帧被压到栈中。一个栈帧能够关联多个异常处理器,每一个异常处理器保护源程序中一块特定代码。当发生一个异常时,内核查找与当前帧关联在一块儿的某个异常处理器。若是没有找到内核继续查找与上一个栈帧关联在一块儿的某个处理。若是最终仍是没有找到异常处理器,内核会调用本身默认的异常处理器。

异常发生,CPU硬件将控制权递交给内核陷阱处理器,内核陷阱处理器建立一个陷阱帧。正因为陷阱帧处理完异常后,系统能够从中止的地方恢复。

若是在内核模式下的异常,异常分发器调用一个例程来找到一个基于帧的异常处理器。由它来处理异常。

在用户模式下,windows子系统有一个调试器端口和异常端口,经过它们来接收windows进程中用户模式异常的通知。内核在它默认的异常处理器中用了这些端口。

 

 

 

调试器端口是最多见的异常来源,所以异常分发器采起动做,

1.查看引起该异常的进程是否有一个相关的调试器进程。若存在异常分发器发送一个调试器对象信息到调试对象相关的进程。

2.若该进程没有附载的调试器进程或调试器并无处理该异常,那么异常分发器切换到用户模式下。将陷阱帧按照Context数据结构的格式拷贝到用户栈中,并调用一个例程来找到一个基于帧的异常处理器。

3.若是没有找到或者虽然找到了可是它不处理该异常,则异常分发器切换到内核模式下,而且再次调用调试器,以便让用户作更多的调试。

4.若调试器不在运行,并无找到基于帧的处理器,那么内核向与该线程的进程关联在一块儿的异常端口发送一个信息。该异常端口若是存在的话,则必定是由控制该线程的环境子系统注册的。环境子系统监听该端口,在恰当的时机把一个异常转化为一个与环境相关的信号或异常。客户/服务器运行时子系统(CSRSS)简单的弹出一个消息框来通知用户发生了错误,而且终止进程。

5.当POSIX从内核收到一个消息,指定的一个线程产生了异常,当内核在处理异常过程走得比较深了,而子系统并无处理该异常,那么内核执行一个默认的异常处理器,它只是简单的将引起该异常的线程所在的进程终止掉。

未处理的异常

全部windows线程都有一个异常处理器来处理未被处理的异常。该异常处理器是在windows内部的进程启动函数或线程启动函数中声明。如:

 

 

 

若是一个线程的异常没有被处理,则windows的未处理异常过滤器将会被调用。这个函数目的是,当一个异常未被处理时,能够提供一种系通通一的行为和方法。

3.1.3 系统服务分发

内核陷阱处理器分发中断,异常和系统服务调用

3.1.3.1 32位系统服务分发

在x86 Pentium II处理器以上,使用windows使用sysenter执行触发一个陷阱,这个是intel特别为快速系统服务定义的。为了支持这一指令,windows在引导时刻把内核的服务分发器的地址保存与该指令相关的寄存器中。

执行该指令会致使变化到内核模式下,而且执行系统服务分发器,为了返回到用户模式,系统服务分发器一般执行sysexit执行(当处理器单步标记被打开,系统分发器改而使用iretd指令。)

在K6和更高的32位AMD处理器上,windows使用syscall相似于sysenter,系统嗲用号也在EAX上,而调用者参数则保存在栈中。在完成了分发以后,内核执行sysret指令。

3.1.3.2 64位系统服务分发

在64位体系结构上,windows使用syscall指令进行系统分发(和AMD处理器上syscall相似),系统调用号存在EAX寄存器,前4个参数存放在寄存器汇总其余参数存放在栈中。

在IA64上使用EPC指令,前8个系统调用参数经过寄存器来传递,其余参数经过栈传递。

3.1.3.3 内核模式的系统服务分发

内核利用传递进来的参数找到系统分发表中的服务信息(相似IDT表)。

 

 

 

系统服务分发器KiSystemService将调用的参数从用户模式栈中复制到内核模式,而后执行服务。若是换地给一个系统服务的参数指向了用户空间中的缓冲区,那么在内核模式代码复制到缓冲区或从缓冲区读前先要查明缓冲区是否能够访问。

每一个线程都有一个指针指向它的系统服务表,windows有2个系统服务表,最多能够支持4个。系统服务分发器肯定哪一个表包含了全部请求的服务,它将32位系统服务号中的其中2个位解释成一个索引表。系统服务号低12位被用在该表索引所指定的表中进行的索引。

 

3.1.3.4 服务描述符表

一个主要的默认数组表(KeDescriptorTable)定义了Ntosrknl.exe中实现的核心执行体系统服务。另外一个默认数组表(KeserviceDeseriptorTableShadow)包含了在windows子系统的内核模式部分win32.sys中实现的windows user和GDI服务。

当windows线程第一次调用一个windows user和GDI服务,该线程的系统服务表的地址被指向一个包含windows user和GDI服务的表格。KeAddSystemSericeTable可让win32.sys加入到系统服务表中。

针对windows执行体服务的系统服务分发指令位于NTdll.dll中。子系统调用Ntdll.dll来实现。windows user和GDI函数,在这些函数中,系统分发指令是直接在user32.dll和GDI.dll中实现,没有涉及ntdll.dll。

 

3.2 对象管理器

windows实现了一个对象模型,以便为执行体的实现各类内部服务提供了一致的,安全的访问路径。执行体内部复制建立,删除,保护和跟踪对象的组件(windows对象管理器)。

对象管理器把本来可能散落在整个系统各处的资源控制操做集中在一块儿。对象管理器的设计意图是为了实现本章稍后列出的一些功能。

1.提供一种公共,同一个的机制来使用系统资源

2.将对象保护隔离到操做系通通一的区域中,从而能够作到c2安全等级

3.提供一种来记录进程使用对象数量的机制,从而能够对系统资源的使用上加限制。

4.简历一套对象命名方案,能够很方便的融合现有对象。

5.支持各类操做系统环境的须要

6.简历统一的规则来维护对象的保持力。

windows内部有两种类型的对象:执行体对象和内核对象。

执行体对象是指执行体的各类组件所实现的对象(如,进程管理器,内存管理器,I/O子系统)内核对象是指windows内核实现的一组更为基本的对象。这些对象在执行体内部被建立和使用。

 

3.2.1 执行体对象

每一个windows环境子系统老是把操做系统的不一样面貌呈现给它的应用程序。执行体对象和对象服务是环境子系统用于构建其本身版本的对象和其余资源基础。

执行体对象每每由在用户应用程序中通常的环境子系统或由操做系统的组件做为他们常规操做的一部分而建立。如为了建立一个文件,windows应用程序调用windows的createfile函数,该函数在windows子系统DLL kernel32.dll中现实中实现的,在通过了一些验证和初始化工做之后,createfile会调用原生的windows服务ntcreatefile来建立一个执行体文件对象。

windows子系统使用执行体对象来导出它本身对象集合,其中许多对象直接对应于执行体对象。

暴露给windows api的执行体对象:

对象类型

所表明的含义

符号连接(Symbolic link)

间接的引用一个对象名字的机制

进程(Process)

虚拟地址空间,以及为了执行一组线程对象而必需的控制信息

线程(Thread)

进程内部的一个可执行实体

做业(Job)

指一组进程,经过做业机制,能够像单个实体那样来管理他们

内存区(section)

共享内存的一个区域(在windows中也称为文件映射对象)

文件(File)

一个已打开的文件或者I/O设备的实例

访问令牌(Access token)

一个进程或者线程的安全轮廓(安全ID,用户权限等)

事件(Event)

一个具备持久状态(有信号,或者无信号的)的对象,可被用于同步或者通知。

信号量(Semaphore)

信号量是一个计数器,它提供了资源门控能力,对该信号量所保护的资源只容许某个最大数目的线程来访问它。

互斥体(Mutex)

用于顺序访问一个资源的一种同步机制

定时器(Timer)

这是一种当固定长时间过去时,通知一个线程的机制

IO完成(IoCompletion)

使线程可以将”I/O操做完成通知”进出队列的一种方法,在windows中称为IO完成端口。

键(Key)

这是一种引用注册表中数据的机制。

窗口站(WindowStation)

该对象包含了一个剪贴板,一组全局原子和一组桌面对象

桌面(Desktop)

这是一个被包含在窗口站内部的对象。桌面对象有一个逻辑显示器表面,其中包含了窗口,菜单和钩子。

3.2.2 对象结构

每一个对象都有一个对象头和对象体,对象管理器控制了对象头,而执行体组件则控制了由它们建立的对象类型的对象体。每一个对象头指向一个进程列表,类表中每一个进程都打开了此对象。对象类型指向了称为类型对象的特殊对象。

 

 

 

3.2.2.1 对象头和对象体

对象管理器使用对象头中保存的数据来管理这些对象,而无须关系它们的类型。

标准对象头的属性:

属性

用途

对象名称

使一个对象对于其余的进程也是可见的,以便于共享

对象目录

提供了一个层次结构来存储对象名称

安全描述符

决定谁可使用该对象,以及容许它们如何使用它(注:对于没有名称的对象来讲,安全描述符是空[null])

配额花费

列出了当一个进程打开一个指向该对象的句柄时,针对该进程收取的资源花费额

已打开句柄的计数

记录了“打开一个句柄来指向该对象”的次数

已打开句柄的列表

指向一个进程列表,其中每一个进程都打开了指向该对象的句柄。

对象类型

指向一个类型对象,该对象包含了正对这个类型的对象都是公共属性

引用计数

记录了一个内核模式组件引用该对象地址的次数

除了对象头之外,每一个对象也有一个对象体,而且其格式和内容只有这种对象类型才有,同一类型的全部对象共享一样的对象体格式。一个执行体组件经过建立一个对象类型,而且为它提供一些服务,就能够控制和维护全部这个类型的对象体中的数据。

对象管理器提供了少许经过服务,经过这些服务能够对一个对象头中保存的属性进行操做,经过服务能够用再任何类型的对象上。

虽然通用的对象服务都支持全部对象类型,可是每一个对象都有它本身的建立,打开和查询服务。

3.2.2.2 对象类型

对象头中包含的数据对于全部对象都是公共的,可是每一个对象实例能够取不一样的值。

为了节省内存,对象管理器只在建立一个新的对象类型时才会存储静态的,特定于对象类型的属性。

进程对象和进程类型对象:

 

 

 

类型对象的属性

属性

用途

类型名称

此种类型的对象名称(“process”,”event”,”port”)

池类型

指明了这种类型的对象是从换页的仍是非换页的内存中分配

默认的配额花费

默认从进程配额中扣除的换页内存池值和非换页内存池值

访问类型

当一个线程打开某个指向该类型的对象时能够请求的访问类型(“读”,”写”,”终止”,”挂起”)

通用访问权限的映射关系

在4种通用的访问权限和属于该类型的访问权限之间的映射关系。

同步

指明了一个线程是否能够等待这种的对象

方法

在一个对象的生命周期的特定点上,对象管理器自动调用的一个或者多个例程。

一个对象可否支持同步,取决于该对象是否包含了一个内嵌的分发器对象,在“低IRQL的同步”中有介绍。

3.2.2.3 对象方法

上面的表中,最后一个属性就是方法。方法是由一组内部例程构成的,这些例程相似构造和解析函数(在建立和销毁时被使用)。

当一个执行体组件建立了一个新的对象类型时,它能够像对象管理器注册一个或多个方法,对象管理器在此种类型的对象生命周期中,某些明肯定义的点上调用这些方法。

对象方法:

方法

什么时候调用

Open

当一个对象句柄被打开

Close

当一个对象句柄被关闭

Delete

在对象管理器中删除一个对象以前

Query name

当一个线程在一个从属名字空间中查询一个对象的名称时

Parse

当对象管理器在一个从属名字空间中搜索一个对象名称时

Security

当一个进程读写(如文件)在其从属名字空间中的保护属性时。

3.2.2.3.1 Open函数

对象管理器建立一个指向对象的句柄时会调用open方法,在对象被建立或者打开时候运行。只有一个对象类型(windowstation)定义了open方法。这样win32.sys可以与服务于桌面相关内存池的进程共享内存。

3.2.2.3.2 Close函数

close方法的例子是IO中,对象管理器关闭一个句柄使用close方法。close方法先检查看正在关闭该文件句柄进程是否有任务用于该文件而且未完成的锁,若是有则除去锁。

3.2.2.3.3 Delete函数

对象管理器在内存中删除临时对象之前,调用delete方法。内存管理器为内存区对象类型注册了delete方法,它会释放该内存区使用的物理页面。并在删除内存区对象前验证一下内存管理器为该内存区所分配的任何内部数据结构已被删除了。

3.2.2.3.4 Parse函数(相似于Query name)

若发现对象存在于对象管理器名字空间外,容许对象管理器把查找一个对象的控制权交给一个从属的对象管理器。若在搜索路径上碰到一个关联了parse的对象,会暂停搜索。对象管理器调用parse方法。将正在搜索的对象名称的剩余部分传给parse方法。除了对象管理器方法外在windows中还有注册表名字空间和文件系统名字空间。例如打开一个名为\Device\Floppy0\docs\resume.doc的文件句柄,对象管理器遍历它的名称树,直到到达Floppy0。调用parse,把\docs\resume.doc传入。I/O管理器的parse例程接受名称,而且传给文件系统,文件系统找到文件并打开。

3.2.2.3.5 Security方法

Security也是I/O系统使用方法,相似parse。一旦一个线程视图查询或改变那些用于保护一个文件的安全信息时,该方法就会被调用。安全信息是存储在文件对象中,而不是内存,所以必须调用I/O系统才能找到安全信息,并将它们读出来或进行修改。

3.2.2.4 对象句柄和进程句柄表

当进程根据名称来建立或者打开一个对象时,它会接受到一个句柄,经过句柄来访问一个对象,要比使用名称访问快得多。由于对象管理器能够跳过名称查找过程,直接找到目标对象。进程也能够在其建立时刻经过继承句柄的方式得到句柄或从另外一个进程接收一个复制的句柄。

全部的用户模式进程在其线程使用一个对象之前,必须先拥有一个指向该对象的句柄。句柄被用作指向系统资源的间接指针,这样可让应用程序不与系统数据结构直接交互。

对象句柄仍是提供了额外的一些好处:第一,不一样句柄没有什么区别可使用统一的接口来引用。第二,对象管理器有独立的权利来建立句柄,查找句柄。也就是对象管理器能够仔细地审查每一个可能会影响对象的用户模式动做。

对象句柄是索引与进程相关的句柄表中的项相关。执行体进程(EPROCESS)块中一个域指向句柄表。句柄表实现方式是3层和虚拟地址到物理地址映射相似。

当进程被建立对象管理器分配了句柄表的最高层结构,其中包含了指向中间层表的指针;同时也建立了中间层,其中包含了第一个指向子句柄表的指针数组,还分配了最底层,其中包含了第一个子句柄表。

 

 

 

把低24位当作3个8位,分别索引到3层结构中的一层。在xp,2003在进程建立时,最底层句柄表被分配,其余的都会被按需分配。在windows 2000中一个子句柄表是255个可用表项。在xp,2003表项=(页大小/表项大小)-1。在windows xp,2003上句柄表项:

 

 

 

P:说明了调用者是否容许关闭句柄。I:该进程建立的子进程是否在它们句柄表中有一份该句柄的拷贝。A:关闭该对象时是否应该产生一个升级信息(对象管理器内部使用该标记)。

系统组件和设备驱动程序一般须要打开一些不该该让用户访问的对象。能够经过内核句柄表来表示。内核句柄表只有在内核模式下能够飞昂文,能够在任何进程环境下。

对象管理器看到一个句柄的高位被设置时,就会将它识别为内核句柄表中的句柄。也就是说内核句柄表中的句柄的引用值大于0x80000000。在windwos 2000中内核句柄表是一张独立的句柄表,可是在xp和2003中,内核句柄表也被用作system进程的句柄表。

3.2.2.5 对象安全性

当一个进程打开一个句柄,对象管理器调用安全引用监视器,监视该对象描述符是否容许该进程所请求的访问类型,若容许,引用监视器返回一组准许的访问权限,同时对象管理器放入它建立的对象句柄中。

当下次进程要使用句柄时能够快速的检查这一组句柄中的准许访问权限。

3.2.2.6 对象保持力

对象保持力,分为暂时和永久的。暂时是当须要的时候使用,不须要的时候释放。永久是一直保持知道被显式释放。

对象管理器经过两个阶段来实现对象保持力。第一阶段称为名称保持力,第二个阶段,再也不有用时,中止保留对象自己(也就是删除)。

名称保持力:当一个进程打开一个对象的句柄。会在该对象头信息中的已打开句柄计数器+1。当用完关闭句柄,对象管理器已打开句柄-1,。当计数器为0,对象管理器从全局名字空间中删除该对象名称。

再也不有用时删除:对象专门提供一个引用计数来记录。

已打开句柄计数器:当进程打开一个对象句柄+1,关闭句柄-1

引用计数:提供一个对象指针+1,用完了-1

当已打开计数器为0,引用计数大于0.表示对象还在使用。当引用计数为0,对象管理器会从内存中将它删除。

 

进程A,进程B和内核结构引用了一个对象,所以handlecount=2,referencecount=3。

3.2.2.7 资源记帐

windows对象管理器提供了一个中心设施来实现资源记帐。每一个对象头都包含了配额花费。

windows每一个进程都指向一个配额的数据结构,配额为0表示不限制。

3.2.2.8 对象名称

对象名称能够知足1.区分对象之间的方法。2.找到并得到特定对象的方法。3.容许程序间共享。

只有2种状况会使用名称进行查找,1.建立一个命名对象时,会经过名称查找,验证全局名称空间中不存在。2.当打开一个句柄,句柄指向一个命名对象时,对象管理器查找该名称并返回一个对象句柄。

对象的名称存储位置取决于对象类型

目录

所存储对象名称的类型

\GLOBAL??

Ms-dos设备名(\DosDevices是指向此目录的符号连接)

\BaseNameObjects

互斥体,时间,信号量,可等待的定时器和内存区对象

\Callback

回调对象

\Device

设备对象

\Driver

驱动程序对象

\FileSystem

文件系统驱动程序对象和文件系统识别器对象

\KnowDlls

已知DLL(在启动时候由系统映射的DLL)的内存区名称和路径

\Nls

已映射的国家语言支持表的内存区名称

\ObjectTyoes

对象类型名称

\RPC Control

远程过程调用(RPC)所使用的端口对象

\Security

与安全子系统相关的对象的名称

\Windows

Windows子系统的端口和窗口站

对象的名称相对于一台计算机而言是全局的,可是他们的跨越网络是不可见的。可是对象管理器解析名称的方法使得有可能访问其余机器上的命名对象。

对象目录是对象管理器支持这种层次型命名结构手段。对象目录解析对象名称为指向对象的指针。对象管理器利用指针来构建对应的句柄,将这些对象句柄返回给用户模式的调用者。

符号连接,在某些文件系统中,经过符号连接,用户能够建立一个文件名或一个目录名,当被使用的时候,实际上被操做系统转译成另一个不一样的文件或文件名。使用符号连接,是一种让用户间接的共享一个文件或目录的内容。

符号连接对象,完成的功能相似于对象名称的功能同样。当对象名称中有符号连接,对象管理器遍历它的对象名称空间,找到该符号连接对象,并找到一个取代该符号连接名的字符串。

3.2.2.9 会话名称空间

一个登录到控制台会话上,用户能够访问全局名称空间,另外会话能够得到该名称空间的私有名称空间实例。\DosDevices,\Windows,\BaseNamedObjects属于会话局部的名称空间,都会被放在私有名称空间中。将名称空间中相同部分复制,来初始化名称空间。

对象管理器在\session\X下建立私有版本,对象管理器以透明的方法,将对象的名称从\BaseNameObjects重定向到\session\2\BaseNamedObjects。

windows子系统DLL将windows应用程序传过来的位于\DosDevice中对象引用加上\??前缀(c:\windows变成\??\c:\windows)。依赖于EPROCESS中DeviceMap。DeviceMap结构中DosDevicesDirectory域所指的对象目录管理器表明了进程的局部DosDevices。

在windows 2003和xp上,系统没有将全局对象拷贝到局部DosDevices目录中,当看到\??会经过DeviceMap中DosDevicesDirectory找到该进程局部\DosDevices目录。若在局部中没有,而且DeviceMap有效,则会在GlobalDosDevicesDirectory查找对象。

当会话中的应用程序要与其余会话的实例同步在任何对象名称前加入\Global\ApplicationInitialized被重定向到\BasedNameObjects\ApplicationInitized而不是\Sessions\2\BaseNamedObjects\ApplicationInitialized。

在2003和xp中应用程序只要在\DosDevices中没有这样的对象就会访问全局,不须要使用\Global。

3.3 同步

当一个资源不容许共享访问,或共享访问致使不可预测的后果则须要互斥。若一段代码访问了一个不可共享的资源,则这样的代码区成为临界区。

3.3.1 高IRQL的同步

在内核执行的各个阶段,内核必须保证,在临界区内部同一时刻只有一个处理器在执行。

在中断发生,内核可能在更新一个全局数据结构,而中断的处理例程可能也要修改此数据结构。在单处理器,能够用如下方式来避免。如,当线程修改全局数据结构时,禁止全部中断。windows的做法是执行临界区时,把IRQL拉高会用到该数据结构的最高IRQL。

3.3.1.1 互锁操做

这个最简单的同步方式,依赖于支持多处理器硬件,操做一个整型值来进行比较。

3.3.1.2 自旋锁

自旋锁是内核用来实现多处理器互斥的机制

 

在windows中,全部内核模式自旋锁都有一个与之关联的IRQL。当运行自旋锁就会拉高IRQL。

3.3.1.3 排队自旋锁

工做方式:当一个处理器要得到已被其余处理器持有的队列自旋锁锁时,把本身的标示符放入一个与该自旋锁关联的一个队列中。

当自旋锁被释放,将锁交给队列中第一个标示符对于的cpu。

在同时处理器等待一个较忙的自旋锁不是检查自旋锁自己而是每一个处理器的标志。在队列中位于它以前的处理器会对它设置,代表轮到这个等待的处理器了。

排队的自旋锁的天然结果是,他们在每一个处理器标识符上旋转,而不是全局自旋锁上旋转有2个效果:

1.多处理器总线不会由于处理器之间的同步招致繁重的流量。

2.排队增强了先进先出的顺序,处理器之间性能更加一致。

在windows中定义了不少全局队列自旋锁,而且在每一个处理器的“处理器控制区域(PCR)”包含了一组数组(保存了指向这些全局队列的自旋锁指针)。当调用KeAcquireQueueSpinLock的时候将一个PCR的索引传进去,能够得到对应的全局自旋锁。

3.3.1.4 栈内排队自旋锁

除了使用全局定义的静态排队自旋锁,xp和2003还提供了KeAcquireInstackQueuedSpinlock和KeReleaseInstackQueuedSpinlock。来支持动态分配的排队自旋锁。

3.3.1.5 执行体的互锁操做

内核提供了不少简单的创建在自旋锁基础上的同步函数。

3.3.2 低IRQL的同步

自旋锁使用有严格的限制:

1.对于受保护的资源,必须快速访问,不要与其余代码有复杂的交互关系

2.临界区代码的内存页不能换出去,不能引用可被换页的数据,不能调用外部过程,不能中断或异常。

在自旋锁不适合是可用:内核分发器对象,快速互斥体和受限互斥体,压栈锁,执行体资源。

 

是否暴露给设备驱动程式使用

禁止常规的内核模式APC

禁止特殊的内核模式APC

支持递归获取操做

支持共享的和独占的获取操做

内核分发器互斥体

内核分发器信号量

快速互斥体

受限互斥体

压栈锁

执行体资源

3.3.2.1 内核分发对象

内核之内核对象的形式,向执行体提供了额外的同步机制,这些内核对象合起来统称为分发器对象。每一个支持同步的用户可见对象都封装了至少一个内核分发器对象。

 

3.3.2.1.1 等待分发器对象

一个用户模式的线程等待一个事件对象的句柄。

内核将该线程的调度状态从就绪状态改变成等待状态,而后将该线程加入到正在等待该事件的线程列表中。

另一个线程设置了该事件,内核沿着该事件的等待线程队列向前搜索。如有一个线程等待条件知足将线程状态从等待改成就绪。如果一个可变优先级的线程,则内核可能也要提高它的执行优先级。

由于一个新线程已经变成就绪执行状态,因此进行从新调度。若是它找到一个正在运行的线程。其优先级低于就绪线程的优先级。那么会抢占此低优先级的线程,而且发出一个软中断,以便激发一个环境切换,切换到高优先级的线程中。

若是没有处理器能够抢占的话,则分发器将该就绪线程放到分发器就绪队列中,之后再被调度。

3.3.2.1.2 若是Signals一个对象

3.3.2.1.3 数据结构

typedef struct _DISPATCHER_HEADER {

UCHAR Type;

UCHAR Absolute;

UCHAR Size;

UCHAR Inserted;

LONG SignalState;

LIST_ENTRY WaitListHead;

} DISPATCHER_HEADER;

typedef struct _KWAIT_BLOCK {

LIST_ENTRY WaitListEntry;

struct _KTHREAD *RESTRICTED_POINTER Thread;

PVOID Object;

struct _KWAIT_BLOCK *RESTRICTED_POINTER NextWaitBlock;

USHORT WaitKey;

USHORT WaitType;

} KWAIT_BLOCK, *PKWAIT_BLOCK, *RESTRICTED_POINTER PRKWAIT_BLOCK;

每一个分发器对象都有一个等待列表,列表中一项表明一个等待该对象的线程。因此当线程向一个分发器对象发出信号,内核能够很快的肯定谁在等待对象。

等待快结构WaitListEntry指向被等待对象,Thread指向等待线程,NextWaitBlock指向下一个等待块。

 

 

 

3.3.2.2 快速互斥体和受限互斥体

快速互斥体也成为执行体互斥体,比互斥体对象提供了更好的性能。尽管他们也是创建在分发器事件对象基础上的,可是若是对于快速互斥体没有竞争的话,他们无须等待事件对象。

受限互斥体,本质上它与快速互斥体是相同的。使用了KGATE同步对象,经过调用KeEnterGuardedRegion来进制全部内核模式APC的事务,主要用户内存管理器。

3.3.2.3 执行体资源

执行体资源是一种支持共享和独占访问的同步机制,要求APC事务禁止,若是一个线程正在等待得到一个共享访问权,则它应该等待一个与该资源相关联的信号量,若是一个线程正在等待得到一个资源的独占访问权,则应该等待一个事件。

当一个独占持有者经过给信号量发型号来释放一个资源唤醒共享访问者。

当一个线程在等待独占访问一个资源,而该资源正在被其余线程拥有,该线程等待一个同步事件对象。

3.3.2.4 压栈锁

压栈锁是创建在KGATE同步对象基础之上,相比快速互斥体好处是能够按照共享的方式独占的模式来得到。

有两种类型压栈锁:普通压栈锁和能感知缓存的压栈锁。

普通压栈锁:当一个线程想要得到一个普通的压栈锁,若还没有被使用则压栈锁代码标记为已被占用。若已被占有(共享,独占),线程在本身栈上分配一个等待块,将初始化等待块中的事件对象,等待块加入到与压栈锁相关联的等待列表中。向该等待着的等待块中的事件发出信号。

能感知缓存的压栈锁简历在基本压栈锁之上。为每一个处理器分配一个压栈锁,而后将这些压栈锁和处理器关联起来。当一个线程但愿以共享方式得到压栈锁时,简单的得到对应于当前处理器的那个压栈锁以独占方式得到独占锁时,以独占模式得到每一个处理器的压栈锁。

压栈锁的使用范围包括对象管理器和内存管理器,对象管理器中,能够保护全局对象管理器结构和对象安全描述符,在内存管理器,他们能够保护awe数据结构。

3.4 系统辅助线程

windows在system进程中建立了几个线程,这些线程称为系统辅助线程它们表明其余线程来完成一些工做。如DPC级别的IRQL不能运行更低IRQL级别才能执行的函数,必须将这样的处理过程传递给一个低于DPC级别的IRQL的执行线程上。

设备驱动程序或执行体组件经过ExQueueWorkItem和IoQueueWorkItem把工做放到一个队列分发器对象上,系统复制线程在该对象上寻找工做。工做包含一个例程以及一个参数,当辅助线程处理该工做,会把参数传递给例程。

系统辅助线程有如下三类:

延迟型辅助线程:优先级12上,处理器非紧急工做项目,当它在等待工做项目时容许栈页面被换出到页面文件中。

紧急型辅助线程:优先级13,处理一些紧急工做项目,始终在内存上

超紧急型辅助线程:优先级15,总在内存中。

执行体函数ExpWorkerThreadBalanceManager肯定是否建立新的紧急型辅助线程,新的线程被称为动态的辅助线程。建立时必须知足下列条件:

1.在紧急工做队列下有工做项目

2.不活动的紧急型辅助线程的数目必须少于系统处理器个数

3.动态辅助线程数据少于16个。

3.5 windows全局标志

3.6 本地过程调用(LPC)

LPC用于进程间通讯,LPC为了如下3中方式通讯而设计:

1.短于256字节的信息能够经过LPC发送。从发送进程拷贝到系统地址空间中,再从系统地址空间中拷贝到接收进程地址空间中。

2.若多于256字节则复制到共享内存区。

3.若超过了内存共享区,能够直接在地址空间中读取或写入。

LPC有多种端口:服务器链接端口,服务器通讯端口,客户通讯端口,未命名的通讯端口

 

 

 

3.7 内核事件跟踪

一个公共的基础设施,向内核和ETW提供痕迹数据应用程序要使用到ETW,要属于如下3类:

1.控制器,启动或中止,也管理缓冲区

2.提供者,为它所能产生的事件类定义GUID,并注册到ETW以上,并接受控制器命令,启动,中止它所负责的事件类跟踪。

3.消费者,选择一个或多个会话,读取数据。

控制器启动内核记录器(ETW库)向WMI发送一个IO请求说明要开始跟踪哪些事件类。当WMI接受到已启动跟踪源接收到数据就会写入buffer,每隔一秒触发一次写入日志文件。

3.8 Wow64

64位windows上win32仿真,也就是能够在64位上执行32位,x86应用程序。以DLL形式来实现。

wow64.dll实现了文件系统重定向,以及注册表重定向和反射

wow64cpu.dll实现了cpu从32到64,从64到32之间的切换

wow64win.dll截取了win32k.sys导出GUI系统调用

 

 

 

3.8.1 Wow64进程地址空间布局结构

wow64进程能够是2G,也能够是4G虚拟空间。若没有设置大地址空间感知标志则最多保留2G,若开启大地之空间感知标志最多保留4G。

3.8.2 系统调用

Wow64.dll钩住从32位代码变值原生64为系统代码路径,也钩住64位原生系统须要调用至32位用户模式代码的全部代码路径。

启动应用程序,64位ntdll.dll映射到地址空间,初始化判断映像头为32位x86则加载wow64.dll映射32位ntdll.dll,创建ntdll内部启动环境切换到32位,执行32位加载器。

64位和32位间经过wow64在之间转换。

3.8.3 异常分发

经过wow64来转化异常分发。

3.8.4 用户回调

经过wow64来转化

3.8.5 文件系统重定向

为了下降应用程序移植代价,全部相关API将windows\system32替换为windows\syswow64。使用文件系统重定向来实现。

线程使用wow64enable,wow64FsRedirection函数进制文件系统重定向。

3.8.6 注册表重定向和反射

注册表也使用重定向在注册表上建立原生和wow642中,视图为了容许32和64位com组件互操做,在注册表中某些特定部分被更新,wow64也会将这些更新映射到迎来一个视图。

3.8.7 I/O请求

IO除了读写硬盘还能够用于程序通讯,驱动程序通IoIs32bitProcess来检测是否从一个wow64进程发出的。

3.9总结

主要介绍执行体创建起来的基本系统机制。