架构图
- Windows绝大部分代码用C语言编写的,少部分使用C++编写的,只有那些需要直接与系统硬件打交道的部分、或者对性能极端敏感的部分,才使用汇编编写的
- 应用程序代码运行在用户模式下(Ring 3),操作系统代码运行在内核模式下(Ring 0),处理器在硬件一级保证高优先级别的数据和代码不会被低优先级的代码破坏。一旦用户空间代码访问内核空间数据,处理器会产生保护性异常(#GP)。用户态程序通过系统调用从用户态模式切换到内核态,从而间接访问内核空间中的数据、间接执行内核空间中的代码。见后面Ntdll.dll笔记。
- 内核模式下运行的代码共享内核模式地址空间,一旦进入内核模式,操作系统和设备驱动程序的代码可以完全访问系统空间的内存,也可以绕过Windows的安全机制直接访问对象。由于缺少保护,在加载第三方设备驱动程序的时候更需要加倍小心。为此,Windows实现了一些内核保护机制,如PatchGuard和内核模式代码签名。
内核空间
从职能角度来看,内核空间主要包含以下部件。- Windows执行体(Executive)包含了基本的操作系统服务,包括内存管理、进程管理、线程管理、输入输出(I/O)、网络和跨进程通信
- Windows内核由一组低层次的操作系统功能构成的,负责线程调度、中断处理、异常分发、多处理同步等关键人物,是操作系统最核心的部分
- 内核态设备驱动程序,我理解是对应架构图中的File and Device Drivers
- Windows子系统驱动程序(WIN32K.SYS),包括USER和GDI两大部分。USER部分负责窗口管理、用户输入等,GDI(图形设备接口)负责显示输出和各种图形操作。
- 硬件抽象层(HAL,Hardware Abstraction Layer)是指一层特殊的代码,它主要用来隔离平台相关的硬件差异性(比如不同主板的差异),使内核和顶层模块可以通过统一的方式来访问硬件
- 内核支持模块,对于架构图中的KDCOM.DLL、BOOTVID.DLL、CI.DLL、CLFS.SYS、PSHED.DLL
内核文件和HAL文件
从文件角度来看,内核与执行体都位于一个文件中,即通常所说的NT内核文件。NT内核文件有几种版本,它们是使用同一套源码通过不同编译选项而编译出来的。安装程序在安装时会根据处理器的个数,选择对应的文件拷贝到system32目录,并改名为单处理器版本的名字;对于32位Windows,还要在Windows系统启动过程中,根据是否启用PAE来加载对应的文件。System和IDLE进程
- 没有对应的可执行映像文件,是在系统启动时“捏造”出来的
- 只在内核态执行,没有运行在用户态空间的部分
- IDLE进程ID是0,它是IDLE线程的宿主,IDLE线程的个数与系统中启用的处理器个数是一致的。当CPU空闲时,就会执行IDLE线程。
- system进程ID是4,它是系统内核和大多数系统线程的宿主,例如内存管理器使用系统线程来实现诸如“将脏页面写到页面文件或者映射文件中”、“将进程在内存中换进/换出子类的功能”
高级本地过程调用(ALPC)
典型情况下出于移植性的考虑,可以使用文件、命名管道、套接字等UNIX机制来完成进程通信。而在Windows内部实现了一种称为高级本地过程调用的内部IPC机制,被广泛应用于Windows的各个部分,第三方开发人员无法使用。- 基于ncalrpc的RPC,用于在同一个系统上的进程之间进行通信。
- Windows子系统中与CSRSS进程通信、所有的子系统与SMSS进程通信,都通过ALPC
- Winlogon使用ALPC与LSASS进行通信
- 安全引用监视器使用ALPC与LSASS通信
用户空间
Smss.exe
Wininit.exe
服务控制管理器Services.exe
见https://www.yuque.com/u21376397/hacknotes/kvsm08 ### 本地安全认证子系统服务器Lsass.exe ### 本地会话管理器Lsm.exe
Userinit.exe
一旦获取到了用户名和凭证,Winlogon将它们发送到LSASS进程认证,如果认证通过LSASS会返回一个访问令牌。然后Winlogon利用此访问令牌创建该用户会话的初始进程,默认是Userinit.exe(HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon)。 Userinit执行用户环境的一些初始化工作(比如运行登录脚本、应用组策略),然后在注册表中查找Shell值,创建一个进程来运行系统定义的shell程序,默认是Explorer.exe,然后Userinit退出。Windows子系统
为了能够在Windows操作系统上运行其他类型的软件,Windows设计了不同的环境子系统。每个可执行映像都被绑定到一个且唯一的子系统上,映像文件运行时,负责创建进程的代码会检查该映像头部的子系统类型代码,所以它可以通知正确的子系统,有新的进程被创建。 子系统是由会话管理器Smss.exe进程启动起来的,子系统列表见:计算机\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems。- POSIX子系统,也称SUA子系统,用于运行符合POSIX标准的程序,Windows XP开始去除了此子系统
- OS/2子系统,用于支持16位的OS/2程序,Windows XP开始去除了此子系统
- Windows子系统,即支持Windows程序运行的子系统
Windows子系统
Windows子系统由以下组件构成:- 每个会话有一个环境子系统服务进程Csrss.exe: - 创建或删除进程和线程,进程、线程的创建和删除都需要报告给环境子系统才能继续操作 - 对16位DOS虚拟机(VDM)进程的部分支持(仅32位Windows)
- Windows为系统中的每个控制台窗口使用了一个单独的进程:控制台窗口宿主进程Conhost.exe
- 子系统DLL提供已经文档化的Windows API函数,最后转译为Ntoskrnl.exe和Win32k.sys中恰当的且绝大多数未文档化的内核模式系统服调用
- 内核模式设备驱动程序Win32k.sys,窗口管理USER(包括屏幕输出、用户输入和消息传递)和GDI(图形设备接口)
- 图形设备驱动程序,与硬件相关的图形显示器驱动、打印机驱动程序和视频微端口驱动程序。应用程序调用标准的USER函数在显示器上创建用户界面控件,比如窗口和按钮。窗口管理器将这些请求发送给GDI,GDI又将它们传递给图形设备驱动程序;在设备驱动程序内部,这些请求被格式化以适合特定的显示器设备。
Ntdll.dll
用户态API与内核态API的沟通桥梁,系统会在启动阶段便把它加载到内存中,并把它映射到所有用户进程的进程空间中,而且是映射到相同的虚拟地址中。它包含两种类型的函数:- 系统服务分发存根 stub,它们会调用Windows执行体的系统服务
- 内部支持函数,如程序映像加载(Ldr开头的函数)、运行时函数(Rtl开头的函数)、异常分发例程和调试支持例程
- 使用INT2E切换到内核模式
- 使用快速系统调用切换到内核模式
使用远程API来避免检测