返回 2026-05-12
⚙️ 工程

控制 CreateProcess 继承句柄的附加说明Additional notes on controlling which handles are inherited by Create­Process

Raymond Chen 在微软旧闻博客中深入解析 Windows API 中 CreateProcess 函数的句柄继承机制。文章提出一种新方案:使用私有容器存储需继承的句柄,从而更精细地控制子进程可访问的系统资源,提升安全性与隔离性。

Raymond Chen

之前我曾写过关于如何使用 PROC_THREAD_ATTRIBUTE_HANDLE_LIST 来编程控制 Win32 中哪些句柄会被新进程继承,从而精确限制可继承的句柄范围。这样,在创建新进程时,就能准确控制哪些句柄被继承,避免意外继承进程中无关组件创建的句柄。

我的同事指出,问题其实并未完全解决:由于只有被标记为可继承的句柄才能参与 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 参与 Windows 系统演进已超过 30 年。2003 年,他创办了名为 The Old New Thing 的网站,其受欢迎程度远超他的想象,至今仍让他感到些许不安。该网站催生了一本同名书籍《The Old New Thing》(Addison Wesley, 2007)。他偶尔会在 Windows Dev Docs 的 Twitter 账号上出现,讲述一些毫无实用价值的故事。

需要完整排版与评论请前往来源站点阅读。