枚举进程句柄

目前正在做的项目进行性能测试,被通知进程句柄数已经到达2600多,心中甚是一惊,用Procexp查看句柄表得知,为类型为Key的句柄,名称为\Registry\HKLM\Microsoft\CTF\AssemblyItem....,基本上得知是输入法关联的注册表项,而后用ProcMon监视注册表项操作关联的线程栈,确认句柄为Sogou输入法组件打开,为什么句柄没有关闭,原因不得而知,本人并没有深入的研究,或许是Sogou的bug,或者我们的注册表过滤驱动导致。也没有时间去协调人员去检查,于是我打算在用户层枚举句柄,而后关闭这些句柄。经过Google,查到了一下方法

http://forum.sysinternals.com/howto-enumerate-handles_topic18892.html

于是本人写了个枚举句柄的类

#pragma once

#define SystemHandleInformation 16

#define ObjectBasicInformation 0
#define ObjectNameInformation 1
#define ObjectTypeInformation 2

#define STATUS_SUCCESS 0x00000000
#define STATUS_INFO_LENGTH_MISMATCH 0xC0000004


typedef NTSTATUS (WINAPI *_NtQuerySystemInformation)(
	ULONG SystemInformationClass,
	PVOID SystemInformation,
	ULONG SystemInformationLength,
	PULONG ReturnLength
	);

typedef NTSTATUS (WINAPI *_NtQueryObject)(
	HANDLE ObjectHandle,
	ULONG ObjectInformationClass,
	PVOID ObjectInformation,
	ULONG ObjectInformationLength,
	PULONG ReturnLength
	);

/* The following structure is actually called SYSTEM_HANDLE_TABLE_ENTRY_INFO, but SYSTEM_HANDLE is shorter. */
typedef struct _SYSTEM_HANDLE
{
	ULONG ProcessId;
	BYTE ObjectTypeNumber;
	BYTE Flags;
	USHORT Handle;
	PVOID Object;
	ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE, *PSYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION
{
	ULONG HandleCount; /* Or NumberOfHandles if you prefer. */
	SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

typedef struct _UNICODE_STRING
{
	USHORT Length;
	USHORT MaximumLength;
	PWSTR Buffer;
} UNICODE_STRING, *PUNICODE_STRING;

typedef struct _OBJECT_TYPE_INFORMATION
{
	UNICODE_STRING TypeName;
	ULONG TotalNumberOfObjects;
	ULONG TotalNumberOfHandles;
	ULONG TotalPagedPoolUsage;
	ULONG TotalNonPagedPoolUsage;
	ULONG TotalNamePoolUsage;
	ULONG TotalHandleTableUsage;
	ULONG HighWaterNumberOfObjects;
	ULONG HighWaterNumberOfHandles;
	ULONG HighWaterPagedPoolUsage;
	ULONG HighWaterNonPagedPoolUsage;
	ULONG HighWaterNamePoolUsage;
	ULONG HighWaterHandleTableUsage;
	ULONG InvalidAttributes;
	GENERIC_MAPPING GenericMapping;
	ULONG ValidAccessMask;
	BOOLEAN SecurityRequired;
	BOOLEAN MaintainHandleCount;
	ULONG PoolType;
	ULONG DefaultPagedPoolCharge;
	ULONG DefaultNonPagedPoolCharge;
} OBJECT_TYPE_INFORMATION, *POBJECT_TYPE_INFORMATION;



class CProcHandles
{
public:
	CProcHandles(void);
	~CProcHandles(void);

public:
	BOOL GetUndocumentedFunctionAddress();
	BOOL QueryHandleInfomation(DWORD PID=-1);
private:
	_NtQuerySystemInformation m_pfunNtQuerySystemInformation;
	_NtQueryObject m_pfunNtQueryObject;
};


 

#include "StdAfx.h"
#include "ProcHandles.h"

#define ONEPAGESIZE 0x1000

CProcHandles::CProcHandles(void)
{
}


CProcHandles::~CProcHandles(void)
{
}

BOOL CProcHandles::GetUndocumentedFunctionAddress()
{
	m_pfunNtQuerySystemInformation=(_NtQuerySystemInformation)GetProcAddress(
		GetModuleHandle(_T("ntdll.dll")),
		"NtQuerySystemInformation");

	m_pfunNtQueryObject=(_NtQueryObject)GetProcAddress(
		GetModuleHandle(_T("ntdll.dll")),
		"NtQueryObject");

	return (m_pfunNtQuerySystemInformation!=NULL && m_pfunNtQueryObject!=NULL);
}

BOOL CProcHandles::QueryHandleInfomation(DWORD PID)
{
	PSYSTEM_HANDLE_INFORMATION pSysHandleInfo=NULL;
	size_t HandleInfoSize=0x1000;  //4K
	NTSTATUS NtStatus;
	pSysHandleInfo=(PSYSTEM_HANDLE_INFORMATION)malloc(HandleInfoSize);

	do 
	{
		NtStatus=m_pfunNtQuerySystemInformation(SystemHandleInformation,
			pSysHandleInfo,HandleInfoSize,NULL);

		if (NtStatus==STATUS_INFO_LENGTH_MISMATCH)
		{
			HandleInfoSize*=2;
			pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION)realloc(pSysHandleInfo, HandleInfoSize);
		}
		else
		{
			break;
		}
	} while (TRUE);

	for (int i=0;i<pSysHandleInfo->HandleCount;i++)
	{
		PSYSTEM_HANDLE SystemHandle=&pSysHandleInfo->Handles[i];
		if (SystemHandle->ProcessId==PID)
		{
			//HANDLE DuplicatedHandle = NULL;
			//if(!DuplicateHandle(GetCurrentProcess(),
			//	(HANDLE)SystemHandle->Handle,
			//	GetCurrentProcess(),
			//	&DuplicatedHandle,0,FALSE,0))
			//{
			//	CString strMsg;
			//	strMsg.Format(_T("DuplicateHandle failed. code=%x\n"),GetLastError());
			//	::OutputDebugString((LPCTSTR)strMsg);
			//	continue;
			//}

			 /* Query the object type. */
			POBJECT_TYPE_INFORMATION objectTypeInfo = (POBJECT_TYPE_INFORMATION)malloc(ONEPAGESIZE);
			NtStatus = m_pfunNtQueryObject((HANDLE)SystemHandle->Handle,
				ObjectTypeInformation,
				objectTypeInfo,
				ONEPAGESIZE,
				NULL
				);

			if(NtStatus!=STATUS_SUCCESS)
			{
				CString strMsg;
				strMsg.Format(_T("[%#x] Error!, NtQueryObject return %x"),SystemHandle->Handle, NtStatus);
				//CloseHandle(DuplicatedHandle);
				continue;
			}

			 /* Query the object name (unless it has an access of 
				0x0012019f, on which NtQueryObject could hang. */
			if (SystemHandle->GrantedAccess == 0x0012019F)
			{
				/* We have the type, so display that. */
				CString strMsg;
				strMsg.Format(_T("[%#x] %s: (did not get name)\n"),SystemHandle->Handle,objectTypeInfo->TypeName.Buffer);
				::OutputDebugString((LPCTSTR)strMsg);
				free(objectTypeInfo);
				//CloseHandle(DuplicatedHandle);
				continue;
			}

			PVOID objectNameInfo;
			objectNameInfo = malloc(ONEPAGESIZE);
			ULONG retLength;
			if (m_pfunNtQueryObject((HANDLE)SystemHandle->Handle,ObjectNameInformation,objectNameInfo,ONEPAGESIZE,&retLength)!=STATUS_SUCCESS)
			{
				objectNameInfo = realloc(objectNameInfo,retLength);

				if (m_pfunNtQueryObject((HANDLE)SystemHandle->Handle,ObjectNameInformation,objectNameInfo,ONEPAGESIZE,&retLength)!=STATUS_SUCCESS)
				{
					/* We have the type name, so just display that. */
					CString strMsg;
					strMsg.Format(_T("[%#x] %s: (could not get name)\n"),SystemHandle->Handle,objectTypeInfo->TypeName.Buffer);
					::OutputDebugString((LPCTSTR)strMsg);

					free(objectTypeInfo);
					free(objectNameInfo);
					//CloseHandle(DuplicatedHandle);
					continue;
				}
			}

			/* Cast our buffer into an UNICODE_STRING. */
			UNICODE_STRING objectName;
			objectName = *(PUNICODE_STRING)objectNameInfo;

			/* Print the information! */
			if (objectName.Length)
			{
				/* The object has a name. */
				CString strMsg;
				strMsg.Format(_T("[%#x] %s: %s\n"),SystemHandle->Handle,objectTypeInfo->TypeName.Buffer,objectName.Buffer);
				::OutputDebugString((LPCTSTR)strMsg);
			}
			else
			{
				/* Print something else. */
				CString strMsg;
				strMsg.Format(_T("[%#x] %s: (unnamed)\n"),SystemHandle->Handle,objectTypeInfo->TypeName.Buffer);
				::OutputDebugString((LPCTSTR)strMsg);
			}

			CString strType=objectTypeInfo->TypeName.Buffer;
			if (strType.CompareNoCase(_T("Key"))==0)
			{
				//CString strName=objectName.Buffer;
				//if (strName.CompareNoCase(_T("\\REGISTRY\\MACHINE\\SOFTWARE\\Wow6432Node"))==0)
				//{
				//	CloseHandle((HANDLE)SystemHandle->Handle);
				//}

				//CloseHandle((HANDLE)SystemHandle->Handle);
			}

			free(objectTypeInfo);
			free(objectNameInfo);
			//CloseHandle(DuplicatedHandle);
		}
	}

	free(pSysHandleInfo);

	return TRUE;
}


1. 本人写的和人家的源代码有点区别,我并没有复制句柄,但是觉得这样写是有道理的,防止程序其它部分代码关闭句柄后,导致查询句柄信息失败。

2. 我最开始想不管三七二十一把所有的注册表句柄都关闭,这样做从逻辑上是不正确的,例如程序的例程A刚刚创建注册表句柄,还没使用,就被运行在其它线程中的这段代码关闭,造成异常。另外我还发现,把所有的注册表句柄都关闭,其中包括一个句柄名称为HKLM的句柄,关闭这个句柄后,会导致后继的操作

RegOpenKeyEx(HKEY_LOCAL_MACHINE,_T("Software"),0,KEY_READ,&hKey)失败,失败代码为ERROR_INVALID_HANDLE。

所以最后我还是匹配了句柄类型,句柄名称(匹配\Registry\HKLM\Microsoft\CTF\AssemblyItem),句柄存在时长等条件去关闭注册表句柄。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值