前言
近期开始阅读《Windows Internals》这本书,现在已经出到第七版了,相比于第六版来讲增加了Win10的部分知识,但是由于翻译版本较少,且未出完整版的书籍,笔者啃原版书效率也比较低,暂时决定先看看翻译第六版即《深入解析Windows操作系统》,继续加深一下基础,书中有大量的可动手操作的部分,相当不错,后面记录一下阅读的部分记录,虽然极有可能是马了不看系列,但是还是写写,希望能加深下自己的印象。
Windows操作系统的版本
产品名称 | 内部版本号 | 发布日期 |
---|---|---|
Windows NT 3.1 | 3.1 | 1993.07 |
Windows NT 3.5 | 3.5 | 1994.09 |
Windows NT 3.51 | 3.51 | 1995.05 |
Windows NT 4.0 | 4.0 | 1996.07 |
Windows 2000 | 5.0 | 1999.12 |
Windows XP | 5.1 | 2001.08 |
Windows Server 2003 | 5.2 | 2003.03 |
Windows Vista | 6.0(编译版本6000) | 2007.01 |
Windows Server 2008 | 6.0(编译版本6001) | 2008.03 |
Windows 7 | 6.1(编译版本7600) | 2009.10 |
Windows Server 2008 R2 | 6.1(编译版本7600) | 2009.10 |
tips: Windows7 的7并非指版本号,而是指家族的世代编号。为使兼容问题尽可能的小,其真实版本应该为6.1。
Windows API分类
- 基本服务
- 组件服务
- 用户界面服务
- 图形和多媒体服务
- 消息和协作
- 网络
- Web服务
程序和进程
程序是一个静态的指令序列。
进程是一个容器,包含了执行程序的特定实例时所需的各种资源。
从最高层次的抽象来看,Windows进程由已下元素组成:
- 私有的虚拟地址空间,这是指该进程可以使用的一组虚拟内存地址。
- 可执行的程序,它定义了初始的代码和数据,并且被映射到该进程的虚拟地址空间中。
- 已打开句柄的列表,这些举办指向各种系统资源,比如信号量、通信端口和文件,该进程内所有的线程都可以访问这些系统资源。
- 被称为访问令牌的安全环境,它标识了与该进程关联的用户、安全组、特权、UAC(User Account Control,用户账户控制)虚拟化状态、绘画,以及有限的用户账户状态。
- 被称为进程ID的唯一标识符(在内部,进程ID还是标识符客户ID的一部分)。
- 至少一个线程执行(尽管“空”进程也是有可能的,但是没有用处)。
任务管理器
“应用程序”选项卡类除了子啊当前链接的交互窗口站中所有桌面上的顶级可见窗口(在默认情况下没只有一个交互桌面——可以利用Windows的CreateDesktop函数创建更多的桌面对象)。“状态(status)”列表明创库所属的线程是否处于WIndows消息等待状态。“正在运行(Running)”表示该线程正在等待窗口输入;“未响应(Not Responding)”表示该线程并不在等待窗口输入。
工具:Process Explorer
此工具可显示更多进程和线程信息的细节:
- 显示进程安全令牌
- 加亮显示进程和线程列表中的变化。
- 列出服务宿主进程中的服务,包括显示名称和说明。
- 显示加入到作业(job)中的进程,以及作业的细节。
- 显示运行.NET应用的进程,以及与.NET相关的细节。
- 显示进程线程的启动时间。
- 显示内存映射文件的完整列表。
- 能够挂起进程或线程。
- 能够杀死单个线程。
- 识别一段时间某个进程小号了大量的CPU时间。
在一个地方访问到各种信息:
- 进程树
- 进程内已打开句柄
- 进程内的DLL(和内存映射文件)列表。
- 进程内的线程活动。
- 用户模式和内核模式的线程栈。
- 利用线程的指令计数计量更为精确的CPU百分比
- 完整性级别(intergrity level).
- 内存管理器的细节(提交内存量峰值、内核内存中换页和非换页的内存池限制)
线程
线程是一个进程内部的实体,Windows执行次进程时的调度实体。包括下面一些基本部件:
- 一组代表处理器状态的CPU寄存器中的内容。
- 两个栈(Kernel & User)
- 线程句柄存储(TLS,Thread-Local Storage)的私有存处区域,各个子系统、运行库和DLL都会用到该存储区域。
- 一个被称为线程ID的唯一标识符。
- 有事也存在自己的安全环境,或者Token。(易失的寄存器、栈和私有存储区 合起来被称为环境)。
纤程和用户模式调度
纤程(fiber):使得一个应用程序可以调度他自己的“线程”的执行过程,而不必依赖于Windows内置的基于优先级的调度机制。
用户模式调度(UMS,User-Mode Scheduling)仅在64位Windows上可用,它基本提供了与纤程同样的作用。
不同的时,前者对内核是不可见的,因为他们是在用户模式下Kernel32.dll中实现的。而猴儿由他们自己的内核线程状态,因此对于内核是可见的,使得多个UMS纤程都可以发出阻塞的系统调用、对资源进行共享或竞争。
访问令牌(Access Token)
进程的一个安全环境,存储在访问令牌对象,对象中包含该进程的安全标识和凭证。
虚拟地址描述符(VAD,Virtual Address Descriptor)
一些数据结构,内存管理器用来记录进程正在使用的虚拟地址。
作业(job)
进程模型的扩展,主要功能是,是一组进程被当作一个整体来管理和维护。通过作业对象,对特定的属性进行控制,也可对一个进程或所有与作业相关联的进程进行限制。
虚拟内存
Windows实现了一个基于线性地空间的虚拟内存系统,使每个进程感觉用一个很大的私有地址空间。
虚拟内存提供一个内存逻辑试图,可能并不对应于内存的物理格局。运行时,内存管理器借助于硬件的支持,将虚拟地址转译或者映射成真正存放数据的物理地址。
操作系统通过这一机制,确保进程不会互相影响,更不会去改动操作系统的数据。
大多数系统拥有的物理内存,比当前正在运行的进程所用到的虚拟内存总量要小得多,因此,内存管理器会将内存中的有些内容转移或换页(page)到磁盘上。这样之后,就可以释放出这部分物理内存,可以被别的进程使用,或用于操作系统自身。
当线程访问一个已经交换到磁盘的虚拟内存时,虚拟内存管理器会见磁盘的信息装回内存。
32位x86系统中,总的虚拟地址空间有一个理论上的最大值4GB。默认情况低2G(0x00000000-0x7fffffff)分配个进程,作为私有存储空间;高2G(0x80000000-0xffffffff)用作其自己的被保护的操作系统内存。
两种虚拟地址空间布局结构
用户模式和内核模式
为避免用户应用程序访问和/或修改关键的操作系统数据,Windows使用了两种处理器访问模式(用户模式和内核模式)
用户程序代码运行在用户模式下,而操作系统代码(比如系统服务和设备驱动程序)运行在内核模式下。
内核模式是指这样一种处理器执行模式:它允许访问所有的系统内存和所有的CPU指令。通过让操作系统软件比应用软件有更高的特权级,处理器为操作系统设计者提供了一层必要的保护,可以确保行为不正常的应用程序不会破坏系统整体的稳定性。
1 | 注 x86和x64处理器架构定义了4中特权级,或者称为4个环(ring),来保护系统代码和数据不会被低级别的代码恶意地或无意地改写。 |
终端服务及多个会话
终端服务是指在单个系统中,Windows对于多个可交互用户会话的支持。
利用Windows的终端服务,一个远程用户可以在另一台机器上建立一个会话,并且登录进去,在该服务器上运行应用程序。服务器把图形用户界面传送到客户机,客户机把用过户的输入传回服务器。(Windows 允许在一个服务器系统上运行单独的应用程序,其显示部分远程传送到客户机,而非将整个桌面远程到而客户机)。
第一个会话被叫做服务会话,或者零号会话,它包含了寄纳系统服务的进程。在机器的物理控制台上的第一个登陆会话为一号会话,而其他的会话可以通过远程桌面连接程序(Mstsc.exe)来建立,或者通过快速用户切换来建立。(Win+L)
对象和句柄
在Windows操作系统中,内核对象是指某个静态的定义的对象类型的单个运行时实例。
对象类型由系统定义的数据类型、在该数据类型的实例上进行操作的一组函数、以及一组对象属性构成。
对象属性是对象中的数据域,每个对象属性定义了对象的一部分状态。(eg: 进程ID、基本调度优先级和指向访问令牌对象的指针)
对象方法,即操作对象的手段,通常用与读取或者改变对象的属性。(eg:进程的open函数接受一个进程标识符作为输入,返回一个指向该进程对象的指针作为输出)
对象与普通数据结构的区别是:
对象内部结构是不透明的。必须调用一个对象服务才可获取对象内部的数据,或者把数据放到对象内部。不能直接读取或者改变一个对象内部的数据。这使得对象的底层实现和那些仅仅使用该对象的代码区别开来,此技术使得对象的实现可以随着时间而容易地改变。
而通过WIndows的对象管理器,操作WIndows中的对象,来实现四个重要的操作系统任务:
- 为系统资源提供和可供人读的名称。
- 在进程之间共享资源和数据。
- 保护资源,避免未授权的访问。
- 引用跟踪,这使得系统能够知道一个对象何时不再有用,从而可以被自动释放。
安全性
Windows的核心安全包括:针对所有可共享系统对象(比如:文件、目录、进程、线程,等等)的自主保护(need-to-know)和强制完整性保护,安全审计(针对主体或者用户和他们发起的动作的记录),登录时的用户认证,以及禁止用户通过访问未初始化资源的做法来访问其他用户已释放的资源(比如空闲内存和磁盘空间)。
WIndows的三种对对象访问控制形式。
第一种是自主访问控制,由对象(比如文件或者打印机)的所有者授权或者拒绝其他人访问这些对象。
第二种是特权访问控制,此方法确保:即使对象的所有者当前无法联系到,也有人可以访问被保护的对象。例如,如果一个员工离开了公司,则管理员必须有办法访问那些本该只有该员工才可以访问的文件。
第三种是强制完整性控制。它既被用于将Internet Explorer的保护模式与用户的配置隔离开,也被用于保护那些由提升了特权的管理员所创建的对象,避免被未提升特权的管理员账户所访问。
Windows子系统实现了基于对象的安全性,其方式与操作系统的做法相同;Windows子系统在共享的Windows对象上设置了Windwos安全描述符,防止它们遭到非法访问。当应用程序第一次试图访问某个共享对象时,Windows子系统将验证该应用程序是否有权这样做。如果安全检查通过,则Windows子系统允许该应用程序继续执行。
注册表
注册表是系统数据库,它包含了引导和配置系统所必须的信息、全系统范围内控制Windows操作的软件设置、安全数据库,以及针对每个用户的配置设置。
同时它也是一个反映内存易失数据的窗口,比如系统当前的硬件状态以及Windows的性能计数器。
Unicode
Windows区别于大多数操作系统的一个方面是它内部大多数文本串是以16位等宽度的Unicode字符来存储和处理的。
用于查看Windows内部机制的工具
工具 | 映像名 | 来源 |
---|---|---|
Access Check | ACCESSCHK | Sysinternals |
Dependency walker | DEPENDS | www.dependencywalker.com |
Global Flags | GFLAGS | Windows调试工具 |
Handle Viewr | HANDLE | Sysinternals |
Kernel debuggers | WINDBG,.KD | Windows调试工具,WindowsSDK |
Object Viewer | WINOBJ | Sysinternals |
性能监视器(performance monitor) | PERFMON.MSC | Windows 内置工具 |
Pool monitor | POOLMON | Windows Driver Kit |
Process Explorer | PROCEXP | Sysinternals |
Process Monitor | PROCMON | Sysinternals |
Task(Process) List | TLIST | Windows调试工具 |
任务管理器(Task Manager) | TASKMGR | Windows 内置工具 |
性能监视器
三项功能:系统监视、查看性能计数日志,以及设置报警。为简化起见,我们在提到性能监视器时,实际指的是该工具内部的系统监视功能。
性能监视器所提供的有关操作系统当前运行状况的信息,比其他单个工具所能提供的信息都要多得多。他针对各种各样的对象提供了数百个基本的和扩展的计数器。
Windows还包含了一个使用工具——资源监视器,它可以显示四种主要的系统资源:CPU、磁盘、网络和内存。
- CPU选项卡显示了有关每个进程CPU使用率的信息,可以清楚的知道哪写进程最为活跃。还包含了一个单独的关于Windows服务机器关联的CPU使用率和平均CPU使用率的显示区,如同Process Explorer一样,选择某个进程将显示出该进程所打开的有名称句柄和列表,以及被加载到该进程地址空间中的模块的列表。
- 内存部分显示了与任务管理器同样多的信息,但它针对了整个系统进行了组织。物理内存条状图将当前的物理内存,按照“为硬件保留的的内存”、“正在使用”、“已修改”、“备用”、“可用”进行组织。
- 磁盘显示了基于每个文件的I/O信息,这样可以很容易的识别出当前系统中那些文件被访问的最多、被写得最多,或者被读得最多。
- 网络部分显示了活动的网络连接、哪写进程拥有这些连接,以及这些连接上传了多少数据。
内核调试
内核调试意味着检查内核的内部数据结构,以及/或者跟踪内核中的函数。
内核调试符号
符号文件包含了函数和变量的名称,以及数据结构的布局和格式。它们是由链接器产生的,在调试会话中被调试器用来引用和显示这些名称,这些名称通常并不存储在二进制映像文件中,因为执行代码的时候并不需要用到它们。
Windows调试工具
用户模式的调试
这些调试工具可以被用于负载到一个用户模式进程上,然后检查或改变进程的内存。在附载到进程上时有以下两种选择:
- 侵入式的 除非另行制定,否则在调试器附载到一个正在运行的进程上时,将通过Windows函数DebugActiveProcess,在调试器和被调试的程序之间建立一个连接。这使得可以检查或改变该进程的内存,设置断点,执行其他的调试功能。
- 非侵入式的 这种选择方式下,调试器只是简单的利用OpenProcess函数打开被调试的进程。它并不作为一个调试器附载到目标进程上。尽管可以检查或改变目标进程中的内存,但是不能设置断点。
有两个调试器可用于内核调试:命令行版本(Kd.exe)和图形用户界面(GUI)版本(Windbg.exe)。这两个版本提供了同样的命令集,多以,应该喧嚣而哪一个,完全取决于习惯和爱好。这些工具可以执行以下三种类型的调试:
- 打开崩溃转储文件。Windows系统崩溃时会产生这样的文件。
- 连接到正在运行的系统上,并检查该系统的状态;或者,如果正在调试设备驱动程序的代码,则可以设置断点。这种操作要求有两台计算机——目标计算机和控制主机。目标计算机是要调的目标系统,控制主机是指运行调试器的主机。目标系统可以通过零调试解调线(null modern cable)、IEEE 1394线或者USB2.0调试线连接至控制主机。目标系统必须按调试模式引导。也可以通过命名管道来建立连接,当通过虚拟机产品,不如Hyper-V、Virtual PC或VMware,来进行调试时,这是非常有用的。此时客户(guest)操作系统的串口被暴漏为一个命名管道设备。
- Windows系统也允许连接到本地系统上,然后检查系统的状态。这称为本地内核调试。