admin管理员组

文章数量:1595880

1.1.1 Windows 10 和未来版本

在Windows 10中,微软宣布将以比以前更快的速度更新Windows。不会有正式的“Windows 11”;相反,Windows更新会将现有的Windows 10更新为新版本。如2015年11月更新的Win 10版本称为1511版,2016年7月更新的Win 10 版本为1607版。
目前Win 10系统已经成功更新到了1909版,下图为MSDN中Win10操作系统版本列表。

1.1.2 Windows 10和OneCore

除了主流的个人电脑Windows系统外,Xbox360游戏机运行一个派生的Windows2000。WindowsPhone7运行一个基于WindowsCE的变体。维护和扩展所有这些代码基显然是困难的。因此,微软决定将内核和基础平台支持的二进制文件合并为一个。首先,Windows 8和Windows Phone 8具有共享内核(Windows 8.1和Windows Phone 8.1具有聚合的Windows运行时API)。有了Windows 10,融合就完成了;这个共享平台被称为OneCore,它运行在个人电脑、手机、Xbox One游戏机、HoloLens和物联网(IoT)设备上,如树莓派Pi 2。

显然,所有这些设备的组件大不相同。有些功能在某些设备上根本不存在。例如,在HoloLens设备上支持鼠标或物理键盘可能没有意义,因此您不能期望这些部件出现在此类设备的Windows 10版本上。但是内核、驱动程序和基础平台二进制文件本质上是相同的(基于注册表和/或基于策略的设置,在这些设置中,它们出于性能或其他原因是有意义的)。

1.2 基础概念和术语

1.2.1 Windows API

Windows应用程序编程接口(API)是Windows操作系统系列的用户模式系统编程接口。Windows API分为:Win16 API,Win32 API,Win64 API,windowsdk文档中描述了Windows API。

Windows API风格
Windows API最初只包含C风格的函数。因为C具有最强的兼容性,可以和其他语言交互,并且它足够底层能够和操作系统服务交互。缺点是函数的数量太多,缺少命名一致性和逻辑分组(例如,C++命名空间)。这些困难的一个结果是,一些较新的API使用了不同的API机制:组件对象模型(Component Object Model,COM)。

COM最初创建的目的是使Microsoft Office应用程序能够在文档之间通信和交换数据(例如在Word文档或PowerPoint演示文稿中嵌入Excel图表)。这种能力称为对象链接和嵌入(OLE)。OLE最初是使用名为动态数据交换(DDE)的旧Windows消息传递机制实现的。DDE本质上是有限的,这就是为什么开发了一种新的通信方式:COM。事实上,COM最初被称为OLE 2。

下图为在Word文档中插入的OLE对象,通过由文件创建的对象如果指定文件路径为恶意文件,并选择显示为图标,那么Word文档中会插入一个新的图标,点击图标可触发恶意文件。
![在这里插入图片描述]

在Word和Excel里,可以使用DDE来执行命令。下图为Word中插入DDE代码的截图,在Word中可以通过Ctrl+F9添加一个域,然后插入DEE代码。图中为自动开启计算器程序的DDE代码。


COM基于两个基本原则。首先,客户端通过接口与对象(有时称为COM服务器对象)通信。这将导致二进制兼容性和编译器名称损坏问题的消除。因此,有可能从许多语言(和编译器)调用这些方法,例如C、C++、Visual Basic、.NET语言、Delphi等。第二个原则是动态加载组件实现,而不是静态链接到客户端。

COM服务器通常指实现COM类的动态链接库(DLL)或可执行文件(EXE)。COM还具有其他与安全性、跨进程编组、线程模型等相关的重要功能。

Windows Runtime

Windows 8引入了一个新的API和支持Runtime(运行时),称为Windows运行时(有时缩写为WinRT,不要与Windows RT混淆,后者是已停止使用的基于ARM的Windows操作系统版本)。Windows Runtime由平台服务组成,特别针对所谓的Windows应用程序开发人员。

从API的角度来看,WinRT是建立在COM之上的,它向基本COM基础设施添加了各种扩展。例如,完整的类型元数据在WinRT(存储在WINMD文件中并基于.NET元数据格式)中可用,它在COM中扩展了一个类似的概念,即类型库。从API设计的角度来看,它比经典的Windows API 函数更具内聚性,具有名称空间层次结构、一致的命名和编程模式。

各种api和应用程序之间的关系并不是直接连接。桌面应用程序可以使用WinRT api的一个子集。相反,Windows应用程序可以使用Win32和COM api的子集。但是,在基本二进制级别上,WinRT API仍然基于传统Windows二进制文件和API之上,即使某些API的可用性可能没有文档记录或支持。对于系统来说,它不是一个新的“本机”API,就像.NET仍然利用传统的Windows API一样。

C++语言、C语言(或其他.NET语言)编写的应用程序和JavaScript可以很容易地使用WiRtAPI来开发这些平台的语言预测。对于C++,微软创建了一个称为C++ /CX的非标准扩展,使其更容易使用WRET类型。.NET的普通COM互操作层(带有一些支持运行时扩展)允许任何.NET语言自然地、简单地使用WinRT API,就像它是纯.NET一样。对于JavaScript开发人员,开发了一个名为WinJS的扩展来访问WinRT,尽管JavaScript开发人员仍然必须使用HTML来构建他们的应用程序的用户界面。

.Net 框架

.Net 框架是Windows系统的一部分,下面是不同的操作系统版本默认对应的.Net框架版本。

.NET框架由两个主要组件组成:

The Common Language Runtime(CLR):这是.NET的运行时引擎,包括一个实时(JIT)编译器,它将公共中间语言(CIL)指令转换为底层硬件CPU机器语言、垃圾收集器、类型验证、代码访问安全性等。它被实现为一个COM进程内服务器(DLL),并使用WindowsAPI提供的各种工具。

The .NET Framewor Class Library(FCL):这是实现客户机和服务器应用程序通常需要的功能(如用户界面服务、网络、数据库访问等)的大型类型集合。

通过提供这些功能和其他功能,包括新的高级编程语言(C#、Visual Basic、F#)和支持工具,.NET框架提高了开发人员的工作效率,并提高了针对它的应用程序的安全性和可靠性。下图显示了.NET框架和操作系统之间的关系。

1.2.2 服务、功能和Routines

Windows用户和编程文档中的几个术语在不同的上下文中有不同的含义。例如,单词service可以指操作系统中的可调用例程、设备驱动程序或服务器进程。以下列表描述了本书中某些术语的含义:

  • Windows API函数:这些函数是Windows API中有文档记录的可调用的子例程。示例包括CreateProcess、CreateFile和GetMessage。

  • **本机系统服务(或系统调用)**这些是操作系统中未记录的、可从用户模式调用的底层服务。例如,NtCreateUserProcess是Windows create process函数调用以创建新进程的内部系统服务。

  • **内核支持函数(或例程)**这些是Windows操作系统中的子例程,只能从内核模式调用(在本章后面定义)。例如,ExAllocatePoolWithTag是设备驱动程序调用以从Windows系统堆(称为池)分配内存的例程。

  • Windows服务这些是由Windows服务控制管理器启动的进程。例如,在支持schtasks命令的用户模式进程中运行的任务计划程序服务。(不包括Windows设备驱动程序)

  • **动态链接库(dll)**这些可调用的子例程作为二进制文件链接在一起,可由使用这些子例程的应用程序动态加载。例子包括Msvcrt.dll(C运行时库)和Kernel32.dll(Windows API子系统库之一)。Windows用户模式组件和应用程序广泛使用dll。与静态库相比,动态链接库的优势在于应用程序可以共享动态链接库,而Windows则确保在引用动态链接库的应用程序中只有一个动态链接库代码的内存副本。请注意,库.NET程序集编译为DLL,但没有任何非托管的导出子例程。相反,CLR解析编译元数据以访问相应的类型和成员。

1.2.3 进程

虽然程序和进程表面上看起来很相似,但本质上是不同的。程序是指令的静态序列,而进程是执行程序实例时使用的一组资源的容器。在最高抽象级别上,Windows进程包含以下内容:

  • 私有虚拟地址空间 :这是进程可以使用的一组虚拟内存地址。
  • 可执行程序:定义初始代码和数据并映射到进程的虚拟地址空间。
  • 打开句柄的列表:将这些句柄映射到各种系统资源,如信号量、同步对象和进程中所有线程都可以访问的文件。
  • 安全上下文这是一个访问令牌,用于标识与进程关联的用户、安全组、权限、属性、声明、功能、用户帐户控制(UAC)虚拟化状态、会话和受限用户帐户状态,以及AppContainer标识符及其相关沙箱信息。
  • 进程ID这是一个唯一的标识符,它是一个称为客户机ID的标识符的内部部分。
  • 至少有一个执行线程:尽管一个“空”进程是可能的,但是很不实用。
实验:查看使用任务管理器进程信息

使用以下方式可以快速开启任务管理器:

  • 使用组合键 Ctrl+Shift+ESC
  • 右键点击进程栏并点击开启任务管理器
  • 点击 Ctrl+Alt+Delete 并点击开启任务管理器按钮
  • 开启可执行程序 Taskmgr.exe

任务管理器截图

详细信息:

在详细信息栏中可以也可以查看进程的信息,右键点击第一行可以选择显示的项目

任务管理器中的关键列:

  • Threads Threads列显示每个进程中的线程数。如果进程显示零线程,则通常意味着由于某些原因无法删除该进程,原因可能是某些错误的驱动程序代码。

  • Handles Handles列显示由进程内运行的线程打开的内核对象的句柄数。

  • Status 对于没有任何用户接口的进程,"正在运行"应该是正常的情况,尽管线程可能都在等待某些东西,例如发出信号的内核对象或某个I/O操作完成。此类进程的另一个选项是挂起,如果进程中的所有线程都处于挂起状态,则会发生这种情况。对于创建用户接口的进程,Running status值表示UI是响应的。换句话说,创建窗口的线程正在等待UI输入。Suspended状态是可能的,就像在非UI情况下一样,但是对于Windows应用程序(那些托管Windows运行时的应用程序),Suspended通常发生在应用程序由于被用户最小化而失去其前景状态时。这样的进程在5秒后暂停,这样它们就不会消耗任何CPU或网络资源,从而允许新的前台应用程序获取所有的计算机资源。不管是哪种方式,用户界面都会冻结,而Windows会通过淡入有问题的窗口并在其标题后附加“(不响应)”来表示这一点。

  • 每个进程还指向其父进程或创建者进程。如果父项不再存在,则不会更新此信息。因此,进程可以引用不存在的父进程。这不是问题,因为没有什么依赖于这些信息保持最新。对于Process Explorer工具,考虑父进程的开始时间,以避免基于重用的进程ID附加子进程。下面的实验演示了此行为。

实验:查看进程树

使用Windows调试工具中的工具Tlist.exe,使用/t 参数显示进程树:

使用Process Explorer.exe也可以查看进程树信息:

使用wmic可以根据PID查看进程的父进程,命令格式如下:

wmic process where ProcessId=PID get ParentProcessId

1.2.4 线程

线程是进程中的一个实体,Windows为其调度执行。没有它,进程的程序就无法运行。线程包括以下基本组件:

  • 表示处理机状态的一组CPU寄存器的内容
  • 两个堆栈一个用于线程在内核模式下执行时使用,另一个用于在用户模式下执行
  • 称为线程本地存储(TLS)的专用存储区域,供子系统、运行时库和DLL使用
  • 唯一标识符线程ID(称为客户机ID的内部结构的一部分;进程ID和线程ID是从同一个命名空间生成的,因此它们永远不会重叠)

此外,线程有时有自己的安全上下文或令牌,这通常由多线程服务器应用程序使用,这些应用程序模拟它们所服务的客户端的安全上下文。

易失性寄存器、堆栈和专用存储区域称为线程的上下文。因为Windows运行的每种计算机体系结构的信息都是不同的,因此这种结构必然是特定于体系结构的。Windows GetThreadContext函数提供对这个体系结构特定信息(称为CONTEXT块)的访问。

因为将执行从一个线程切换到另一个线程涉及到内核调度程序,所以这可能是一个昂贵的操作,特别是当两个线程经常在彼此之间切换时。Windows实现了两种机制来降低成本:Fiber和用户模式调度(UMS)。

Fibers纤程

纤程允许应用程序调度自己的执行线程,而不是依赖于Windows内置的基于优先级的调度机制。纤程通常被称为轻量线程。在调度方面,它们对内核是不可见的,因为它们是在Kernel32.dll中以用户模式实现的。要使用纤程,首先调用Windows ConvertThreadToFiber函数。此函数用于将线程转换为正在运行的纤程。之后,新转换的纤程可以通过CreateFiber函数创建额外的纤程。(每个纤程都可以有自己的一组纤程。)但是,与线程不同的是,在通过调用SwitchToFiber函数手动选择纤程之前,纤程不会开始执行。新纤程将一直运行,直到退出或调用SwitchToFiber,再次选择另一个纤程运行。

用户模式调度线程

用户模式调度(UMS)线程只在64位版本的Windows上可用,它提供了与纤程相同的基本优势,但只有一些缺点。UMS线程有自己的内核线程状态,因此对内核可见,这允许多个UMS线程发出阻塞系统调用并共享和争夺资源。或者,当两个或多个UMS线程需要在用户模式下执行工作时,它们可以在用户模式下周期性地切换执行上下文(通过从一个线程切换到另一个线程),而不是让调度器参与。从内核的角度来看,同一个内核线程仍然在运行,没有任何变化。当UMS线程执行需要进入内核的操作(例如系统调用)时,它将切换到其专用的内核模式线程(称为定向上下文切换)。虽然并发的UMS线程仍然不能在多个处理器上运行,但它们确实遵循一个不完全是协作的抢占模型。

虽然线程有自己的执行上下文,但进程中的每个线程共享进程的虚拟地址空间(除了属于该进程的其余资源外),这意味着进程中的所有线程都具有对进程虚拟地址空间的完全读写访问权。但是,线程不能意外地引用另一个进程的地址空间,除非另一个进程将其私有地址空间的一部分用作共享内存部分(在Windows API中称为文件映射对象),或者除非一个进程有权打开另一个进程以使用跨进程内存函数,例如ReadProcessMemory和WriteProcessMemory(使用相同的用户帐户运行的进程,而不是AppContainer或其他类型的沙盒中运行的进程,默认情况下可以获得这些内存,除非目标进程具有某些保护)。

除了一个私有地址空间和一个或多个线程外,每个进程都有一个安全上下文和一个内核对象(如文件、共享内存段)或某个同步对象(如互斥锁、事件或信号量)的打开句柄列表,如图所示。


每个进程的安全上下文存储在一个称为访问令牌的对象中。进程访问令牌包含进程的安全标识和凭据。默认情况下,线程没有自己的访问令牌,但它们可以获得一个,从而允许单个线程模拟另一个进程(包括远程Windows系统上的进程)的安全上下文,而不会影响进程中的其他线程。

虚拟地址描述符(vad)是内存管理器用来跟踪进程正在使用的虚拟地址的数据结构。这些数据结构将在第5章中进行更深入的描述。

1.2.5 Job

1.2.6 虚拟内存

1.2.7 内核模式与用户模式

    为了防止用户应用程序访问和/或修改关键的操作系统数据,Windows使用两种处理器访问模式:用户模式和内核模式。用户应用程序代码以用户模式运行,而操作系统代码(如系统服务和设备驱动程序)以内核模式运行。

内核模式是指处理器中的一种执行模式,它允许访问所有系统内存和所有CPU指令。一些处理器使用术语代码(term code)特权级别或环级别来区分这些模式,而其他处理器使用诸如管理器模式和应用程序模式之类的术语。不管它被称为什么,通过为操作系统内核提供比用户模式应用程序更高的特权级别,处理器为OS设计者提供了必要的基础,以确保行为不当会破坏整个系统的稳定性。

尽管每个Windows进程都有自己的专用内存空间,但内核模式操作系统和设备驱动程序代码共享一个虚拟地址空间。虚拟内存中的每个页都被标记,以指示处理器必须处于何种访问模式才能读取和/或写入页。系统空间中的页面只能从内核模式访问,而用户地址空间中的所有页面都可以从用户模式和内核模式访问。只读页(例如包含静态数据的页)在任何模式下都是不可写的。此外,在不支持执行内存保护的处理器上,Windows会将包含数据的页标记为不可执行的,从而防止在数据区域中无意或恶意地执行代码(如果启用此功能,则启用数据执行保护[DEP])。

Windows不为内核模式下运行的组件使用的私有读/写系统内存提供任何保护。换句话说,*一旦进入内核模式,操作系统和设备驱动程序代码就可以完全访问系统空间内存,并且可以绕过Windows安全机制来访问对象。*因为大部分的Windows操作系统代码都是在内核模式下运行的,所以在内核模式下运行的组件必须经过仔细的设计和测试,以确保它们不会违反系统安全性或导致系统不稳定。

这种缺乏保护的情况也强调了在加载第三方设备驱动程序时需要保持警惕,尤其是在它没有签名的情况下,因为一旦进入内核模式,驱动程序就可以完全访问所有操作系统数据。这种风险是Windows 2000中引入的驱动程序签名机制的原因之一,该机制在试图添加未签名的即插即用驱动程序时会警告(如果配置为这样,则会阻止)用户,但不会影响其他类型的驱动程序。此外,一种称为驱动程序验证程序的机制可以帮助设备驱动程序编写器发现可能导致安全性或可靠性问题的错误,例如缓冲区溢出或内存泄漏。

在64位和ARM版本的Windows 8.1上,内核模式代码签名(KMCS)策略规定所有设备驱动程序(不仅仅是即插即用)必须使用由主要代码认证机构之一分配的加密密钥进行签名。用户不能显式强制安装未签名的驱动程序,即使作为管理员也是如此。但是可以手动禁用此限制。这允许驱动程序进行自我签名和测试,在桌面墙纸上加上标记为“测试模式”的水印,并禁用某些数字版权管理(DRM)功能。

在Windows10上,微软实施了一项更为重大的改变,作为7月周年更新(1607版)的一部分,从发布一年后开始实施。从那时起,所有新的Windows10驱动程序必须由两个认可的证书颁发机构用SHA-2扩展验证(EV)硬件证书进行签名,而不是常规的基于文件的SHA-1证书及其20个颁发机构。EV签名后,必须通过系统设备(SysDev)门户将硬件驱动程序提交给Microsoft进行证明签名,这将使驱动程序收到Microsoft签名。因此,内核将只签署微软签署的Windows10驱动程序,除了上述的测试模式没有例外。在Windows 10发布日期(2015年7月)之前签名的驱动程序暂时可以继续加载其常规签名。

对于Windows Server 2016,操作系统采取了迄今为止最强大的立场。除上述EV要求外,仅仅签署证明文件是不够的。要将Windows10驱动程序加载到服务器系统上,它必须通过严格的Windows硬件质量实验室(WHQL)认证,作为硬件兼容性工具包(HCK)的一部分,并提交正式评估。只有为系统管理员提供一定兼容性、安全性、性能和稳定性保证的WHQL签名驱动程序才允许加载到这些系统上。总的来说,减少允许在内核模式内存中加载的第三方驱动程序应该能够显著提高稳定性和安全性。

某些供应商、平台,甚至是Windows的企业配置都可以定制任意数量的签名策略,例如通过Device Guard技术。因此,即使在Windows 10客户端系统上,企业也可能需要WHQL签名,或者在Windows Server 2016系统上请求省略此要求。

用户应用程序在进行系统服务调用时从用户模式切换到内核模式。例如,Windows ReadFile函数最终需要调用实际处理从文件读取数据的内部Windows例程。这个例程,因为它访问内部系统数据结构,所以必须在内核模式下运行。使用特殊的处理器指令会触发从用户模式到内核模式的转换,并导致处理器在内核中输入系统服务调度代码。这又会调用中相应的内部函数Ntoskrnl.exe文件或Win32k.sys。在将控制权返回给用户线程之前,处理器模式切换回用户模式。通过这种方式,操作系统保护自己和它的数据不被用户进程阅读和修改。

因此,用户线程的一部分时间在用户模式下执行,一部分时间在内核模式下执行是正常的。事实上,由于大部分图形和窗口系统也在内核模式下运行,图形密集型应用程序在内核模式下的时间比在用户模式下花费的时间要多。测试这一点的一个简单方法是运行一个图形密集型应用程序(如microsoftpaint),并使用表中列出的一个性能计数器观察用户模式和内核模式之间的时间分配。更高级的应用程序可以使用更新的技术,如Direct2D和DirectComposition,它们在用户模式下执行批量计算,并且只将原始表面数据发送到内核。这减少了在用户模式和内核模式之间转换所花费的时间。

实验:内核模式和用户模式

您可以使用性能监视器来查看系统在内核模式下与在用户模式下执行所花费的时间。请执行以下步骤:

1打开“开始”菜单并运行性能监视器(英文版 Performance Monitor)。

2在左侧中的【性能】->【监视工具】下选择【性能监视器】。

3.要删除显示总CPU时间的默认计数器,单击工具栏上的“删除”按钮或按键盘上的SUPR键。

4单击工具栏上的添加(+)按钮。

5.展开Processor计数器部分,单击"%Privileged Time counter",然后,同时按住Ctrl键,单击"% User time",同时选择两个计数器。

6单击“添加”,然后单击“确定”。

7.打开cmd 并键入dir \%127.0.0.1%\c$/s对本机C驱动器运行目录扫描。

8.再次查看性能监视器

此外还可以通过使用【任务管理器】快速看到这结果。只需单击【性能】选项卡,右键单击CPU的图像,然后选择【显示内核时间】。CPU使用率栏将以深蓝色显示内核模式CPU时间使用情况。


要查看性能监视器本身如何使用内核时间和用户时间,请再次运行它,但要为系统中的每个进程添加单独的进程计数器%user time和%Privileged time:

1.再次运行性能监视器。

2.单击工具栏上的“添加”按钮。

3.在“可用计数器”区域中,展开“Process”部分。

4.选择%user time和%Privileged time。

5.在实例框中选择几个进程(例如mmc、csrss和Idle)。

6.单击“添加”,然后单击“确定”。

7.快速来回移动鼠标。

8.按Ctrl+H打开高亮显示模式。这将以黑色突出显示当前选定的计数器。

9.滚动显示底部的计数器,以标识移动鼠标时其线程正在运行的进程,并注意它们是否在user中运行

1.2.8 虚拟机监控程序
1.2.9 固件
1.2.10 终端服务和多个会话
1.2.11 对象和句柄
1.2.12 安全
1.2.13 注册表
1.2.14 Unicode

本文标签: 第七版WindowsinternalsPart