关于控制CreateProcess继承哪些句柄的补充说明

The Old New Thing (Raymond Chen) 工具

摘要

Raymond Chen介绍了一种使用辅助进程的技术,可以精确控制新进程继承哪些句柄,避免同一进程中其他组件意外继承句柄。

<p>不久前,我写了一篇关于如何使用<code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code>精确限制新进程继承哪些句柄的<a title="通过程序控制Win32新进程继承哪些句柄" href="https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873">文章</a>。这样,当你创建新进程时,就能精确控制哪些句柄被继承,避免意外继承进程中无关组件创建的句柄。</p> <p>我的一位同事指出,你仍然面临相反的问题:由于句柄必须标记为可继承才能参与<code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code>,如果另一个线程在未使用<code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code>的情况下调用<code>Create­Process</code>且<code>bInheritHandles</code> = <code>TRUE</code>,那么它们就会意外继承你所有的句柄。</p> <p>如果<code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code>允许包含不可继承的句柄,那么这个问题本可以避免——在这种情况下,它们对于普通的<code>Create­Process</code>是不可继承的,但如果明确选择重新加入,则变为可继承。但可惜,设计并非如此。</p> <p>相反,你可以创建一个辅助进程。这个辅助进程所做的就是等待主进程退出,然后自身退出。</p> <pre>WaitForSingleObject(hMainProcess, INFINITE); ExitProcess(0); </pre> <p>这个进程听起来没什么用处,实际上也确实没什么用。但它的用处不在于它做了什么,而在于对它做了什么。</p> <p>主进程中的组件以不可继承的方式创建句柄。当它们想要创建一个继承特定句柄的进程时,会将所需句柄复制到辅助进程中(作为可继承句柄),然后构建一个<code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />HANDLE_<wbr />LIST</code>,将这些复制的句柄列为要继承的句柄。它们还使用<code>PROC_<wbr />THREAD_<wbr />ATTRIBUTE_<wbr />PARENT_<wbr />PROCESS</code>指定辅助进程为句柄继承的父进程。然后将这些线程属性传递给<code>Create­Process</code>,新进程将恰好继承这些句柄。最后,它们通过<code>Duplicate­Handle</code>和<code>DUPLICATE_<wbr />CLOSE_<wbr />SOURCE</code>关闭辅助进程中的句柄进行清理。</p> <p>请注意,多个线程可以同时以这种方式对辅助进程进行操作,因此你只需要一个辅助进程即可满足所有句柄继承控制的需求。</p> <p>这避免了意外继承的问题,因为属于主进程组件的句柄仍然标记为不可继承,因此主进程中任何其他代码执行<code>Create­Process</code>时都不会继承它们。</p> <p>本文《<a href="https://devblogs.microsoft.com/oldnewthing/20260511-00/?p=112313">关于控制&lt;CODE&gt;Create&shy;Process&lt;/CODE&gt;继承哪些句柄的补充说明</a>》首发于<a href="https://devblogs.microsoft.com/oldnewthing">The Old New Thing</a>。</p>
查看原文
查看缓存全文

缓存时间: 2026/05/16 03:31

# 关于控制 CreateProcess 继承哪些句柄的附加说明 - 旧事新知 来源:https://devblogs.microsoft.com/oldnewthing/20260511-00?p=112313 不久前,我写过一篇文章,介绍如何通过编程控制 Win32 中新进程继承哪些句柄(https://devblogs.microsoft.com/oldnewthing/20111216-00/?p=8873),即使用 `PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST` 来精确限制继承的句柄。这样一来,创建新进程时,你就能精准控制哪些句柄被继承,避免意外继承进程中无关组件所创建的句柄。 我的一位同事指出,这仍然存在反向问题:由于句柄必须标记为可继承,才能参与 `PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`,如果另一个线程调用 `CreateProcess` 时 `bInheritHandles` = `TRUE`,但未使用 `PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`,那么它们就会意外继承你*所有*的句柄。 如果 `PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST` 允许你包含不可继承的句柄,那么这些句柄在常规 `CreateProcess` 中不可继承,但一旦明确重新加入则可继承,这个问题本可以避免。但可惜,设计并非如此。 不过,你可以创建一个辅助进程。这个辅助进程只做一件事:等待主进程退出,然后自己也退出。 ``` WaitForSingleObject(hMainProcess, INFINITE); ExitProcess(0); ``` 这个进程听起来没做什么有用的事,确实如此。但它之所以有用,不在于它做了什么,而在于对它做了什么。 主进程中的组件将其句柄标记为不可继承。当它们需要创建进程并指定继承某些句柄时,会将所需的句柄复制到辅助进程中(标记为可继承),然后构建一个 `PROC\_THREAD\_ATTRIBUTE\_HANDLE\_LIST`,将这些复制的句柄列为要继承的句柄。同时,它们使用 `PROC\_THREAD\_ATTRIBUTE\_PARENT\_PROCESS` 指定*辅助*进程作为句柄来源的父进程。然后,将这些线程属性传递给 `CreateProcess`,新进程将恰好继承这些句柄。最后,它们通过 `DuplicateHandle` 和 `DUPLICATE\_CLOSE\_SOURCE` 关闭辅助进程中的句柄,进行清理。 注意,多个线程可以同时对辅助进程进行此类操作,因此你只需要一个辅助进程就能满足所有句柄继承控制的需求。 这避免了意外继承问题,因为主进程中组件拥有的句柄仍然标记为不可继承,因此主进程中任何其他代码执行 `CreateProcess` 时都不会继承它们。 ### 类别 ### 主题 ## 作者 Raymond Chen Raymond 参与 Windows 的演进已超过 30 年。2003 年,他创办了一个名为“The Old New Thing”的网站,其受欢迎程度远超他最疯狂的想象,这一发展至今仍让他心有余悸。该网站还衍生出一本书,巧合地也名为《The Old New Thing》(Addison Wesley 2007)。他偶尔会出现在 Windows Dev Docs Twitter 账号上,讲述一些不传递任何有用信息的故事。

相似文章

关于滥用Windows窗口类额外字节的兼容性说明

The Old New Thing (Raymond Chen)

Raymond Chen 讨论了一个历史性的 Windows 兼容性问题,其中一些 16 位程序滥用窗口类额外字节来存储私有数据,以及微软如何在保持向后兼容性的同时,对 32 位和 64 位程序堵住了这个漏洞。

理解在试图绕过规则时规则背后的原理

The Old New Thing (Raymond Chen)

本文来自微软的《老东西》博客,解释了Windows内核回调函数最佳实践背后的原理,特别是为什么阻塞或等待工作项会违背其目的,并通过一个关于驱动程序导致系统挂起的警示故事来说明。

为何不根据链接的SDK来改变API行为?

The Old New Thing (Raymond Chen)

本文以Windows的CoInitializeSecurity为例,探讨了根据链接的SDK版本改变API行为的陷阱。讨论了DLL版本不匹配和尾调用优化等问题使这种方法复杂化。