WMI内部机制Part3:从COM方法追踪到RPC过程调用

admin 2026-03-09 01:30:37 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 本文深入分析了WMI创建计划任务的底层机制,详细梳理了ITaskFolder::RegisterTaskDefinition到RPC调用SchRpcRegisterTask的完整链路。通过IDA逆向分析taskschd.dll,利用NdrClientCall3API及相关结构体定位了RPC接口UUID和Opnum,揭示了WMI类PS_ScheduledTask最终通过ITaskSchedulerService接口执行任务注册的本质,为防御者深入理解攻击技术底层实现提供了重要参考。 综合评分: 89 文章分类: 逆向分析,二进制安全,安全建设


cover_image

WMI 内部机制 Part 3:从 COM 方法追踪到 RPC 过程调用

Jonathan Johnson Jonathan Johnson

securitainment

2026年3月7日 23:09 中国香港

| 原文链接 | 作者 | | — | — | | https://jonny-johnson.medium.com/wmi-internals-part-3-38e5dad016be | Jonathan Johnson |

在之前的文章 — WMI Internals Part 2: Reversing a WMI Provider 中,我详细介绍了 WMI 架构在底层如何依赖 COM 构建,进而 WMI 类如何通过调用 COM 方法来执行具体操作。当时我以 PS_ScheduledTaskWMI 类为例,演示了创建该类实例时 COM 方法 ITaskServices:NewTask的调用过程。

本文将进一步深入,探究 ITaskServices:NewTask这个 COM 方法被调用之后发生了什么。虽然这部分内容与 WMI 没有直接关系,但上一篇文章缺少一个完整的收尾,本文正好可以补全这一环节。

简要背景

这里不深入探讨 COM/DCOM/RPC/ALPC 的内部机制 — 简单来说,组件对象模型 (Component Object Model, COM) 在许多技术中充当远程过程调用 (Remote Procedure Call, RPC) 接口之上的抽象层。因此,当你看到 COM 方法被调用时,随后出现 RPC 调用是完全正常的。分布式 COM (Distributed COM, DCOM) 也是同理,因为其底层的调用传输同样基于 RPC。Alex Ionescu 在他的演讲 “All About The Rpc, Lrpc, Alpc, And Lpc In Your Pc” 中对这些概念进行了出色的讲解,强烈推荐一看。

分析过程

查看 Microsoft 文档对 ITaskServices:NewTask方法的描述:”返回一个空的任务定义对象,用于填充设置和属性,随后通过 ITaskFolder::RegisterTaskDefinition方法完成注册”。尽管我认为不应将文档奉为圭臬,但通过动态分析我已验证上述描述确实准确。由于从 NewTask 到 RegisterTaskDefinition 的调用链较为复杂,详细展开会偏离本文的核心主题,因此我们直接从 ITaskFolder::RegisterTaskDefinition 开始分析。

步骤 1 — 定位 ITaskFolder COM 服务器:

好在 Microsoft 对此有完善的文档。COM 服务器存储在 taskschd.dll 中。

步骤 2 — 识别并分析**ITaskFolder::RegisterTaskDefinition**方法定义:

在 IDA 中打开目标文件并在函数窗口中搜索 RegisterTaskDefinition,可以找到一个名为 RegisterTaskDefinition@?QITaskFolder的函数:

该函数实质上是一个包装器 (wrapper),最终调用的是 TaskFolderImp::Register。进一步分析该函数后,可以发现其中调用了一些值得关注的函数,如 TaskFolderImpl::GetNewTaskPath和 TaskDefinitionImpl::get_RawXmlText,但最引人注目的是对 UniSession::RegisterTask的调用:

打开该函数后,可以看到它立即调用了 RpcSession::RegisterTask。这正是我们在追踪计划任务注册流程时需要找到的关键调用。

该调用逻辑相当简洁,其核心目的是调用 NdrClientCall3 API。NdrClientCall 系列 API 通常用于发起 RPC 过程调用。如果我们能追踪到具体调用了哪个 RPC 接口及其 Opnum,就能验证计划任务的注册机制。

传入 NdrClientCall3 的参数中,有 2 个对识别具体调用至关重要:

  • pProxyInfo — 指向该 RPC 调用代理信息的指针。
  • nProcNum — 要调用的过程编号 / opnum 值。

首先来看 pProxyInfo,它承载了 RPC 接口的 UUID。在前文 NdrClientCall3 函数定义的截图中,可以看到 pProxyInfo 是一个指向 MIDL_STUBLESS_PROXY_INFO结构体的指针。搜索该结构体后,可以在 Microsoft 的 GitHub 仓库中找到相关页面 –

点击 MIDL_STUB_DESC 后,我们发现已经接近目标 — 第一个结构体成员 RpcInterfaceInformation暴露了出来。根据文档描述,该成员承载接口结构信息:”对于服务器端的非对象 RPC 接口,它指向 RPC 服务器接口结构;在客户端,它指向 RPC 客户端接口结构;对于对象接口则为空。” 由于我们处于客户端侧,需要找的是 RPC 客户端接口结构,由此引出了 RPC_CLIENT_INTERFACE

可以看到该结构体的第 2 个成员保存了 RPC InterfaceId,其值为 UUID 格式。下面梳理一下我们刚才的寻址过程:

  • pProxyInfo (RCX) 保存 RPC Interface ID,存储于 MIDL_STUBLESS_PROXY_INFO 结构体中 (指针 1 — 偏移 0)
  • MIDL_STUBLESS_PROXY_INFO 的第一个成员 (pStubDesc) 指向 MIDL_STUB_DESC (指针 2 — 偏移 0)
  • MIDL_STUB_DESC 的第一个成员 (RpcInterfaceInformation) 指向 RPC_CLIENT_INTERFACE (指针 3 — 偏移 0)
  • RPC_CLIENT_INTERFACE 的第 2 个成员保存 InterfaceId (偏移 4,InterfaceId 长 16 字节)

在 IDA 中沿着这条指针链追踪,最终会看到如下视图,InterfaceID 起始地址为 000000018005A3C4。

获取 InterfaceID (UUID) 有多种方式,这里我们选择从十六进制视图中提取原始字节,再通过 PowerShell 进行转换。UUID 为 16 字节长,提取内容为 49 59 D3 86 C9 83 44 40 B4 24 DB 36 32 31 FD 0C,然后在 PowerShell 中转换即可 –

搜索该 UUID 86D35949-83C9-4044-B424-DB363231FD0C后,可以找到对应的 RPC 接口 ITaskSchedulerService。现在我们已经确定了被调用的接口,接下来需要确定具体调用的是哪个过程。回到 NdrClientCall3,可以看到 RDX 寄存器存储了该值,此处为 1。在 ITaskSchedulerService 接口中查找 Opnum 1,最终定位到 SchRpcRegisterTask。

经过以上完整的分析流程,我们可以得出结论:当通过 WMI 类 PS_ScheduledTask创建计划任务时,首先会调用 COM 方法 ITaskServices::NewTask,随后到达 ITaskFolder:RegisterTaskDefinition,最终触发 RPC 过程 SchRpcRegisterTask

结论

上一篇文章的结尾留下了遗憾。虽然我们看到了使用 WMI 类 PS_ScheduledTask 后调用了哪个 COM 方法,但始终没有完成后续流程的分析。本文正是为了补全那个节点之后的所有内容。对于任何希望将攻击技术拆解到最底层的防御工程师而言,这一点至关重要。我们很容易停留在较高的抽象层面,仅在可见的最上层进行检测,但如果能继续深入挖掘,就有可能找到实现某种行为的核心函数。

众所周知,计划任务的遥测数据同时存在于 ETW 提供程序和 Windows 安全事件日志中。在后续文章中,我将进一步探讨这些日志的生成机制,以及我们是否能够真正依赖这些事件进行检测。

希望这篇分析对想要了解 COM 到 RPC 层调用链路的读者有所帮助。期待未来能分享更多此类深入分析。


免责声明:本博客文章仅用于教育和研究目的。提供的所有技术和代码示例旨在帮助防御者理解攻击手法并提高安全态势。请勿使用此信息访问或干扰您不拥有或没有明确测试权限的系统。未经授权的使用可能违反法律和道德准则。作者对因应用所讨论概念而导致的任何误用或损害不承担任何责任。


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:securitainment Jonathan Johnson Jonathan Johnson《WMI 内部机制 Part 3:从 COM 方法追踪到 RPC 过程调用》

评论:0   参与:  0