如何统计子进程从父进程继承的可继承句柄数量?
统计CreateProcess继承的可继承句柄数量
需求说明
我希望统计当使用设置了bInheritHandles=TRUE的CreateProcess创建子进程时,子进程将继承的可继承句柄数量。
[in] bInheritHandles
若该参数为TRUE,调用进程中的每个可继承句柄都会被新进程继承;若为FALSE,则句柄不会被继承。
尝试过程
我尝试了以下操作:
- 统计进程中所有可继承句柄数量
- 创建1000个可继承事件
- 重新统计句柄数量
但代码输出结果不正确:
BEFORE: Number of inherited handles: 3802 AFTER: Number of inherited handles: 3804
不过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; }
关键说明
- 过滤当前进程句柄:
SystemHandleInformation返回系统所有进程的句柄,必须先筛选出属于当前进程的条目。 - 检查可继承标志:
HANDLE_FLAG_INHERIT才是判断句柄是否能被子进程继承的正确标志,需通过GetHandleInformation获取。 - 安全复制句柄:不同进程的句柄值空间独立,直接使用
SYSTEM_HANDLE中的Handle值不安全,需通过DuplicateHandle复制到当前进程后再检查。
修改后运行代码,就能得到与Process Explorer一致的正确可继承句柄数量。
内容的提问来源于stack exchange,提问作者vengy
相关产品推荐
相关产品推荐

