首页
社区
课程
招聘
[原创]分析Windows Section Object机制
发表于: 6天前 333

[原创]分析Windows Section Object机制

6天前
333

先导内容:

这里写得较为详细,也有些混乱,主要供以后我遇到相关问题时查阅使用。

Section Object,它是一个系统级的、独立于任何进程的对象,代表了一段可以被多个进程共享的物理存储资源。这个资源可以是内存(由页文件pagefile.sys支持),也可以是磁盘上的文件(如.exe、.dll或数据文件)。通过节对象,多个进程可以映射同一份数据到各自的地址空间,实现内存共享或文件的内存映射。

我们可以使用Process Explorer来查看某个进程的节对象句柄:

图片描述

这是三个对于理解Section Object工作原理与应用的重要概念:

Address就是该section object映射的进程地址空间对应的VAD节点。

Segment是真正描述section object数据的对象。

引自潘爱民老师的《Windows内核原理与实现》:

图片描述

用户态 (Win32 API):

内核态 (内核API):

下面我们通过一个示例程序来更详细地了解section object的工作机制:

图片描述

首先我们调用CreateFileMappingW创建了一个Section Object。这里拿到的HANDLE的值是0xE8。那么我们来看看其对应的Section内核对象。首先拿到进程的基本信息:

图片描述

拿到Cid,就可以使用!handle命令取得句柄对应的内核对象信息了:

图片描述

可以看到HandleCount为1,说明有一个进程引用了这个Section Object,自然就是我们的示例程序了:

图片描述

下面分析这个Section Object对象的结构。

于是我们拿到了Section Object地址:ffff808652d39d30。我们查看其结构:

图片描述

在输出中,可以看到这个节对象被挂载到了一颗AVL树上,Windows系统使用一颗AVL树来管理所有Section Object。

由于我们在CreatFileMappingW中传递了INVALID_HANDLE_VALUE,使用了系统分页文件作为物理存储,那么其StartingVpn和EndingVpn就都为0。

还可以看到该Section Object大小为4KB,我们在CreatFileMappingW中填写的是1024,但是最小也是以页大小为单位创建Section Object。还可以看到页保护属性字段正是我们在CreateFileMappingW中填写的PAGE_READWRITE:

图片描述

_SECTION中的u1联合体中是CONTROL_AREA,当然也有是FileObject的情况(以磁盘文件作为物理存储时):

图片描述

我们查看CONTROL_AREA:

图片描述

_CONTROL_AREA 是连接 _SECTION(逻辑对象)与 _SEGMENT(物理/页文件存储)的桥梁。它不关心映射到哪个进程的哪个地址,只关心“这块内存的物理存储状态”和“当前有多少人在用”。

注意到 +0x008 处同时显示了 ListHeadAweContext

这是 _CONTROL_AREA 中的一个联合体(Union)

这个结构不关心有多少人在看这块内存(MappedViews),也不关心是谁在看。它只负责一件事:管理这块虚拟内存实际占用的物理存储资源(物理内存页或分页文件槽位)

对于NumberOfCommittedPages = 0PrototypePte

我们的进程是映射了这个Section Object对应的物理存储到虚拟地址空间的,从VAD中可以看到:

图片描述

我们查看这个VAD节点的详细信息:

图片描述

可以看到其中_MMVAD中和Section Object相关的字段,和我们通过_SECTION结构获取的对应字段,值是一致的。

具体如何通过__MMVAD解析得到Section Object这里就演示了。

我们开始调试这个程序。

图片描述)

反汇编CreateFileMappingW,它只是把用户态参数格式转换为内核态参数格式,然后调用NtCreateSection:

从这里准备进入内核态。

这里进行了0x4A号系统调用,我们查找SSDT表基址为:

图片描述

根据索引号计算在SSDT表中的偏移,右移四位后加上SSDT基址,得到0x4A对应的函数地址:

图片描述

偏移为0x087a0003,右移4位加上SSDT基址得到:

图片描述

那么我们开始分析nt!NtCreateSection函数:

图片描述

注意 a10 = 1(倒数第二个参数):这个标志表示"来自NtCreateSection系统调用"还是"来自其他入口"——它影响 MiCaptureSectionCreateExtendedParameters 中的权限检查和 MiCreateSectionCommon 中是否获取进程令牌。

接下来分析MiCreateSectionCommon

首席是AllocationAttributes 合法性检查(大量位掩码,非法即返回 STATUS_INVALID_PARAMETER_6 = 0xC00000F4

这些是 SEC_* 标志的有效组合校验(例如 SEC_RESERVE 和 SEC_COMMIT 冲突等)。

然后是用户/内核模式敏感的指针捕获:

这是 Nt 函数的标志性行为:由于参数来自用户态,必须在异常捕获下安全读取指针。

接着捕获扩展参数 + 获取令牌/会话

这里解释了为什么需要 a10=1 标志:该标志决定是否引用进程主令牌——文件映射需要以进程令牌做后续的文件访问权限检查。

然后调用 MiCreateSection + 重试循环

重试循环处理文件映射创建时遇到的瞬态条件(如文件正在被锁定/删除中)。

最后成功后处理 + 句柄创建(NtCreateSection 的收尾):

CcZeroEndOfLastPage 值得注意:它把映射文件最后一页末尾的未使用字节清零,防止映射视图泄漏文件中未初始化的数据(信息泄露防护)。

在NtCreateSectionEx中,调用了MiCreateSection,这个函数的分派逻辑如下:

我们的示例代码中创建的文件映射对应的物理存储是页交换文件,所以调用的是MiCreatePagingFileMap。注意到MiCreateSection中调用了MiLogSectionObjectEvent,这里会触发ETW,我们可以使用ETW检测Section Object的创建。

注意,这是从用户态创建Section Object的调用链分析。如果使用了MmCreateSection这个内核态API,它会调用MmCreateSectionEx,然后也会调用MiCreatePagingFileMap或者MiCreateImageOrDataSection。

对于MmCreateSection,潘爱民老师的《Windows内核原理与实现》中做了详细分析。不过要注意的是,现代Windows内核中MmCreateSection相关实现与WRK中给出的源代码略有不同,应该要

那么对于创建section object的分析就到这里,如果继续再深入分析的话,我的水平还不够,这里浅尝辄止。

下面分析MapViewOfFile,也就是映射这一步的流程。

首先调用了MapViewOfFile:

图片描述

也是对参数进行一些准备后,调用了NtMapViewOfSection:

图片描述

由此准备进入内核,可以看到系统调用号是0x28。

总体调用链:


冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。

收藏
免费 0
打赏
分享
最新回复 (0)
游客
登录 | 注册 方可回帖
返回