当前位置:

首页 > 编程开发 > C++如何统计进程占用的所有句柄类型 _ 句柄枚举与分析【实战】

C++如何统计进程占用的所有句柄类型 _ 句柄枚举与分析【实战】

利用NtQuerySystemInformation枚举进程句柄时,需启用SeDebugPrivilege权限并匹配系统架构。通过SystemExtendedHandleInformation获取ObjectTypeIndex,再查表映射类型名。需注意版本兼容性、权限陷阱及防病毒软件干扰。

很多人以为直接用EnumHandleInformation就能拿到进程句柄,但事实并非如此——这个接口是内核态专属,只有驱动或高权限系统工具才碰得到。对于用户态程序而言,真正可行的路径是借助NtQuerySystemInformation,搭配SystemExtendedHandleInformation(适用于Win10 1607及以上版本)或兼容旧版系统的SystemHandleInformation,同时别忘了把SeDebugPrivilege权限和同架构运行条件备齐。

C++如何统计进程占用的所有句柄类型 _ 句柄枚举与分析【实战】

如何用 EnumHandleInformation 获取进程所有句柄(Windows)

Windows 并没有一个公开的API能直接返回所谓的“句柄类型名”。EnumHandleInformation 是Windows 10 1809+才新增的内核态接口,普通用户态程序根本没法直接调用。所以,实际开发中真正管用的,还是走 NtQuerySystemInformation 加上 SystemHandleInformation(虽然已废弃但还能跑),或者更稳定的 SystemExtendedHandleInformation(Win10 1607+开始支持)。

这里有个关键点:你必须拿到 SeDebugPrivilege 权限才能打开目标进程,同时还得确保调用线程拥有调试权限——否则 NtQuerySystemInformation 要么返回 STATUS_ACCESS_DENIED,要么只给你吐出一部分句柄,根本不够用。

  • 首先,得用 OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_DUP_HANDLE, FALSE, pid) 把目标进程打开。
  • 其次,调用前要通过 AdjustTokenPrivileges 把 SE_DEBUG_NAME 启用上。
  • 最后,SystemExtendedHandleInformation 返回的每个 SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX 结构里,有个 ObjectTypeIndex 字段,但这仅仅是类型索引,不是字符串——要想知道真实的类型名,还得去查系统全局对象类型表(即 ObGetObjectType,但函数不可用;要么靠硬编码映射,要么读取 ntdll!ObTypeIndexTable,不过符号没导出,稳定做法是找已知偏移加特征扫描,或者依赖 Psapi.dll 的 GetProcessImageFileName 做辅助判断)。

为什么 GetFileType 和 GetHandleInformation 不能用于句柄类型分类

这两个函数经常被人误用。GetFileType 只对文件或设备句柄有效,碰到事件、互斥体、节(section)、注册表键这些,直接返回 FILE_TYPE_UNKNOWN。GetHandleInformation 则只返回标志位(比如 HANDLE_FLAG_INHERIT),和类型信息八竿子打不着。

常见的翻车现场是,遍历句柄时对每个句柄都调用 GetFileType,结果80%都返回 FILE_TYPE_UNKNOWN,然后你傻眼以为“不是文件”,其实人家可能是 Event 或 Section。

  • GetFileType 的本质是向对象发送 IRP_MJ_QUERY_INFORMATION,只有 FileObject 类型会回应,其余大多数对象直接撂挑子。
  • GetHandleInformation 读的是句柄表项的 Flags 字段,和对象类型完全不搭。
  • 唯一能间接推断类型的轻量方法,是用 DuplicateHandle 尝试复制为 EVENT_ALL_ACCESS 或 MUTANT_ALL_ACCESS,然后看 GetLastError 返回什么——但这开销大,还容易触发安全软件拦截,只适合离线分析场景。

实战:用 NtQuerySystemInformation 枚举并映射句柄类型(C++ 示例核心逻辑)

下面这段代码可以嵌入任何 Win32 C++ 工程里(记得链接 ntdll.lib,还得自己声明 NtQuerySystemInformation):

// 假设已获取 target_pid 和 hProcess
ULONG size = 0;
NTSTATUS status = NtQuerySystemInformation(SystemExtendedHandleInformation, nullptr, 0, &size);
if (status == STATUS_INFO_LENGTH_MISMATCH) {
    auto info = std::make_unique(size);
    status = NtQuerySystemInformation(SystemExtendedHandleInformation, info.get(), size, &size);
    if (NT_SUCCESS(status)) {
        auto p = reinterpret_cast(info.get());
        for (ULONG i = 0; i < p->NumberOfHandles; ++i) {
            auto h = &p->Handles[i];
            if (h->UniqueProcessId == target_pid) {
                // h->ObjectTypeIndex 是关键:查表得类型名
                const char* type_name = GetTypeNameByIndex(h->ObjectTypeIndex); // 自定义查表函数
                printf("Handle: %p, Type: %s, Attributes: %x\n",
                        (void*)h->HandleValue, type_name, h->HandleAttributes);
            }
        }
    }
}

GetTypeNameByIndex 函数需要维护一个静态数组,对应 Windows 内核中 ObTypeIndexTable 的常见索引(比如 0x19 是 Event,0x1A 是 Mutant,0x1E 是 Section,0x20 是 Key)。这个表在不同 Windows 版本里有微小变化,最好从 ntoskrnl.exe 符号或 WinDbg 中提取最新版,别想着一口气硬编码完 100 多项。

  • 务必要检查 h->HandleValue 是否合法(不能是 0 或 0xffffffff)。
  • h->HandleAttributes 中 HANDLE_FLAG_PROTECT_FROM_CLOSE 位用来识别受保护句柄,别误关了。
  • 另外,枚举结果不包含句柄所指对象的名称(比如文件路径、事件名),要获取名称还得额外调用 NtQueryObject,而且成功率看对象支不支持 ObjectNameInformation。

容易被忽略的兼容性与权限陷阱

很多代码在开发机上跑得飞起,一上线就翻车,问题几乎全出在权限和版本适配这些细节上。

  • Windows Server 2016+ 默认不给非 SYSTEM 进程开 SeDebugPrivilege,得在组策略里把调试程序权限启用,或者用 RunAs 启动(但生产环境不推荐这么做)。
  • SystemExtendedHandleInformation 在 Windows 7 上根本不存在,要向下兼容只能退回到 SystemHandleInformation,但返回的结构里没有 ObjectTypeIndex,只能靠对象地址低字节猜类型,准确率不到 70%。
  • 32 位程序在 64 位系统上枚举 64 位进程句柄会直接失败(STATUS_INVALID_HANDLE),必须确保架构一致,或者折腾 WOW64 兼容层加 NtWow64QueryInformationProcess64,复杂得不行,通常直接要求同架构。
  • 杀毒软件或 EDR 常常 Hook NtQuerySystemInformation,返回截断数据或者伪造句柄,这时候就得结合 Toolhelp32 和内存扫描交叉验证。

真正的稳定句柄类型统计,从来不是单次 API 调用就能搞定的——它牵涉权限控制、版本适配、错误容忍和多源验证。别指望写一个 for 循环就能输出完美报表。

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
编程开发 C++
相关文章 更多
C++动态数组初始化怎么写?常用语句与代码示例
C++动态数组初始化怎么写?常用语句与代码示例

深入解析C++中动态数组的初始化机制,涵盖new操作符的不同用法、基本类型与类对象的初始化差异,以及为何在现代C++开发中应优先使用std::vector。

C++类构造与析构函数详解
C++类构造与析构函数详解

C++类构造与析构函数详解 C++这门语言,可以说是从C语言这棵大树上衍生出的高级果实,如今的应用普及度有目共睹。作为一种静态类型的通用编程语言,它厉害的地方在于融合了多种编程哲学——无论是传统的面向过程,还是主流的面向对象,乃至数据抽象、泛型编程这些高级概念,它都能很好地支持。正因为这份卓越的扩展

C++中std::upper
C++中std::upper

C++中std::upper_bound用法解析 在C++标准模板库(STL)的算法工具箱里,upper_bound() 绝对算得上是一把精准的“探针”。它的核心任务很明确:在一个已经排好序的区间 [first, last) 内,帮你快速定位到第一个**严格大于**指定值 value 的那个元素。这

C++常对象与成员解析
C++常对象与成员解析

C++中“常”概念全景解析:从对象、成员到指针与引用 在C++的世界里,“常量性”是一个强大的保障机制。它不仅仅是一个const关键字那么简单,而是构建健壮、安全程序的重要基石。今天,我们就来系统梳理一下围绕“常”的一系列概念:常成员、常对象、常指针与常引用。理解它们,是写出高质量C++代码的关键一

c++如何将结构体写入SQLite数据库_对象关系映射方案【进阶】
c++如何将结构体写入SQLite数据库_对象关系映射方案【进阶】

直接用SQLiteCAPI绑定结构体需要手动处理字段展平与顺序对齐,ORM库虽省代码但存在隐式行为风险。小项目建议原生绑定,中大型项目可搭配编译期校验使用轻量ORM。绑定std::string需传指针与长度,注意生命周期;浮点字段比较需设误差范围。

什么是编程,学习编程的意义是?
什么是编程,学习编程的意义是?

编程是编写程序指令,让设备按意图运行,常用Python、C等语言或Scratch图形化编程。学习编程能跟上科技时代,锻炼自学与解决问题能力,提升逻辑思维,代表行动力,推动事物前进。各司其职,编程者尽本分。

编程是门艺术_是编程艺术吗?
编程是门艺术_是编程艺术吗?

编程被争论是否为艺术。从定义看,编程是技能表达,但并非所有编程都是应用开发。写代码如音乐、文章,有独特风格。好代码需耐心与逻辑能力。编程是艺术,但应用开发不等同于编程艺术。

【编程的感受】
【编程的感受】

很多人提起编程,总觉得这是一门“不起眼”的学问——不就是写写代码嘛,能有多深?但真走进去了才会发现,编程里头的门道,远比表面看上去要丰富得多。 学习编程的过程中,最容易卡住的往往是那些基础语法。就拿那个常见的 for 循环来说吧,刚开始时怎么都绕不过弯来:为什么这么写能循环?循环条件到底怎么控制?一

对于懂得编程的人来说,编程对你来说有什么乐趣?编程大概是什么感觉?
对于懂得编程的人来说,编程对你来说有什么乐趣?编程大概是什么感觉?

解决编程问题后的痛快、完成作品的成就感、获取知识的满足感,以及用代码实现简化生活的惊喜与踏实,这些是编程独有的乐趣,只有真正写代码的人才能体会其中的酸甜苦辣、惊喜与满足,令人回味无穷。

趣味编程:少儿编程思维的启蒙之旅
趣味编程:少儿编程思维的启蒙之旅

Scratch图形化编程以拖拽积木块方式启蒙少儿编程思维,无需记忆代码语法。通过素材库、即时反馈和社区协作,帮助孩子在创作中理解顺序执行、条件判断等核心概念,锻炼逻辑、创造力和问题解决能力。

查看更多
精品专题 更多
装机必备
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows
Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

PDF教程
PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

Mac软件 更多
Postman macOS版
Postman macOS版
Mac

Postman是一套面向API全生命周期的开发与测试平台,可在Mac上发送和调试多种协议请求,管理集合、环境及认证信息,并完成脚本测试、模拟服务、监控、文档发布和团队协作。它适合开发、测试及运维人员使用,提供个人免费方案。

Docker Desktop macOS版
Docker Desktop macOS版
Mac

Docker Desktop 是 Docker 官方为 Mac 提供的容器开发环境,集成 Docker Engine、命令行工具、Compose、Build、Kubernetes 与图形化管理界面。

Android Studio macOS版
Android Studio macOS版
Mac

Android Studio 是 Google 面向安卓应用开发提供的官方集成开发环境,基于 IntelliJ IDEA 构建。它整合智能代码编辑、Gradle 构建、界面预览、设备模拟、性能分析、调试测试及 APK 分析等工具。

WINDOWS 更多
PixPix 网页版
PixPix 网页版
Windows

PixPix 是面向品牌、卖家和内容团队的在线 AI 图片视频创作平台,提供图视频 Agent、无限画布、图片生成、视频生成、自然语言编辑及商品套图、产品精修和带货视频等电商工具。

Postman Windows版
Postman Windows版
Windows

Postman 是面向 API 全生命周期的开发与协作平台。Windows 桌面版可用于构建和发送 HTTP、GraphQL、gRPC、WebSocket、MQTT 等请求,并提供环境变量、集合、脚本测试、模拟服务、监控、文档及团队工作区等

Docker Desktop Windows版
Docker Desktop Windows版
Windows

Docker Desktop 为 Windows 开发者提供集成式容器环境,内置 Docker Engine、命令行工具、Compose、Build 与 Kubernetes 等组件,可在本机完成镜像构建、容器运行、日志查看和资源管理。