-
-
[原创]Credential Provider、Filter 与 PLAP 的 CLSID 枚举
-
发表于: 19小时前 326
-
程序的目标是只读取注册表,列出 Credential Provider、Credential Provider Filter 与 PLAP Provider 的 CLSID、默认名称和 COM 服务器注册位置。它不创建 Provider,也不触发登录或身份验证。
要想得到这份登记信息,分为四步:
Credential Provider、Credential Provider Filter 与 PLAP Provider 都以 CLSID 子键登记在 Authentication 注册表树中。登录界面枚举候选 Provider,Filter 决定场景可见性,PLAP 支持登录前访问准备。COM Classes 注册再提供 DLL 或 EXE 服务器位置。
第一步决定读取范围,避免把 32 位和 64 位注册数据混为一组。第二步取得每条登记记录的原始事实。第三步筛掉不能作为 COM 类标识使用的文本,并让每条记录保留来源。第四步才根据有效 CLSID 查找可能的实现位置。静态注册记录不能证明组件会显示、激活或成功完成身份验证。
登录界面与身份验证系统有不同分工。Windows 登录界面由 LogonUI 等组件承载,它向 Credential Provider 查询可用的凭据方案。Provider 可以提供用户名密码、智能卡、Windows Hello 等不同类型的凭据磁贴,并将收集到的数据按系统约定序列化后交给后续身份验证流程。
Provider 是 COM 组件。登录界面从 Credential Providers 注册表根读取 CLSID,再根据 CLSID 在 Classes 注册中定位 COM 服务器并创建对象。CLSID 表示类身份,默认值通常只是显示名称。真正的实现位置来自 InprocServer32 或 LocalServer32 等 COM 注册子键。
枚举到一个 Provider CLSID 只证明它被登记为候选组件。是否会在当前登录场景显示、是否通过筛选、是否创建成功以及用户是否提交凭据,分别取决于系统策略、会话类型和运行时调用结果。
三类根键的职责需要分别解释。Credential Provider 负责提供具体凭据和磁贴。Credential Provider Filter 参与判断哪些 Provider 在某个使用场景中可见或可用。PLAP(Pre-Logon Access Provider)面向用户登录前的网络或访问准备场景。三种类型可使用相同的 COM 基础设施,接口职责和触发场景不同。
相同 CLSID 出现在多个根键时,应生成多条带类型标签的记录。只按 CLSID 去重会丢失“它作为 Provider、Filter 还是 PLAP 被登记”的语义。
使用场景决定登录界面请求哪些能力。登录、解锁、凭据 UI 和远程连接等场景需要的凭据交互不同。登录界面将场景信息交给 Provider 和 Filter,由组件决定是否支持该场景以及要显示什么字段。
这意味着注册表检查无法单独回答“用户会看到哪个磁贴”。静态配置能够给出已注册的 CLSID、默认名称和 COM 服务器文本。策略、Filter 返回结果、设备状态、用户状态与当前登录场景共同决定实际可见集合。
CLSID、默认名称和服务器位置要保留各自含义。Provider 子键名是 CLSID。子键默认值可提供名称或说明。COM Classes 根下的 InprocServer32 或 LocalServer32 默认值提供服务器注册文本。它们位于不同注册表树,不能用一个字符串字段覆盖。
HKEY_CLASSES_ROOT 是用户级和机器级 Classes 注册的合并视图。要判断数据来自哪个范围,应分别查询 HKCU\Software\Classes\CLSID 与 HKLM\Software\Classes\CLSID,并分别记录 32 位和 64 位视图。进程内服务器还需要与宿主进程架构兼容,因此视图标签不能省略。
注册、加载和使用需要分别判断。子键存在说明 Provider 类型已登记。服务器键存在说明 COM 注册文本已找到。文件验证可以说明候选文件是否存在或签名状态如何。实际 COM 对象是否能激活、接口是否实现正确、Filter 是否允许显示、凭据是否被接受,必须由运行时调用或系统日志独立证明。
Credential Provider 不直接决定身份验证结果。Provider 的职责是收集字段、构造凭据序列化数据并向登录界面报告状态。登录界面把序列化结果交给后续的 Windows 身份验证路径。LSA(Local Security Authority,本地安全机构)及其认证包负责协议验证、令牌建立和安全策略处理。Provider 注册存在或显示磁贴,不等于认证包已经接受某次凭据。
这条流程要求审计记录明确边界。注册表和 COM 服务器信息属于 Provider 发现层。令牌、会话和认证事件属于身份验证运行层。读者不能从某个 CLSID 或 DLL 路径推断特定用户的认证是否成功。
COM 资源、注册表句柄和字符串有不同释放规则。HKEY 是 RegOpenKeyExW 成功返回的注册表键引用,调用方 RegCloseKey。COM 接口指针由 Release 减少引用计数。BSTR 由 SysFreeString 释放。三者不能交叉释放。Provider 子键的默认值数据由注册表 API 写入调用方缓冲区,缓冲区本身通常由 std::vector<BYTE> 或调用方数组管理。
RegEnumKeyExW 的子键名长度是 UTF-16 宽字符数,RegQueryValueExW 的值数据长度是字节数。NUL 只是字符串终止字符,返回数据不保证总有 NUL。只有确认 REG 类型和长度对齐后才可解码。成功打开的 Provider 子键、得到的文本副本和从 Classes 根取得的服务器记录都应有明确的所有者和使用期。
标准读取要保留每一层的关联字段。先对三类根键分别以两个视图枚举 CLSID 子键。每条记录保存 Provider 类型、根键、视图、CLSID 子键名、默认值类型和原始数据。随后只对格式有效的 CLSID 查询用户级和机器级 Classes 根,分别保存 InprocServer32 与 LocalServer32 默认值。失败时保留 HRESULT 或 Win32 错误,不用空字符串替代。
错误做法是拿到默认显示名称后立即丢弃 CLSID。名称可重复、可缺失或可本地化,Classes 查询需要 CLSID 才能定位服务器。Provider 类型和视图也决定该注册项在什么登录架构上下文中可见。
Credential Provider、Filter、PLAP Provider 是三种独立类型。相同 CLSID 出现在不同根键时仍保留类型身份,不能按 CLSID 合并为单一条目。
注册表读取同时覆盖 64 位和 32 位视图。认证组件存在于一个视图并不能推断另一视图也存在,输出中应保留视图标签。
完成第一步后,读取范围已经包含三类 Provider 和两个独立的注册表视图。下一步需要在每个范围内找出实际登记的 CLSID 子键,并把默认名称连同原始类型一起保留。
每个 Provider 根键按一级子键枚举。子键名长度使用可扩容缓冲区,ERROR_MORE_DATA 时扩大容量。ERROR_NO_MORE_ITEMS 表示枚举结束。
[招生]科锐逆向工程师培训(2026年7月3日实地,远程教学同时开班, 第56期)!