Once you want to see the objects in you computer. The most important is the Mutants and the Events. But how to enumerate all the object in you computer. Sorry about that there is no easy way to get these information.
After research a while, I found the un-documented API from NTDLL.dll. There are some functions can do this work. So, I export by using LoadLibrary and GetProcAddress.
Please reference the code as following.
The following is the prototype definition:
#pragma once #include <string> #include <map> #include <vector> using namespace std; #ifndef NtCurrentProcess #define NtCurrentProcess() ((HANDLE)0xFFFFFFFF) #endif /* NtCurrentProcess */ #ifndef NtCurrentThread #define NtCurrentThread() ((HANDLE)0xFFFFFFFE) #endif /* NtCurrentThread */ #ifndef NT_SUCCESS #define NT_SUCCESS(x) ((x)>=0) #define STATUS_SUCCESS ((NTSTATUS)0) #endif #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS)0xC0000004) #define DUPLICATE_SAME_ATTRIBUTES 0x00000004 typedef DWORD ULONG; typedef WORD USHORT; typedef ULONG NTSTATUS; /////////////////////////////////////////////////// typedef enum _SYSTEM_INFORMATION_CLASS { SystemHandleInformation = 16, } SYSTEM_INFORMATION_CLASS, * PSYSTEM_INFORMATION_CLASS; typedef struct _UNICODE_STRING { USHORT Length; USHORT MaximumLength; PWSTR Buffer; } UNICODE_STRING, * PUNICODE_STRING; typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO { USHORT UniqueProcessId; USHORT CreatorBackTraceIndex; UCHAR ObjectTypeIndex; UCHAR HandleAttributes; USHORT HandleValue; PVOID Object; ULONG GrantedAccess; } SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO; typedef struct _SYSTEM_HANDLE_INFORMATION { ULONG ProcessId; UCHAR ObjectTypeNumber; UCHAR Flags; USHORT Handle; PVOID Object; ACCESS_MASK GrantedAccess; } SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION; typedef struct _OBJECT_BASIC_INFORMATION { ULONG Attributes; ACCESS_MASK GrantedAccess; ULONG HandleCount; ULONG PointerCount; ULONG PagedPoolUsage; ULONG NonPagedPoolUsage; ULONG Reserved[3]; ULONG NameInformationLength; ULONG TypeInformationLength; ULONG SecurityDescriptorLength; LARGE_INTEGER CreateTime; } OBJECT_BASIC_INFORMATION, * POBJECT_BASIC_INFORMATION; 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; typedef enum _OBJECT_INFORMATION_CLASS { ObjectBasicInformation, ObjectNameInformation, ObjectTypeInformation, ObjectAllInformation, ObjectDataInformation } OBJECT_INFORMATION_CLASS, * POBJECT_INFORMATION_CLASS; typedef struct _OBJECT_NAME_INFORMATION { UNICODE_STRING Name; } OBJECT_NAME_INFORMATION, * POBJECT_NAME_INFORMATION; typedef NTSTATUS (NTAPI* PZwQuerySystemInformation)(IN ULONG SystemInformationClass, OUT PVOID SystemInformation, IN ULONG Length, OUT PULONG ResultLength); typedef NTSTATUS (NTAPI* PZwDuplicateObject)(IN HANDLE SourceProcessHandle, IN HANDLE SourceHandle, IN HANDLE TargetProcessHandle, OUT PHANDLE TargetHandle, IN ACCESS_MASK DesiredAccess, IN ULONG HandleAttributes, IN ULONG Options); typedef NTSTATUS (NTAPI* PZwQueryObject)(IN HANDLE ObjectHandle, IN OBJECT_INFORMATION_CLASS ObjectInformationClass, OUT PVOID ObjectInformation, IN ULONG Length, OUT PULONG ResultLength OPTIONAL); typedef NTSTATUS (WINAPI *pFnRtlAdjustPrivilege)(ULONG Privilege, BOOLEAN Enable, BOOLEAN CurrentThread, PBOOLEAN Enabled); typedef struct _ProcessInformation { DWORD dwPID; // Process ID wstring strProcessName; // Process Name wstring strProcessImagePath; // Process Image file path HANDLE handle; wstring EventName; // Event Name wstring MutexName; // Mutex Name } ProcessInformation; class CInformer { public: CInformer(void); ~CInformer(void); void GetProcessInformation(vector<ProcessInformation>& vecPI); wstring GetProcessNameByID(DWORD pid); private: BOOL setPrivilege(HANDLE hToken, LPCTSTR szPrivilege, BOOL bOk); vector<ProcessInformation> m_vecInformer; };
The following is the implementing file content.
#include "StdAfx.h" #include "Informer.h" #include <Tlhelp32.h> namespace { PZwQuerySystemInformation ZwQuerySystemInformation = NULL; PZwDuplicateObject ZwDuplicateObject = NULL; PZwQueryObject ZwQueryObject = NULL; pFnRtlAdjustPrivilege RtlAdjustPrivilege = NULL; } CInformer::CInformer(void) { if(!(ZwQuerySystemInformation = (PZwQuerySystemInformation)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "ZwQuerySystemInformation"))) { ASSERT(FALSE); } if(!(ZwDuplicateObject = (PZwDuplicateObject)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "ZwDuplicateObject"))) { ASSERT(FALSE); } if(!(ZwQueryObject = (PZwQueryObject)GetProcAddress(GetModuleHandle(_T("ntdll.dll")), "ZwQueryObject"))) { ASSERT(FALSE); } BOOL bRet = FALSE; HANDLE hToken; bRet = OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken); if(!bRet) { ASSERT(FALSE); } bRet = setPrivilege(hToken, SE_DEBUG_NAME, TRUE); if(!bRet) { ASSERT(FALSE); } } CInformer::~CInformer(void) { } BOOL CInformer::setPrivilege(HANDLE hToken, LPCTSTR szPrivilege, BOOL bOk) { BOOL bRet = FALSE; LUID luid; TOKEN_PRIVILEGES tp; bRet = LookupPrivilegeValue(NULL, szPrivilege, &luid); if(!bRet) { return bRet; } tp.PrivilegeCount = 1; if(bOk) { tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; } else { tp.Privileges[0].Attributes = NULL; } bRet = AdjustTokenPrivileges(hToken, FALSE, &tp, sizeof(TOKEN_PRIVILEGES), (PTOKEN_PRIVILEGES)NULL, (PDWORD)NULL); if(!bRet) { return bRet; } return TRUE; } wstring CInformer::GetProcessNameByID(DWORD pid) { HANDLE hSnapshot; PROCESSENTRY32 pe; BOOL fFound = FALSE; pe.dwSize = sizeof(PROCESSENTRY32); hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); if(hSnapshot != NULL) { fFound = Process32First(hSnapshot, &pe); while(fFound) { if(pid == pe.th32ProcessID) { CloseHandle(hSnapshot); return pe.szExeFile; } fFound = Process32Next(hSnapshot, &pe); } CloseHandle(hSnapshot); } return L""; } void CInformer::GetProcessInformation(vector<ProcessInformation>& vecPI) { ULONG n = 0x4000; PULONG p = new ULONG[n]; // Get all system information from system handles while(ZwQuerySystemInformation(SystemHandleInformation, p, n* sizeof * p, 0) == STATUS_INFO_LENGTH_MISMATCH) { delete [] p; p = new ULONG[n *= 2]; } // indicate the array to a handle information structure PSYSTEM_HANDLE_INFORMATION h = PSYSTEM_HANDLE_INFORMATION(p + 1); // Query handle information for(ULONG i = 0; i < * p; i++) { HANDLE hProcess; // if the process is system process, ingore it. if(h[i].ProcessId == 0 || h[i].ProcessId == 4 || (hProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, h[i].ProcessId)) == NULL) continue; DWORD dwQueryPID = h[i].ProcessId; HANDLE hObject; if(ZwDuplicateObject(hProcess, HANDLE(h[i].Handle), NtCurrentProcess(), &hObject, 0, 0, DUPLICATE_SAME_ATTRIBUTES) != STATUS_SUCCESS) { continue; } OBJECT_BASIC_INFORMATION obi; ZwQueryObject(hObject, ObjectBasicInformation, &obi, sizeof obi, &n); n = obi.TypeInformationLength + 2; // extend the length to get the type name POBJECT_TYPE_INFORMATION oti = (POBJECT_TYPE_INFORMATION) (new char[n]); ZwQueryObject(hObject, ObjectTypeInformation, oti, n, &n); n = obi.NameInformationLength == 0 ? MAX_PATH* sizeof(WCHAR): obi.NameInformationLength; POBJECT_NAME_INFORMATION oni = (POBJECT_NAME_INFORMATION) (new char[n]); NTSTATUS rv = ZwQueryObject(hObject, ObjectNameInformation, oni, n, &n); if(oni[0].Name.Buffer == NULL || wcscmp(oni[0].Name.Buffer, L"") == 0) { delete [] (char*)oti; delete [] (char*)oni; continue; } ProcessInformation pi; if(wcscmp(oti[0].TypeName.Buffer, L"Event") != 0 && wcscmp(oti[0].TypeName.Buffer, L"Mutant") != 0) { goto clean; } if(wcscmp(oti[0].TypeName.Buffer, L"") == 0) goto clean; if(wcscmp(oti[0].TypeName.Buffer, L"Event") == 0) { pi.EventName = oni[0].Name.Buffer; } else if(wcscmp(oti[0].TypeName.Buffer, L"Mutant") == 0) { pi.MutexName = oni[0].Name.Buffer; } pi.handle = HANDLE(h[i].Handle); pi.dwPID = h[i].ProcessId; pi.strProcessName = GetProcessNameByID(h[i].ProcessId); vecPI.push_back(pi); clean: delete [] (char*)oti; delete [] (char*)oni; } delete [] p; }
After calling Informer::GetProcessInformation, you can get the Mutex and Events in your computer.