window学习笔记(待整理)

在看一个视频,感觉还不错,打算整理一下笔记,视频地址: 深入研究windows内部原理
笔记先丢这,随着学习慢慢整理,等有了时间再慢慢调整格式补充内容。
深入研究windows内部原理

关键系统文件

  • Ntoskrnl.exe 执行体和内核
    • 执行体功能
      • 进程和线程管理器
      • 虚拟内存管理器
      • 安全引用监视器
      • I/O管理器
      • 即插即用管理器
      • 电源管理器
      • 缓存管理器
      • 其他服务组件
    • 内核功能
      • 供其他组件使用的底层原语
      • 线程调度
      • 中断处理
      • 多处理器同步
    • 以dll的方式输出函数给hal和其他内核模块
  • Ntoskrnlpa.exe 支持PAE的执行体和内核
  • Hal.dll 硬件抽象层 对硬件平台的细节进行了抽象, 包括I/O接口,中断控制器等,使得NT可以在各种硬件环境下保持可移植性
  • Windows子系统
    • 环境子系统csrss.exe (Client\Server Runtime Server Subsystem)
      • WINSRV.dll控制台窗口
      • SCRSRV.dll创建或者删除进程或线程以及调试
      • BASESRV.dll 安全,登陆
      • 对16位虚拟DOS机的支持
    • 内核模式驱动程序Win32k.sys
      • 窗口管理器
        • 控制窗口显示
        • 管理屏幕输出
        • 收集输入设备的输入
        • 将用户消息传递给应用程序
      • 图形设备接口GDI
        • 针对图形输出设备的函数库
    • 子系统DLL
      • Kernel32.dll
      • Advapi.dll
      • User32.dll
      • Gdi32.dll
    • 图形设备驱动程序
      • 硬件相关的图形显示器驱动程序
      • 打印机驱动程序
      • 视频微端口驱动程序
  • Ntdll.dll 内部支持函数和执行体函数的存根函数
    • 将用户模式的请求转义为内核模式的服务

I/O管理器

I/O管理器实际为传递IRP(I/O请求包)的一个框架
IRP控制了所有I/O操作的处理过程,其中快速I/O不使用IRP
+ I/O管理器
+ 为每一个I/O操作创建一个IRP
+ 将IRP传递给正确的驱动程序
+ 当I/O操作完成时删除IRP
+ 驱动程序
+ 向I/O管理器登记必要的信息
+ 接受IRP
+ 执行IRP指定的操作
+ 把IRP传回给I/O管理器,或者通过I/O管理器传递给另一个驱动程序以便进一步处理

常用工具

  • TaskManager 查看进程和线程

  • Performance Monitor 对系统所有资源的访问进行记录

  • Regedit 查看注册表

  • Netmon 查看网络结构

  • Dependency Walker from VS 查看dll依赖

  • spy++ from VS 查看窗口消息和进程线程(杀弹窗很好用)

  • windbg

  • Filemon 文件监视软件

  • Regmon 注册表监视程序

  • Process Explorer 增强型任务管理器

windows体系结构

操作系统角度

X86的工作模式

实模式

实地址模式,段地址+ 偏移=物理地址

保护模式

现代cpu的native模式,多任务和虚拟地址支持

  • 用户程序不可以执行特权指令
  • 用户程序不可以直接访问I/O端口和硬件寄存器
  • 高特权级代码可以执行和访问低特权级别代码和数据,低特权级不能直接访问搞特权级的代码和数据
  • 正在执行的代码所在的代码段的特权级别就是该代码的特权级别
段式内存管理

逻辑地址logical address = selector+offset 其中,selector是cs寄存器的值,offset为eip寄存器的值。
如果selector去GDT表里(全局描述符表)拿到segment base address (段基址)然后加上offset(段内偏移),这就得到了linear address 。
整个过程叫做段式内存管理。
(仅限于在intel32下,因为64-bit long mode 下分段被直接禁用了)

页式内存管理

把linear address 切成四段,用前三段分别索引去PGD、PMD、Page Table里查表,最终会得到一个页表项(Page Table Entry),那里面的值就是一页物理内存的起始地址。
把该值加上linear address 切分后的第四段的内容(又叫业内偏移),就得到最终的physical address 。
整个过程叫做页式内存管理

virtual address和linear address实际上是同一个东西.

CR3寄存器

用来存放当前页目录表的物理基地址的寄存器,简称PDBR(Page Directory Base Register)
切换任务时,系统会将包括CR3在内的上下文信息保存起来.
切换CR3意味着切换地址空间.
不同的进程拥有不同的CR3内容.

系统管理模式

系统固件(BIOS)执行电源管理、安全检查或者平台相关的特定任务

Session

每个会话有自己的桌面\输入设备和显示输出设备

系统服务运行在一个session中
本地登录使用,运行在另一个session中.
远程登录使用,运行在第三个session中.

中断和异常

中断源于CPU外,异常源于CPU内

IDT(Interrupt Descriptor Table)中断向量表

应用程序的角度

进程

进程是一个程序的实例,是一个静态的概念。
进程本身不会运行,是线程的容器。

组成部分
  • 一个核心态的对象,操作系统用来保存进程的信息
  • 地址空间,包含可执行文件和所有动态链接库的代码和数据,以及动态分配的内存。
进程的终止

进程终止之后,Windows会释放掉进程所使用的所有资源,包括内存和句柄等。
进程终止的方式:
+ 主线程的入口函数返回
+ 进程主动退出:一个线程调用了exitprocess
+ 进程被动退出,一个其他进程调用了terminateprocess
+ 进程中所有线程都终止。

进程的虚拟地址空间
  • 32位系统上,进程的虚拟地址为4GB
  • 默认状态下,用户态和核心态虚拟地址空间各占2GB
  • 各个进程的用户态地址空间是相互独立的。
  • 各个进程的核心态地址空间是相互共享的。

线程

创建于一个进程的上下文中,在进程的地址空间中运行。
线程是动态的,一个进程至少要有一个线程。
进程中所有线程共享进程的地址空间。

组成部分
  • 一个核心态的对象,操作系统用来保存线程信息。
  • 线程堆栈,用于存放线程运行时的函数参数以及局部变量等。
线程的运行
  • 当进程初始化时,系统会创建这个进程的主线程。
线程的终止
  • 线程函数返回
  • 线程调用exitthread
  • 其他线程调用terminalthread
  • 该线程所在的进程终止。
context switch
  • 保存当前线程的上下文(context)
  • 把当前线程放在同一优先级的线程队列最后。
  • 找到最高优先级的ready线程
  • 把它从所在的线程队列中移出,装载它的上下文,开始执行该线程。
线程上下文的内容
  • instruction pointer(EIP)
  • 用户和核心态堆栈指针
  • 指向这个线程所在的地址空间的指针(page table directory)

动态链接库

DLL不能直接运行,必须装载到一个进程中。

进程装载DLL,触发dll_process_attach
进程卸载dll,触发dll_process_detach
dll装载后创建新线程dll_thread_attach
dll装载后一个线程被终止dll_thread_detach

DLL搜索顺序

HKLM\System\CurrentControlSet\Control\Session Manager \SafeDllSearchMode决定dll搜索顺序
safe的搜索顺序:

  1. 可执行文件所在目录
  2. 系统目录%systemroot%system32
  3. 16位系统目录
  4. windows目录%systemroot%
  5. 进程的当前目录
  6. 环境变量Path的目录

HEKY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager \KnownDLLs 保证装载系统dll时只在指定目录下装载

异常处理

HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug指定默认异常的调试程序。

windows sysinternals工具集的介绍

进程信息查看

Process Explorer
Process Monitor

安全信息查看

PsExec

网络信息查看

TCPView

磁盘和文件

PageDefrag

用户账户控制

两种访问令牌

SID组

标准权限运行的进程,管理员组SID标记为Deny。
提升权限运行的进程,包含管理员账户SID

特权

标准权限运行的进程,只有5个特权。
提升权限运行的进程,包括23个特权。

虚拟重定向

进程隔离

强制完整性级别控制(MIC)
UI特权隔离(UIPI)

默认禁止低级别进程向高级别进程发送Windows消息。

Windows启动过程

参与启动过程的软硬件
  • ROM中POST(Power On Self-Test)代码
  • BIOS/EFI(Extended Firmware Interface)
  • MBR(Main Boot Record)
  • 引导扇区(Boot sector)
  • NTLDR /WinLoad
  • NTOSKRNL/HAL/BOOTVID/KDCON
  • SMSS.exe
  • CSRSS.exe
  • WINLogon.exe
启动过程
  1. CPU复位
EFI
  1. EFI
  2. BootMgr
  3. WinLoad
MBR
  1. 传统Bios

  2. MBR -> 引导扇区

  3. NTLDR

  4. NTOS

  5. SMSS

  6. CSRSS

  7. WINLogon

重要文件
NTLDR

系统加载器,windows系统的加载程序,位于windows系统的根目录。
工作过程:
1. 使CPU从16位的实模式进入到32位的保护模式。
2. 启用CPU页机制。
3. 如果是SCSI硬盘,则加载BtBootDD.sys用于访问磁盘,否则使用int 13
4. 如果发现有效的hiberfil.sys,则加载并恢复Hibernate
5. 打开boot.ini文件,读取其中的设置,如果有多个选项,则显示菜单。
6. 如果用户按过F8,则显示相应选项。
7. 加载并执行,ntdetect.com,调用BIOS收集系统的基本信息(时间,总线类型,磁盘,输入设备,端口,显卡等)并保存到注册表中HKLM\Hardware\Description
8. 显示启动进度条(win2k)或者启动splash
9. 加载系统目录(\system32)下的ntoskrnl.exe和hal.dll以及它所依赖的模块。
10. 加载注册表的SytemHive,并加载其中定义的boot类型(service_boot_start(0))的驱动程序。
11. 执行ntoskrnl.exe的入口函数。

Ntoskrnl

windows 内核和执行体的PE(Portable Executable)映像文件。
内容:
1. 内核
2. 执行体
3. 以dll的方式输出函数给hal和其他内核模块
4. 内核服务的实现
5. 系统初始化和启动
1. 分两个阶段初始化OS内核
2. I/O管理器启动boot类型的驱动,然后启动system_start类型的驱动程序
3. 创建SMSS.exe进程

  1. KeStartAllProcessors函数
    1. 对于每个CPU.
    1. 设置其GPT(Global Descriptor Table)、IDT(Interrupt Descriptor Table)、TSS(Task State Segment)
    2. 分配用于处理Double Fault异常的TSS和栈
    3. 分配用于处理NMI中断(不可屏蔽中断)的TSS和栈
    4. 分配DPC栈(延迟过程调用)
    5. 将ProcessorState的ContextFrame结构的EIP字段指向KiSystemStartup函数。
    6. 调用KilnitializePcr()初始化PCR(Process Control Region)和PRCB(Process Control Block)
    7. 调用HalStartNextProcessor()

  2. KiSystemStartup

    1. 递增全局变量KeNumberProcessors
    2. HalInitializeProcessor()
    3. 执行KdInitSystem()初始化内核调试引擎。
    4. 调用KiInitialzeKernel()初始化内核数据结构,创建IDLE线程(即当前线程),启动初始化执行体。
    5. 将IRQL降到DISPATCH_LEVEL,然后跳转到KildleLoop(),退化到Idle进程。
  3. KiInitialzeKernel

    1. 如果是bootstrap的cpu(0号),则初始化公共的数据结构,并调用KiInitSystem()
    2. 调用KeInitializeThread()初始化Idle进程。
    3. 调用ExpInitializeExecutive(),以初始化执行体,只有启动CPU做真正的所谓Phase 0初始化工作。
  4. 初始化执行体两个阶段

    1. 阶段0
      1. 由KilnitializeKernel函数调用ExpInitializeExecutive而发起
      2. 在初始的单线程环境中执行各个执行体的Phase 0 初始化
    2. 阶段1
      1. 在系统进程的初始线程(Phase1Initialization)中执行。
      2. 创建多个线程,但是大多数只有初始线程工作。
  5. ExpInitializeExecutive 调用执行体的各个组件的Phase 0 初始化函数。

    1. 内存管理器 - 构建页表和内部数据结构。
    2. 对象管理器 - ObInitSystem ,建立命名空间。
    3. 安全- SeInitSystem, 初始化token模型。
    4. 进程管理器 - PsInitSystem(0,LoaderParaBlock)
      1. 定义进程和线程对象类型。
      2. 建立用于记录活动进程和线程的链表结构(PsActiveProcessHead,此后!process 0 0命令才能工作)
      3. 为初始的进程建立一个进程对象(PsIdleProcess),并命名为Idle;
      4. 创建系统进程(全局变量PsInitialSystemProcess)和线程,起始地址指向Phase1Initialization函数。
      5. PnP管理器 - 初始化executive类型的资源,用于同步。
  6. Phase1 Initialization(0~5%)

    1. HalInitSystem()
      • HalpInitReservedPages
      • HalpInitNonBusHandler
      • HalpGetFeatureBits
      • HalpEnableIniterruptHandler
    2. InbvEnableBootDriver
    3. InbvDriverInitialize
    4. InbvEnableDisplayString(0) 禁止输出字符
    5. DisplayBootBitmap 显示微软logo
    6. PoInitSystem
    7. Hal!HalQueryRealTimeClock
    8. KeSetSystemTime
    9. PoNotifySystemTimeSet
    10. nt!InbvUpdateProgressBar(5) 更新启动进度条
  7. Phase1 Initialization(5~10%)

    1. ObInitSystem
    2. ExInitSystem
    3. KeInitSystem
    4. KdInitSystem
    5. SeInitSystem
    6. InbvUpdateProgressBar(0xa)
      此时系统进程内有两个进程,另一个为InbvRotateGuiBootDisplay,用于显示启动logo
  8. Phase1 Initialization(10~15%)

    1. MmInitSystem(1,PsInitSystem(0,LoaderParaBlock,x) 创建Section对象和内存管理的系统工作线程。
    2. CcInitializeCacheManager 初始化文件系统缓存数据结构和工作线程。
    3. CmInitSystem1 配置管理器(Configuration Manager) 创建\Registry对象
    4. CcPfInitializePrefetcher Prefetch 初始化
    5. InbvUpdateProgressBar(0xf)
      此时系统内已经创建了很多线程,但是除了Phase1Initialization线程外,其他线程大多数都处于排队(WrQueue)等待状态,因为Phase1Initialization线程的优先级被设置为31
  9. Phase1 Initialization(15~20%)

    1. ExpRefreshTimeZoneInformation
    2. FsRtlInitSystem 文件系统初始化
    3. KdDebuggerInitialize1
    4. PpInitSystem -> Pnp管理器初始化,即即插即用管理器
    5. InbvUpdateProgressBar(0x14)
  10. Phase1 Initialization(20~25%)

    1. LpcInitSystem -> Local Procedure Call子系统初始化LPC端口对象类型。
    2. 如果启用了boot logging, 则创建日志,位置在\Ntbtlog.txt
    3. InbvUpdateProgressBar(0x19)
  11. Phase1 Initialization(25~75%)

    1. I/O管理器初始化并枚举设备加载设备驱动
    2. 系统启动过程中最复杂,占用时间最多,也经常出问题的一个阶段。
    3. lolnitSystem
  12. Phase1 Initialization(75~80%)

    1. MmInitSystem(2,LoaderParaBlock) 释放启动过程中所使用的内存。如果是以安全模式启动,则此信息写入注册表
    2. InbvUpdateProgressBar(0x50)
  13. Phase1 Initialization(80~85%)

    1. Kel386VdmInitialize Dos虚拟机初始化
    2. KiLogMcaErrors 检查和记录MCA(Machine Check Architecture)
    3. PoInitSystem(1) 电源管理器阶段1初始化
    4. PsInitSystem(1,LoaderParaBlock) 进程管理器阶段1初始化,调用PsInitializeSystemDll初始化系统DLL,即NTDLL.DLL,将其映射到用户空间(PspMapSystemDll)
    5. InbvUpdateProgressBar(0x55)
  14. Phase1 Initialization(85~90%)

    1. MmFreeLoaderBlock 加载即将结束,释放加载参数块(LOADER_PARAMETER_BLOCK结构)
    2. SeRmInitPhase1 Security Referenc Monitor阶段1初始化,创建用于与LSASS进程通信的Command Server Thread线程。
    3. InbvUpdateProgressBar(0x5a)
  15. Phase1 Initialization(90~100%)

    1. RtlCreateUserProcess 创建SMSS进程
    2. FinalizeBootLogo
    3. ZwResumeThread
    4. InbvUpdateProgressBar(0x64)
    5. InbvEnableDisplayString(1)
    6. ZwWaitForSingleOject 等待5分钟,如果5分钟内SMSS进程退出,则蓝屏终止系统
    7. 此后该线程转变为zero page用途
  16. Session Manager Subsystem 第一个用户态进程,是执行体在初始化的最后一步创建的。

    1. 执行BootExecute表键中定义的程序
    2. 执行PendingFileRenameOperations表键中定义的延迟改名操作
    3. 初始化Paging file 和未完成的注册表初始化
    4. 加载和初始化Win32子系统的内核模块Win32K.sys
    5. 创建Win32子系统服务器进程,CSRSS
    6. 创建WinLogon进程
  17. WINLogon

    1. 启动LSASS(Local Scurity Authority Subsystem Service)进程 。
    2. (WinXp)启动LogonUI进程。
    3. 加载GINA模块,(缺省为MSGINA.dll),显示登录对话框(视情况)
    4. 启动Services.exe,启动系统服务
  18. 登录过程

    1. WinLogon(GINA DLL)将用户名和密码发给LSASS
    2. LSASS调用验证模块对用户名和密码进行验证,如果通过,则创建一个访问令牌对象。
    3. WinLogon启动,HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon的Userinit表键下指定的程序(缺省为userinit.exe)
    4. UserInit进程执行登录和初始化脚本,然后启动Shell表键中定义的Shell程序。
    5. UserInit 完成工作后退出。
  • boot.ini 启动配置文件,现在已经转移至注册表
  • hiberfil.sys 休眠模式下内存内容保存位置
  • io.sys
  • msdos.sys
  • ntdetect.com
  • pagefile.sys虚拟内存交换文件

内存管理揭秘

内存管理理论

  • 内存是现代计算机系统操作的核心
  • 内存是由大量的“字节”组成
  • CPU从内存中读取指令和数据
  • 不同的指令可能造成额外的内存读写操作
地址绑定
  • 地址在程序中以符号的形式存在
  • 编译器将符号绑定到可重定位的内存地址
  • 链接器将可重定位的内存地址绑定到绝对地址

逻辑和物理内存

  • 逻辑地址由CPU产生

  • Memory Unit 负责逻辑地址到物理地址的转换

  • 运行时地址绑定

    • 逻辑地址和物理地址不一致
    • 逻辑地址被称为虚拟地址
    • 实时的地址映射由硬件MMU完成
  • 内存管理的核心任务就是管理虚拟内存和物理内存的对应关系。

交换

  • 一个多任务环境
  • 进程可以被交换到存储介质上以便其他程序运行
  • 对于物理地址:
    进程将被交换到相同的位置
  • 对于逻辑地址
    进程将被交换到固定的物理地址

分页

  • 程序运行时,它的Page将被加载到任何可用的Frame中。
  • 硬件通过PageTable 支持分页
  • 逻辑地址记录页号和它的偏移值

内存管理功能和组件

  • 传统虚拟内存管理
    • 连续的寻址空间
    • 每个进程拥有独立的寻址空间
    • 全局系统地址空间
    • 每个会话的寻址空间
  • 基于对象的
    • 如ACLs
  • 即时内存管理
    • 页面在需要的时候读入和写出
  • 连续的虚拟寻址空间
    • 32-bit:4GB
    • 64-bit:16 Exabytes
内存管理组件
  • 系统服务分配和管理内存
  • 6个系统线程
    • Working set manager(priority 16) 决定所有内存管理的策略
    • Process/Stack swapper(priority 23) 实现所有进程和核心态线程的堆栈的交换
    • Modified page writer(priority 17) 把脏的page记录到页面文件的列表中去,该列表保存了所有修改的页面。
    • Mapper page writer(priority 17) 把已经写过的内存的page从映射文件写入磁盘
    • Dereference segment thread (priority 18)
    • zero page thread (priority 0) 把不用的页面清零

tip

  • NT其实是new technology的缩写

未完待续。。。。。(格式啥的以后再说)

牛逼牛逼,虽然看不懂 /滑稽


服务器资源由ZeptoVM赞助

Partners Wiki IRC