You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何统计子进程从父进程继承的可继承句柄数量?

统计CreateProcess继承的可继承句柄数量

需求说明

我希望统计当使用设置了bInheritHandles=TRUE的CreateProcess创建子进程时,子进程将继承的可继承句柄数量。

[in] bInheritHandles
若该参数为TRUE,调用进程中的每个可继承句柄都会被新进程继承;若为FALSE,则句柄不会被继承。

尝试过程

我尝试了以下操作:

  1. 统计进程中所有可继承句柄数量
  2. 创建1000个可继承事件
  3. 重新统计句柄数量

但代码输出结果不正确:

BEFORE: Number of inherited handles: 3802
AFTER: Number of inherited handles: 3804

不过Process Explorer显示了正确的前后句柄计数:
Process Explorer句柄计数

使用的代码

#include <windows.h>
#include <winternl.h>
#include <ntstatus.h>
#include <stdio.h>

#define SystemHandleInformation 16
#define INITIAL_BUFFER_SIZE 0x10000
#define INHERITED_HANDLE_FLAG 0x1

typedef struct {
    ULONG ProcessId;
    BYTE ObjectTypeNumber;
    BYTE Flags;
    USHORT Handle;
    PVOID Object;
    ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE;

typedef struct {
    ULONG HandleCount;
    SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION;

typedef UINT(CALLBACK* PFN_NT_QUERY_SYSTEM_INFO)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);

int GetInheritedHandleCount() {
    SYSTEM_HANDLE_INFORMATION* handleInfo = (SYSTEM_HANDLE_INFORMATION*)malloc(INITIAL_BUFFER_SIZE);
    ULONG handleInfoSize = INITIAL_BUFFER_SIZE;
    int inheritedHandleCount = 0;

    PFN_NT_QUERY_SYSTEM_INFO NtQuerySystemInformation = (PFN_NT_QUERY_SYSTEM_INFO)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQuerySystemInformation");

    while (NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, handleInfo, handleInfoSize, NULL) == STATUS_INFO_LENGTH_MISMATCH) {
        handleInfo = (SYSTEM_HANDLE_INFORMATION*)realloc(handleInfo, handleInfoSize *= 2);
    }

    for (ULONG i = 0; i < handleInfo->HandleCount; i++) {
        if (handleInfo->Handles[i].Flags & INHERITED_HANDLE_FLAG) {
            inheritedHandleCount++;
        }
    }

    free(handleInfo);
    return inheritedHandleCount;
}

int main(int argc, char* argv[]) {
    printf("BEFORE: Number of inherited handles: %u\n", GetInheritedHandleCount());
    getchar();

    SECURITY_ATTRIBUTES sa;
    sa.nLength = sizeof(SECURITY_ATTRIBUTES);
    sa.lpSecurityDescriptor = NULL;
    sa.bInheritHandle = TRUE;  // Make handles inheritable

    for (int i = 0; i < 1000; ++i) {
        CreateEvent(&sa, FALSE, FALSE, NULL);
    }

    printf("AFTER: Number of inherited handles: %u\n", GetInheritedHandleCount());
    getchar();

    return 0;
}

临时参考方案

微软技术博客中提到了Win32下如何以编程方式控制新进程继承哪些句柄的方法。

问题

是否有方法可以统计子进程将从父进程继承的句柄数量?


解决方法

你的代码错误在于对INHERITED_HANDLE_FLAG的理解:SYSTEM_HANDLE结构中Flags字段的0x1位,标记的是该句柄是从父进程继承来的,而非该句柄可以被子进程继承。这就是为什么创建1000个可继承事件后,计数仅增加2——这些新句柄是当前进程自行创建的,不是继承而来,所以不会被该标志位标记。

要统计可被继承的句柄数量,需要对每个属于当前进程的句柄,调用GetHandleInformation函数检查HANDLE_FLAG_INHERIT标志。修改后的统计函数如下:

int GetInheritableHandleCount() {
    SYSTEM_HANDLE_INFORMATION* handleInfo = (SYSTEM_HANDLE_INFORMATION*)malloc(INITIAL_BUFFER_SIZE);
    ULONG handleInfoSize = INITIAL_BUFFER_SIZE;
    int inheritableHandleCount = 0;
    DWORD currentPid = GetCurrentProcessId();

    PFN_NT_QUERY_SYSTEM_INFO NtQuerySystemInformation = (PFN_NT_QUERY_SYSTEM_INFO)GetProcAddress(GetModuleHandleA("ntdll.dll"), "NtQuerySystemInformation");

    while (NtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, handleInfo, handleInfoSize, NULL) == STATUS_INFO_LENGTH_MISMATCH) {
        handleInfo = (SYSTEM_HANDLE_INFORMATION*)realloc(handleInfo, handleInfoSize *= 2);
    }

    for (ULONG i = 0; i < handleInfo->HandleCount; i++) {
        SYSTEM_HANDLE* handle = &handleInfo->Handles[i];
        // 仅处理当前进程的句柄
        if (handle->ProcessId != currentPid) {
            continue;
        }

        // 复制句柄到当前进程,避免跨进程直接使用句柄值的冲突
        HANDLE hDup;
        if (DuplicateHandle(GetCurrentProcess(), (HANDLE)handle->Handle, GetCurrentProcess(), &hDup, 0, FALSE, DUPLICATE_SAME_ACCESS)) {
            DWORD info;
            if (GetHandleInformation(hDup, &info)) {
                if (info & HANDLE_FLAG_INHERIT) {
                    inheritableHandleCount++;
                }
            }
            CloseHandle(hDup);
        }
    }

    free(handleInfo);
    return inheritableHandleCount;
}

关键说明

  1. 过滤当前进程句柄:SystemHandleInformation返回系统所有进程的句柄,必须先筛选出属于当前进程的条目。
  2. 检查可继承标志:HANDLE_FLAG_INHERIT才是判断句柄是否能被子进程继承的正确标志,需通过GetHandleInformation获取。
  3. 安全复制句柄:不同进程的句柄值空间独立,直接使用SYSTEM_HANDLE中的Handle值不安全,需通过DuplicateHandle复制到当前进程后再检查。

修改后运行代码,就能得到与Process Explorer一致的正确可继承句柄数量。


内容的提问来源于stack exchange,提问作者vengy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 17:41:01