MM 学习笔记 08:Section 段对象与文件映射

📅 2026/7/24 23:14:45
MM 学习笔记 08:Section 段对象与文件映射
MM 学习笔记 08Section 段对象与文件映射文件ntoskrnl/mm/ARM3/section.c~3500 行日期2026-07-191. 概述Section 对象是 Windows 内存管理的核心抽象之一实现文件与虚拟内存之间的映射。它允许进程将文件内容映射到其地址空间或创建共享内存区域。// 核心函数入口NtCreateSection → 创建 Section 对象系统调用 NtMapViewOfSection → 将 Section 映射到进程地址空间系统调用 MmCreateArm3Section → 内部创建例程ARM3 实现 MmCreateSection → 内部创建通过函数指针调用 MmCreateArm3Section三种映射类型类型后端存储创建函数典型用途数据文件映射磁盘文件MiCreateDataFileMap文件 I/O、共享内存分页文件映射系统页面文件MiCreatePagingFileMap匿名共享内存、进程间通信映像映射PE 文件exe/dllMiCreateDataFileMap 映像标志程序加载2. 三层数据结构Section 对象通过三个层次的数据结构来管理映射关系SECTION (对象体) │ ▼ CONTROL_AREA (控制区) ← 管理文件引用和整体状态 │ ├──→ FILE_OBJECT (文件对象指针) │ ▼ SEGMENT (段) ← 管理物理内存的描述 │ ▼ 原型 PTE (数组) ← 每个页面一个原型 PTE │ ▼ 物理页面 (PFN 数据库)2.1 SECTION// section.c 中定义的 Section 对象体typedefstruct_SECTION{MM_SECTION_SEGMENT Segment;// 段指针LARGE_INTEGER SizeOfSection;// 段大小ULONG InitialPageProtection;// 初始页面保护union{ULONG LongFlags;struct{// 各种标志位}Flags;}u;ULONG ControlAreaLock;// 控制区锁...}SECTION,*PSECTION;2.2 CONTROL_AREA控制区是 Section 对象的头部管理文件对象引用和映射状态typedefstruct_CONTROL_AREA{PVOID Segment;// 指向 SEGMENTunion{ULONG_PTR LongFlags;struct{// 标志位BeingCreated, BeingDeleted, Image, File, Rom 等}Flags;}u;PVOID FilePointer;// 指向 FILE_OBJECT文件映射ULONG WritableUserReferences;// 可写用户引用计数LIST_ENTRY DereferenceList;// 解除引用列表...}CONTROL_AREA,*PCONTROL_AREA;2.3 SUBSECTION子段描述映射中的连续区域typedefstruct_MSUBSECTION{PMMPTE SubsectionBase;// 原型 PTE 基地址ULONG_PTR PtesInSubsection;// 子段中的 PTE 数量ULONG ProtectionMask;// 保护掩码ULONG StartingSector;// 文件中的起始扇区ULONG NumberOfFullSectors;// 完整扇区数}MSUBSECTION,*PSUBSECTION;2.4 SEGMENT 与原型 PTESEGMENT 包含指向原型 PTE 数组的指针。每个原型 PTE 描述 Section 中的一个页面SEGMENT ├── SizeOfSegment ← 段大小 ├── NonExtendedPtes ← PTE 数量 ├── TotalNumberOfPtes ├── SegmentFlags ├── ControlArea ← 反向指针 └── (紧跟原型 PTE 数组) 原型 PTE (Prototype PTE): ┌─────────────────────────────────┐ │ 有效位 0 (Invalid) │ │ 原型位 1 (Prototype TRUE) │ │ 转换位 0 或 1 │ │ 页面帧号/页文件偏移 │ └─────────────────────────────────┘原型 PTE 的作用映射共享页面的主副本当进程映射 Section 时其私有 PTE 指向原型 PTE写时复制COW时原型 PTE 标记为只读3. 三种映射类型的区别3.1 数据文件映射// 调用路径MmCreateArm3Section →MiCreateDataFileMap(NewSegment,...)→ 设置 File 标志 → 初始化控制区 → 创建段和原型 PTE后端存储是磁盘文件页面在缺页时从文件读取修改的页面回写到文件ControlArea-FilePointer指向文件对象3.2 分页文件映射// 调用路径MmCreateArm3Section →MiCreatePagingFileMap(NewSegment,MaximumSize,...)→ 设置 PageFile 标志 → 从系统页面文件分配空间 → 创建段和原型 PTE标记为页文件支持后端存储是系统页面文件pagefile.sys没有关联的文件对象适用于匿名共享内存ControlArea-FilePointer为 NULL3.3 映像映射用于加载 PE 映像exe/dll设置Image标志不从文件读取数据而是从映像的内存副本当前 ARM3 实现中尚未完全支持有ASSERT检查4. NtCreateSection 创建流程NTSTATUS NTAPINtCreateSection(OUT PHANDLE SectionHandle,IN ACCESS_MASK DesiredAccess,IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,IN PLARGE_INTEGER MaximumSize OPTIONAL,IN ULONG SectionPageProtection OPTIONAL,IN ULONG AllocationAttributes,IN HANDLE FileHandle OPTIONAL)位置section.c:3083创建流程图NtCreateSection │ ├─ 1. 参数验证 │ ├─ 检查 AllocationAttributes 合法性 │ ├─ 必须包含 SEC_COMMIT | SEC_RESERVE | SEC_IMAGE 之一 │ ├─ SEC_IMAGE 不能与其他属性组合 │ └─ 检查保护属性 │ ├─ 2. 安全捕获用户参数 │ ├─ ProbeForReadLargeInteger(MaximumSize) │ └─ ProbeForWriteHandle(SectionHandle) │ ├─ 3. 参数一致性检查 │ └─ 无文件句柄时必须指定 MaximumSize │ └─ 4. 调用 MmCreateSection └─ 通过 MmCreateSection 函数指针 → MmCreateArm3Section MmCreateArm3Section (section.c:2105) │ ├─ 5. 保护掩码转换 │ └─ ProtectionMask MiMakeProtectionMask(SectionPageProtection) │ ├─ 6. 文件路径有文件句柄 │ │ │ ├─ 引用文件对象 │ ├─ 检查 SectionObjectPointer │ ├─ 分配 CONTROL_AREA SUBSECTION │ ├─ 调用 MiCreateDataFileMap 创建映射 │ │ → 设置 ControlArea-u.Flags.File 1 │ └─ 设置 SizeOfSection │ └─ 7. 分页文件路径无文件句柄 │ ├─ 调用 MiCreatePagingFileMap │ → 分配段和原型 PTE │ → 从页文件分配空间 └─ 设置 SizeOfSection5. NtMapViewOfSection 映射流程NTSTATUS NTAPINtMapViewOfSection(_In_ HANDLE SectionHandle,_In_ HANDLE ProcessHandle,_Outptr_result_bytebuffer_(*ViewSize)PVOID*BaseAddress,_In_ ULONG_PTR ZeroBits,_In_ SIZE_T CommitSize,_Inout_opt_ PLARGE_INTEGER SectionOffset,_Inout_ PSIZE_T ViewSize,_In_range_(ViewShare,ViewUnmap)SECTION_INHERIT InheritDisposition,_In_ ULONG AllocationType,_In_ ULONG Win32Protect)位置section.c:3264映射流程图NtMapViewOfSection │ ├─ 1. 参数验证 │ ├─ InheritDisposition 范围检查 │ ├─ AllocationType 检查 │ └─ 保护掩码转换 MiMakeProtectionMask │ ├─ 2. 安全捕获用户参数 │ ├─ ProbeForWritePointer(BaseAddress) │ ├─ ProbeForWriteSize_t(ViewSize) │ └─ 捕获 SectionOffset │ ├─ 3. 地址范围检查 │ └─ BaseAddress 必须在用户空间范围 │ ├─ 4. 引用对象 │ ├─ ObReferenceObjectByHandle(ProcessHandle) │ └─ ObReferenceObjectByHandle(SectionHandle) │ └─ 5. 调用 MmMapViewOfSection └─ → 内部映射逻辑 ├─ 创建 VAD虚拟地址描述符 ├─ 建立进程 PTE → 原型 PTE 的映射 └─ 处理继承和共享6. MmCreateArm3Section 内部核心逻辑位置section.c:2105这是 ARM3 中 Section 创建的真正核心函数。主要参数MmCreateArm3Section(OUT PVOID*SectionObject,// 返回 Section 对象IN ACCESS_MASK DesiredAccess,// 访问权限IN POBJECT_ATTRIBUTES ObjectAttributes,IN PLARGE_INTEGER InputMaximumSize,// 最大大小IN ULONG SectionPageProtection,// 页面保护IN ULONG AllocationAttributes,// 分配属性IN HANDLE FileHandle,// 文件句柄可选IN PFILE_OBJECT FileObject)// 文件对象可选内部流程1. 验证分配属性 ├─ SEC_COMMIT | SEC_RESERVE | SEC_IMAGE 不能同时设置 ├─ 无效的组合如 SEC_IMAGE SEC_NOCACHE被拒绝 └─ 保护属性不能包含 PAGE_NOCACHE / PAGE_GUARD / PAGE_NOACCESS 2. 转换保护掩码 └─ ProtectionMask MiMakeProtectionMask(SectionPageProtection) 3. 文件映射路径 (FileHandle ! NULL) ├─ ObReferenceObjectByHandle → 获取 FILE_OBJECT ├─ 检查 FileObject-SectionObjectPointer ├─ 分配 CONTROL_AREA sizeof(MSUBSECTION) ├─ 零初始化 ├─ 获取文件锁 FsRtlAcquireToCreateMappedSection ├─ MiCreateDataFileMap(Segment, ...) │ ├─ 设置 BeingCreated TRUE │ ├─ Segment-ControlArea ControlArea │ └─ ControlArea-Segment Segment ├─ 设置 Section.SizeOfSection └─ 清理文件锁 4. 分页文件映射路径 (FileHandle NULL) ├─ MiCreatePagingFileMap(NewSegment, ...) │ ├─ 计算段大小 │ ├─ 分配 CONTROL_AREA SEGMENT │ ├─ 创建原型 PTE 数组 │ └─ 页文件槽位分配 └─ ControlArea NewSegment-ControlArea 5. 构建 SECTION 对象体 ├─ Section.InitialPageProtection SectionPageProtection ├─ Section.Segment NewSegment ├─ Section.u.LongFlags ControlArea-u.LongFlags ├─ 设置 UserWritable 标志如果需要 └─ 分配配额7. MiSegmentDelete 段删除位置section.c:593VOID NTAPIMiSegmentDelete(IN PSEGMENT Segment){PCONTROL_AREA ControlArea;SEGMENT_FLAGS SegmentFlags;PSUBSECTION Subsection;PMMPTE PointerPte,LastPte,PteForProto;...删除流程图MiSegmentDelete │ ├─ 1. 验证状态 │ └─ ControlArea-BeingDeleted 1 │ ControlArea-WritableUserReferences 0 │ ├─ 2. 获取原型 PTE 范围 │ └─ Subsection (PSUBSECTION)(ControlArea 1) │ PointerPte Subsection-SubsectionBase │ LastPte PointerPte Segment-NonExtendedPtes │ ├─ 3. 锁定 PFN 数据库 │ ├─ 4. 遍历所有原型 PTE │ │ │ ├─ 处理 PDE 边界检查主 PTE 是否有效 │ │ │ ├─ 处理转换 PTETransition PTE │ │ └─ 页面在备用/已修改列表中 → 释放页面 │ │ │ ├─ 处理页文件 PTE │ │ └─ MmFreeSwapPage → 释放页文件槽位 │ │ │ └─ 清零原型 PTE │ ├─ 5. 释放段使用的系统 PTE │ ├─ 6. 释放控制区中的文件引用 │ └─ ObDereferenceObject(FileObject) │ └─ 7. 释放 CONTROL_AREA 和 SEGMENT 内存8. 系统空间映射8.1 MmMapViewInSystemSpace系统空间视图用于内核组件如文件系统缓存、驱动程序映射 Section// MiInsertInSystemSpace 管理系统空间视图MiInsertInSystemSpace(IN PMMSESSION Session,IN ULONG Buckets,IN PCONTROL_AREA ControlArea){// 1. 锁定系统空间// 2. 在位图中分配桶// 3. 插入哈希视图表// 4. 返回虚拟地址}系统空间视图管理MiInitializeSystemSpaceMap(IN PMMSESSION InputSession OPTIONAL){// 1. 初始化视图锁// 2. 初始化位图描述系统空间// 3. 分配视图哈希表// 4. 清零所有位}8.2 Session 空间Session 空间位于0xA0000000 - 0xC0000000x86 32位由 Session 子系统管理// session.cViewStartMiSessionViewStart;// Session 视图起始SizeMmSessionViewSize;// Session 视图大小9. MiLocateSubsection 反向定位给定一个虚拟地址反向查找所属的子段PSUBSECTION NTAPIMiLocateSubsection(IN PCONTROL_AREA ControlArea,IN ULONG_PTR Offset){PSUBSECTION Subsection;ULONG_PTR PteIndex;// 计算 PTE 索引PteIndexOffsetPAGE_SHIFT;// 遍历子段Subsection(PSUBSECTION)(ControlArea1);while(PteIndexSubsection-PtesInSubsection){PteIndex-Subsection-PtesInSubsection;Subsection(PSUBSECTION)((PMMPTE)SubsectionSubsection-PtesInSubsection);}returnSubsection;}10. MiMakeProtectionMask 保护掩码转换位置section.c:140将 Win32 API 的保护标志PAGE_READONLY、PAGE_READWRITE等转换为 MM 内部使用的保护掩码。ULONG NTAPIMiMakeProtectionMask(IN ULONG Protect){ULONG Mask1,Mask2,ProtectMask;// 最大有效值是 PAGE_EXECUTE_WRITECOMBINEif(Protect(PAGE_WRITECOMBINE*2))returnMM_INVALID_PROTECTION;// Win32 保护掩码由两个4位字段组成// 通过是否包含执行权限来区分Mask1Protect0xF;// 低4位Mask2(Protect4)0xF;// 高4位// 根据字段存在性查表if(!Mask1){ProtectMaskMmUserProtectionToMask2[Mask2];// 执行权限}else{ProtectMaskMmUserProtectionToMask1[Mask1];// 无执行权限}// 检查 PAGE_GUARDif(ProtectPAGE_GUARD){if((ProtectMaskMM_NOACCESS)||(Protect(PAGE_NOCACHE|PAGE_WRITECOMBINE)))returnMM_INVALID_PROTECTION;ProtectMask|MM_GUARDPAGE;}// 检查 PAGE_NOCACHEif(ProtectPAGE_NOCACHE)ProtectMask|MM_NOCACHE;// 检查 PAGE_WRITECOMBINEif(ProtectPAGE_WRITECOMBINE)ProtectMask|MM_NOACCESS;// 注意这里设置 NOACCESS 而不是 WRITECOMBINEreturnProtectMask;}保护掩码转换表// 无执行权限版本CHAR MmUserProtectionToMask1[16]{MM_NOACCESS,MM_READONLY,MM_INVALID_PROTECTION,MM_READWRITE,MM_INVALID_PROTECTION,MM_INVALID_PROTECTION,MM_INVALID_PROTECTION,MM_WRITECOPY,...};// 有执行权限版本CHAR MmUserProtectionToMask2[16]{MM_EXECUTE,MM_EXECUTE_READ,MM_INVALID_PROTECTION,MM_EXECUTE_READWRITE,MM_INVALID_PROTECTION,MM_INVALID_PROTECTION,MM_INVALID_PROTECTION,MM_EXECUTE_WRITECOPY,...};兼容性检查ULONG MmCompatibleProtectionMask[8]{PAGE_NOACCESS,PAGE_NOACCESS|PAGE_READONLY|PAGE_WRITECOPY,PAGE_NOACCESS|PAGE_EXECUTE,// ... 每种保护类型兼容的映射};11. 整体架构图┌──────────────────────┐ │ NtCreateSection │ │ NtMapViewOfSection │ └──────────┬───────────┘ │ ▼ ┌──────────────────────────────┐ │ SECTION 对象体 │ │ ┌────────────────────────┐ │ │ │ SEGMENT (段) │ │ │ │ ├── SizeOfSegment │ │ │ │ ├── SegmentFlags │ │ │ │ └── ControlArea │──┼──┐ │ └────────────────────────┘ │ │ └──────────────────────────────┘ │ │ ┌────────────────────────────┐ │ │ CONTROL_AREA (控制区) │◄───┘ │ ├── u.Flags (类型标志) │ │ ├── FilePointer (文件) │ │ ├── Segment (段指针) │──┐ │ └── (后面紧跟 SUBSECTION) │ │ └────────────────────────────┘ │ │ ┌────────────────────────────┐ │ ┌────►│ 原型 PTE 数组 │◄───┘ │ │ PTE[0] → 页面 0 │ │ │ PTE[1] → 页面 1 │ │ │ ... │ │ │ PTE[N] → 页面 N │ │ └───────────┬────────────────┘ │ │ │ ▼ │ ┌──────────────────────┐ │ │ 物理页面 (PFN) │ │ │ 或 页文件槽位 │ │ └──────────────────────┘ │ │ 进程 A 进程 B │ ┌─────────────────┐ ┌─────────────────┐ │ │ VAD (视图) │ │ VAD (视图) │ │ │ PTE → 原型 PTE │ │ PTE → 原型 PTE │ │ └─────────────────┘ └─────────────────┘ │ │ │ └─────────┴────────────────────────┘ │ │ ▼ ▼ ┌──────────────────────────────────┐ │ 原型 PTE (共享副本) │ │ Valid0, Prototype1 │ │ 写时复制 (COW) 机制 │ └──────────────────────────────────┘参考链接[section.c — ARM3 Section 实现](file:///d:/reactos/ntoskrnl/mm/ARM3/section.c)[miarm.h — 核心数据结构定义](file:///d:/reactos/ntoskrnl/mm/ARM3/miarm.h)[Windows Internals 7th Part 1, Section “Sections and Views”]