跳转到主内容
趣航编程网 - 趣学编程,启航技术之路!

C++如何获取系统已打开的句柄总数 _ NtQuerySystemInformation【实战】

NtQuerySystemInformation 返回 STATUS_INVALID_INFO_CLASS 主因是误用已禁用的 SystemHandleInformation(24),应改用 SystemExtendedHandleInformation(64)并动态加载、提权后两次调用获取 HandleCount 总数。 为什么
NtQuerySystemInformation
返回
STATUS_INVALID_INFO_CLASS
直接调用
NtQuerySystemInformation
查询句柄总数时,最常见错误是用了已废弃或未公开的
SystemHandleInformation
(即
24
)。Windows 10 1809+ 和 Server 2019 起,该信息类默认被禁用,即使你正确声明了
SYSTEM_HANDLE_INFORMATION
结构体,也会触发
STATUS_INVALID_INFO_CLASS
。这不是权限问题,也不是函数没导出——而是系统策略层面限制了该接口的直接使用。 真正可用且稳定的替代方案是:
SystemExtendedHandleInformation
(
64
),它返回带进程名的句柄列表,结构体更宽但兼容性好;或者改用
SystemKernelDebuggerInformation
等间接方式(不推荐)。实战中应优先尝试
64
。 必须用
ntdll.dll
动态加载
NtQuerySystemInformation
,不能静态链接 调用前需启用
SE_DEBUG_PRIVILEGE
权限,否则部分进程句柄无法枚举(尤其是系统进程)
SystemExtendedHandleInformation
返回的
NumberOfHandles
字段才是当前系统总句柄数,不是数组长度 如何安全获取
SYSTEM_HANDLE_INFORMATION_EX
并统计总数 Windows SDK 不提供
SYSTEM_HANDLE_INFORMATION_EX
定义,必须手动声明。注意:该结构体在不同 Windows 版本中字段对齐可能变化,不能直接按旧版
SYSTEM_HANDLE_INFORMATION
复用。 关键点在于两次调用模式:第一次传
nullptr
获取所需缓冲区大小,第二次分配足够内存再调用。失败时检查
STATUS_INFO_LENGTH_MISMATCH
,而非直接报错退出。 立即学习 “ C++免费学习笔记(深入) ”; C知道 CSDN推出的一款AI技术问答工具 下载 缓冲区大小建议初始分配 64KB,多数场景够用;若失败则按返回的
*ReturnLength
重新分配
HandleCount
字段位于结构体开头,类型为
ULONG
,不是数组元素个数,而是系统级总计数 每个句柄条目(
SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX
)的
ObjectTypeIndex
可用于过滤(如只算
File
或
Event
类型)
// 示例片段:获取总数(省略权限提升和错误处理) ULONG size = 0; NTSTATUS status = pNtQuerySystemInformation( (SYSTEM_INFORMATION_CLASS)64, nullptr, 0, &size); if (status == STATUS_INFO_LENGTH_MISMATCH) { auto buf = std::make_unique(size); status = pNtQuerySystemInformation( (SYSTEM_INFORMATION_CLASS)64, buf.get(), size, &size); if (NT_SUCCESS(status)) { auto info = reinterpret_cast(buf.get()); printf("Total handles: %lu\n", info->HandleCount); // 这就是你要的总数 } }
用
GetProcessHandleCount
只能查单个进程,别误当系统总数
GetProcessHandleCount
是 Win32 API,只能返回**调用者自身进程**的句柄数(即当前程序打开了多少句柄),和系统全局句柄总数完全无关。很多开发者看到函数名里有 “HandleCount” 就以为是系统级接口,结果调试半天发现数值始终在几百徘徊——那只是你自己的进程。 它不需要提权,也不依赖 ntdll,但作用域严格限定为当前进程 返回值是
DWORD
,但实际受进程句柄表限制(默认上限约 16,777,216,但极少达到) 若需监控多个进程句柄数,必须用
OpenProcess
+
NtQuerySystemInformation
枚举匹配 PID 的条目,不能靠累加 权限、符号与调试器干扰的真实影响 即使代码逻辑完全正确,仍可能拿不到准确总数:一是权限不足导致跳过某些进程(如
svchost
、
lsass
),二是启用内核调试器(如 WinDbg 启用本地内核调试)会强制禁用
SystemExtendedHandleInformation
,此时返回
STATUS_ACCESS_DENIED
。 提权代码必须在调用前执行,且要确保
SeDebugPrivilege
已启用(不是仅获取句柄) 用
!handle
命令在 WinDbg 中验证:若输出显示 “Scanning all processes...” 且无拒绝提示,说明权限到位 Release 模式下关闭所有调试器连接,否则某些 Windows 版本会静默降级信息类 句柄总数本身是个瞬时快照,没有原子性保证;如果你在循环中反复调用并观察到剧烈波动(比如 ±5000),大概率是其他进程正在批量创建/关闭句柄,而不是你的代码有问题。

相关文章