-
-
[原创]Session Manager 的 BootExecute、SetupExecute 与 Execute 多字符串解析
-
发表于: 2026-7-21 19:12 3299
-
本程序的目标是只读记录 Session Manager(会话管理器)的 BootExecute、SetupExecute 与 Execute 配置,并准确说明每一项的类型、原始条目和读取状态。会话管理器是 Windows 在用户登录前启动的系统组件,负责建立早期会话环境。三项值位于 HKLM\System\CurrentControlSet\Control\Session Manager,都应按 REG_MULTI_SZ 处理。REG_MULTI_SZ 是注册表保存多段 UTF-16 文本的值类型,每段文本和整个列表都使用 NUL 终止字符标记边界。
要完成这个目标,分为四步:
这四步连接了注册表配置、Windows API(Windows Application Programming Interface,Windows 应用程序编程接口)和最终记录。注册表键提供配置来源,RegOpenKeyExW 提供可查询的键句柄,RegQueryValueExW 返回类型和字节范围,解析器在该范围内恢复条目,最后输出每项值的状态。
会话管理器子系统(Session Manager Subsystem)在用户登录前参与系统初始化,通常由 smss.exe 承载。BootExecute、SetupExecute 与 Execute 是 Session Manager 键下三份独立的 REG_MULTI_SZ 配置。每份配置都应保留自己的条目顺序、类型、终止状态和读取结果。
枚举程序只读取三项配置。它按返回字节长度验证 REG_MULTI_SZ,然后保留原始条目、空列表、缺失值和双 NUL 终止状态。
这三个值位于用户登录前的启动阶段。Windows 从固件、Windows Boot Manager、内核加载到用户登录之间经过多个阶段。内核完成基本初始化后,会启动会话管理器子系统(Session Manager Subsystem,常由 smss.exe 承载)来建立会话、准备子系统环境并处理早期启动相关配置。
HKLM\System\CurrentControlSet\Control\Session Manager 保存的是会话管理器相关配置。CurrentControlSet 是系统当前使用的控制集别名,系统会将它映射到某个实际的 ControlSet00x。读取时使用 CurrentControlSet 能对应本次启动选择的控制集。仅比较另一个 ControlSet00x 的同名值不能代替当前配置的结果。
这类值出现在早期系统阶段,读取时更应保留原始格式。条目文本可以包含由会话管理器或其调用组件解释的参数,不能直接按普通桌面程序命令行的规则拆成“第一个空格前是路径”。
BootExecute、SetupExecute 与 Execute 要分别记录。BootExecute 常与启动检查阶段相关,常见条目为 autocheck autochk *。SetupExecute 面向安装或设置场景。Execute 是同一配置键下的另一份列表。它们共享父键,但系统不一定在相同条件下处理每一项。
每个值至少有四种读取状态:键不存在或无法打开、值不存在、值存在且为空列表、值存在且包含条目。值存在但类型不是 REG_MULTI_SZ 还应作为类型异常单独报告。把所有“没有条目”的情况合并为一个空字符串,会丢失配置和读取失败之间的重要区别。
多字符串不是普通字符串。REG_MULTI_SZ 的数据由多段 UTF-16 文本串接而成。每段以单个 NUL 结束,列表以额外 NUL 结束。条目顺序就是 API 返回缓冲区中的顺序,应按原顺序输出。
每个 \0 代表一个 UTF-16 NUL 宽字符而非字面反斜杠和零。RegQueryValueExW 的长度参数仍以字节为单位,因此程序先用字节数分配缓冲区,再通过 字节数 / sizeof(wchar_t) 得到可检查的字符数量。读取长度为奇数、缺少双 NUL 或在第二次查询中扩容的情况都应保留为格式或读取状态。
配置值与实际执行需要分开。注册表中出现 BootExecute 条目,只证明读取时配置包含该文本。条目是否在某次启动中被处理、具体工具是否运行成功、是否因为磁盘状态或安装阶段被跳过,需要启动日志、事件记录或独立运行时证据。
读取程序可以安全地报告:完整键路径、值名、类型、条目顺序、原始长度、是否观察到双 NUL 和 API 返回码。它不应仅凭某个词出现在条目内就断言系统已经执行过相应程序。
下方 API 使用几个基础对象。HKEY 是已打开注册表键的句柄,不是路径字符串,也不是键内容。RegOpenKeyExW 成功后产生它,调用方负责用 RegCloseKey 归还系统资源。KEY_QUERY_VALUE 是只读查询值的访问权限,请求它不允许修改配置。
DWORD 是 32 位无符号整数类型。注册表 API 中保存长度的 DWORD 可能表示两种单位:名称长度通常是 UTF-16 宽字符个数,原始值数据长度通常是字节数。BYTE 是一个字节。wchar_t 在 Windows 上通常承载一个 UTF-16 代码单元。将字节数直接当作字符数会造成缓冲区过大或过小。
NUL 是数值为零的终止字符。C 和 Win32 的许多宽字符串 API 依靠 NUL 找到文本结尾。REG_MULTI_SZ 则把 NUL 同时用作条目分隔符和列表终止符。因此解析该类型时必须以 API 返回长度为边界,不能只调用寻找第一个 NUL 的字符串函数。
三个值共享同一个父键。BootExecute 用于启动检查阶段,SetupExecute 用于安装与设置阶段,Execute 是另一份会话管理器命令列表。同一父键不代表三项配置具有相同状态。
打开键时只申请查询权限。成功返回的 HKEY 是系统资源,读取结束后必须关闭。
正确读取时为每个值保留独立结果。父键存在而 Execute 未设置时,BootExecute 和 SetupExecute 仍应照常输出。
完成第一步(定位父键并区分三项配置)后,已经取得只读查询所需的 HKEY,也明确了每次查询对应的值名。键句柄只能说明查询入口有效,尚未提供值的内容。下一步需要让注册表 API 返回每项数据的类型和准确字节范围。
注册表查询函数的长度参数单位是字节。先传入空数据指针取得长度,再按该长度读取原始数据。第二次读取遇到 ERROR_MORE_DATA 时需要扩大缓冲区并有限重试。
正确的两次读取保留 API 返回的类型和实际字节数。REG_MULTI_SZ 只有在字节数能被 sizeof(wchar_t) 整除时才按 UTF-16 解析。
完成第二步(按返回字节数读取原始数据)后,已经获得类型与限定长度的字节缓冲区。此时缓冲区仍只是原始数据,直接当作普通字符串会丢失后续条目,或在终止字符缺失时越出返回范围。下一步需要确认它确实符合 UTF-16 多字符串的边界规则,再恢复原有顺序。
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。