枚举进程句柄

来源:互联网 发布:淘宝给差评被砍死 编辑:程序博客网 时间:2024/06/09 14:30

目前正在做的项目进行性能测试,被通知进程句柄数已经到达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 0xC0000004typedef 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 0x1000CProcHandles::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;  //4KNTSTATUS 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 0
原创粉丝点击