2010年5月31日 星期一

How to get the named Mutex and Event in your system.

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.

沒有留言: