NtQueryObject 获得内核对象的信息

导读

玩过电脑的都知道,Widnows任务管理器,我们经常用它查看机器的CPU内存等信息,也用它杀死一些卡主的进程。

而作为开发人员,我们为了更了解进行的运行状况,就不得不说另外两个工具:

  • procexp.exe,某大佬写的Sysinternals系列工具中的其中一个工具,可查看操作系统中的各种信息,丰富无比,绝对的Windows瑞士军刀。
  • ProcessHacker.exe,功能和procexp.exe很像,不过是开源项目,学习Windows的可以看看它的实现。

今天我们就获取自己进程主线程的内核对象信息。

API介绍

一个内核对象有两个计数器:一个是句柄计数,句柄是给用户态用的;另一个是指针计数,也叫引用计数,因为核心态也常常用到内核对象,为了方便,在核心态的代码用指针直接访问对象,所以Object   Manager维护了这个指针引用计数。只有在句柄计数和引用计数都为0时,对象才被释放。一般而言,指针引用计数值比句柄计数值大。

再进一步,实际上,在用户态其实是可以查询一个内核对象的句柄计数和引用计数的。Ntdll.dll里导出的NtQueryObject函数可以查询内核对象的当前状态,只不过它没有被文档化。

参考微软官网 NtQueryObject function https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntqueryobject

函数声明如下:
DWORD   WINAPI   NtQueryObject(   HANDLE   handle,   DWORD   nQueryIndex,   VOID*   pOutBuffer,   DWORD   cbInBufferSize,   VOID*   cbOutBufferSize);

handle   --   待查询的句柄
nQueryIndex   --   0为查询对象的当前状态,包括句柄计数,引用计数等等。
pOutBuffer   --   存放查询结果
cbInBufferSize   --   pOutBuffer的大小,注意,如果nQueryIndex为0,这里一定得是0x38
cbOutBufferSize   --   实际大小。

返回值:如果成功则返回0

pOutBuffer里返回的数据结构如下:
typedef   struct   _SYSTEM_HANDLE_STATE   {
DWORD   r1;
DWORD   GrantedAccess;
DWORD   HandleCount;   //   减1为句柄计数
DWORD   ReferenceCount;   //   减1为指针引用计数
DWORD   r5;
DWORD   r6;
DWORD   r7;
DWORD   r8;
DWORD   r9;
DWORD   r10;  
DWORD   r11;  
DWORD   r12;  
DWORD   r13;  
DWORD   r14;  
}SYSTEM_HANDLE_STATE,   *PSYSTEM_HANDLE_STATE;

功能实现

#include <string>
#include <ntdll/ntdll.h>
#pragma comment(lib,"ntdll.lib")

int test()
{
	HANDLE Handle = GetCurrentThread();
	OBJECT_BASIC_INFORMATION o_BASIC_INFORMATION;
	OBJECT_TYPE_INFORMATION o_TYPE_INFORMATION[10];
	OBJECT_NAME_INFORMATION o_NAME_INFORMATION;
	ULONG ReturnLength = 0;
	NtQueryObject(Handle, ObjectBasicInformation, &o_BASIC_INFORMATION, sizeof(o_BASIC_INFORMATION), &ReturnLength);
	NtQueryObject(Handle, ObjectNameInformation, &o_NAME_INFORMATION, sizeof(o_NAME_INFORMATION), &ReturnLength);
	NtQueryObject(Handle, ObjectTypeInformation, &o_TYPE_INFORMATION, o_BASIC_INFORMATION.TypeInfoSize, &ReturnLength);

	std::wstring TypeName(o_TYPE_INFORMATION[0].TypeName.Buffer, o_TYPE_INFORMATION[0].TypeName.Length / 2);
	std::wstring ObjName(L"[NULL]");
	if (o_NAME_INFORMATION.Name.Length)
	{
		ObjName.assign(o_NAME_INFORMATION.Name.Buffer, o_NAME_INFORMATION.Name.Length / 2);
	}
	printf("Name: %ws \nType: %ws \n \nGranted access:%8X \nReferences: %d \nHandles: %d \n", 
		ObjName.data(), TypeName.data(), o_BASIC_INFORMATION.GrantedAccess,
		o_BASIC_INFORMATION.PointerCount, o_BASIC_INFORMATION.HandleCount);
	return 0;
}

这里我们使用了https://github.com/x64dbg/x64dbg项目中的ntdll.hntdll.lib,里面讲ntdll中的函数及数据结构整理出来了,我们直接使用就行了,通过NtQueryObject接口,我们可以查询到丰富的句柄信息。运行结果如下:

ProcessHacker.exe查看的结果如下:

 内容基本相同,句柄数和引用数有差异,暂时不深入研究了。

 

参考资料

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
前言 上一次发布过的程序:【首发】检测文件的占用,具有学习和商业价值(By超级用户),可以使用,仿电脑管家 正文 对于怎么枚举文件句柄 ,上一帖子对此有介绍,核心代码大概如下:如果 (ZwQueryObject (handle, #ObjectTypeInformation, unicode, 0, size) ≠ #STATUS_INVALID_HANDLE )' 只要不是无效的,为什么,详细看下面的注释 ' 参数 ' Handle ' 对象的一个句柄来获取信息。 ' ObjectInformationClass ' 指定一个OBJECT_INFORMATION_CLASS返回值的类型决定了信息在ObjectInformation缓冲区。 ' ObjectInformation ' 一个指向caller-allocated缓冲接收请求的信息。 ' ObjectInformationLength ' 指定的大小,以字节为单位,ObjectInformation缓冲区。 ' ReturnLength ' 一个指向变量的指针,接收的大小,以字节为单位,请求的关键信息。如果NtQueryObject STATUS_SUCCESS返回,返回的变量包含的数据量。如果NtQueryObject返回STATUS_BUFFER_OVERFLOW或STATUS_BUFFER_TOO_SMALL,您可以使用变量的值来确定所需的缓冲区大小。 ' 返回值 ' NtQueryObject返回STATUS_SUCCESS或适当的错误状态。可能的错误状态码包括以下: ' 返回代码 描述 ' STATUS_ACCESS_DENIED ' 有足够的权限来执行该cha询。 ' STATUS_INVALID_HANDLE ' 提供对象句柄无效。 ' STATUS_INFO_LENGTH_MISMATCH ' 信息长度不足以容纳数据。 unicode = 取空白字节集 (size) ZwQueryObject (handle, #ObjectTypeInformation, unicode, size, 0)' 读取信息的unicode文本 RtlUnicodeStringToAnsiString (ansi, unicode, 真)' 编码转换 ' RtlUnicodeStringToAnsiString例程将给定Unicode字符串转换成一个ANSI字符串。 str = 指针到文本 (ansi.Buffer) ' RtlFreeAnsiString常规版本存储由RtlUnicodeStringToAnsiString分配。 ' 参数 ' AnsiString ' 指针ANSI字符串缓冲区由RtlUnicodeStringToAnsiString以前分配的。 RtlFreeAnsiString (ansi) str = “无法获取”' 无效的怎么获取…… 返回 (str) 这一次呢更新了一个RemoteCloseHandle ,大概的原理是什么呢? 同时也采用了一些比较骚的方法,这种方法的限制较多,但是对于32位进程就很有效果。 NtClose在MSDN的大概介绍 1. NtClose is a generic routine that operates on any type of object. 2. Closing an open object handle causes that handle to become invalid. The system also decrements the handle count for the object and checks whether the object can be deleted. The system does not actually delete the object until all of the object's handles are closed and no referenced pointers remain. 3. A driver must close every handle that it opens as soon as the handle is no longer required. Kernel handles, which are those that are opened by a system thread or by specifying the OBJ_KERNEL_HANDLE flag, can be closed only when the previous processor mo

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夜猫逐梦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值