获取进程打开的互斥量

最近有个任务涉及到区分【同进程名进程】,所以想到了用进程”拥有”的互斥量来区分这些进程。所以下面实现了获取指定进程”拥有”哪些互斥量的方法,当然这种方法也适合各种内核对象(FILE、REG…)。

1. 使用NtQuerySystemInformation检索SystemHandleInformation(16)即可获得系统中所有的句柄信息:

通过SystemHandleInformation检索到的系统中所有句柄的数据结构是这样定义的:

1
2
3
4
5
typedef struct _SYSTEM_HANDLE_INFORMATION
{
  ULONG HandleCount;
  SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
} SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;

其中SYSTEM_HANDLE_TABLE_ENTRY_INFO是一个句柄信息的数据结构

1
2
3
4
5
6
7
8
9
typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
  ULONG ProcessId;
  BYTE ObjectTypeNumber;
  BYTE Flags;
  USHORT Handle;
  PVOID Object;
  ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
2. 将句柄复制到当前进程

想要获取一个句柄的详细信息,必须将其拷贝到当前进程,对于一个句柄数据类型:SYSTEM_HANDLE_TABLE_ENTRY_INFO,我们可以使用其第四个成员Handle,然后使用DuplicateHandle将这个句柄复制到当前进程。

3. 获取句柄的类型信息

由2中获取的复制到当前进程的句柄,调用函数NtQueryObject,指定获取ObjectNameInformation(1)即可获取句柄的类型信息,获取到的句柄的类型信息结构是这样的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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;

其中第一个成员TypeName即是句柄类型的类型名

4. 获取句柄的名字

调用函数NtQueryObject,指定获取ObjectNameInformation即可获取句柄的类型信息,获取到的句柄的名字数据结构是UNICODE_STRING类型。

5. 找到当前进程占有的互斥量

由获取的句柄的类型信息和句柄所在的进程ID,即可找到当前进程拥有的互斥量,同时我们也得到了互斥量的名字。

完整代码如下:

WIN7/VS2010 (get_process_mutex.cpp) download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
#include "stdafx.h"
#include <functional>
#include <Windows.h>
#include <winternl.h>
#include <vector>
#include <ntstatus.h>
#include <iostream>

// NtQueryObject枚举出的内核对象的类型信息的结构
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 struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
{
  ULONG ProcessId;
  BYTE ObjectTypeNumber;
  BYTE Flags;
  USHORT Handle;
  PVOID Object;
  ACCESS_MASK GrantedAccess;
} SYSTEM_HANDLE_TABLE_ENTRY_INFO, *PSYSTEM_HANDLE_TABLE_ENTRY_INFO;

// 获取一个句柄的详细信息
// 可以获取类型名和内核对象的名字
// bType - 获取句柄的类型名
std::wstring QueryHandleNameInfo(HANDLE handle, BOOL bType)
{
  std::wstring strName;
  const HMODULE hDll = LoadLibrary(_T("ntdll.dll"));
  if (hDll == NULL)
  {
      return strName;
  }
  typedef NTSTATUS (NTAPI *NtQueryObjectFunc)(HANDLE, OBJECT_INFORMATION_CLASS, PVOID, ULONG, PULONG);
  NtQueryObjectFunc NtQueryObject_ = (NtQueryObjectFunc)GetProcAddress(hDll, "NtQueryObject");

  do
  {
      if (NtQueryObject_ == NULL )
      {
          break;
      }
      // 获取信息
      const DWORD ObjectNameInformation = 1;
      OBJECT_INFORMATION_CLASS infoType = bType ? ObjectTypeInformation :
                                                            OBJECT_INFORMATION_CLASS(ObjectNameInformation);
      std::vector<BYTE> objVec(256);
      ULONG bytesOfRead = 0;  
      NTSTATUS status = STATUS_UNSUCCESSFUL;
      do
      {
          status = NtQueryObject_(handle, infoType, (void*)objVec.data(), objVec.size(), &bytesOfRead);
          if (STATUS_INFO_LENGTH_MISMATCH == status)
          {
              objVec.resize(objVec.size() * 2);
              continue;
          }
          break;
      } while (TRUE);
      if (!NT_SUCCESS(status))
      {
          break;
      }
      objVec.resize(bytesOfRead);

      if (bType)
      {
          const OBJECT_TYPE_INFORMATION *pObjType =
                                                       reinterpret_cast<OBJECT_TYPE_INFORMATION*>(objVec.data());
          strName = std::wstring(pObjType->TypeName.Buffer, pObjType->TypeName.Length / sizeof(WCHAR));
      }
      else
      {
          const UNICODE_STRING *pObjName = reinterpret_cast<UNICODE_STRING*>(objVec.data());
          strName = std::wstring(pObjName->Buffer, pObjName->Length / sizeof(WCHAR));
      }

  } while (FALSE);

  FreeLibrary(hDll);
  return strName;
}

// 遍历句柄辅助类
class WalkHandleHelper
{
public:
  WalkHandleHelper(const SYSTEM_HANDLE_TABLE_ENTRY_INFO& handleInfo, const HANDLE& handle)
        :m_HandleInfo(handleInfo), m_Handle(handle){}
  DWORD GetProcessID() const {return m_HandleInfo.ProcessId;}
  std::wstring GetTypeName() const
  {
      return QueryHandleNameInfo(m_Handle, TRUE);
  }
  std::wstring GetObjectName() const
  {
      return QueryHandleNameInfo(m_Handle, FALSE);
  }

private:
  const SYSTEM_HANDLE_TABLE_ENTRY_INFO& m_HandleInfo;
  const HANDLE& m_Handle;
};

// 枚举系统的句柄
void WalkHandle(const std::function<void(const WalkHandleHelper&)> &functor)
{
  const HMODULE hDll = LoadLibrary(_T("ntdll.dll"));
  if (hDll == NULL)
  {
      return;
  }

  // 使用NtQuerySystemInformation检索SystemHandleInformation(16)即可获得系统中所有的句柄信息
  const DWORD SystemHandleInformation = 16;        

  // 通过SystemHandleInformation检索到的系统中所有句柄的数据结构
  typedef struct _SYSTEM_HANDLE_INFORMATION
  {
      ULONG HandleCount;
      SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
  } SYSTEM_HANDLE_INFORMATION, *PSYSTEM_HANDLE_INFORMATION;


  typedef NTSTATUS (NTAPI *NtQuerySystemInformationFunc)(ULONG, PVOID, ULONG, PULONG);
  NtQuerySystemInformationFunc NtQuerySystemInformation_ = (NtQuerySystemInformationFunc)
                                                                 GetProcAddress(hDll, "NtQuerySystemInformation");
  const HANDLE hCurProcess = GetCurrentProcess();
  do
  {
      if (NULL == NtQuerySystemInformation_)
      {
          break;
      }
      // 获取系统句柄表
      std::vector<BYTE> vecData(512);
      ULONG bytesOfRead = 0;
      NTSTATUS status;
      do
      {
          status = NtQuerySystemInformation_(SystemHandleInformation, vecData.data(), vecData.size(), &bytesOfRead);
          if (STATUS_INFO_LENGTH_MISMATCH == status)
          {
              vecData.resize(vecData.size()*2);
              continue;
          }
          break;
      } while (TRUE);
      if (!NT_SUCCESS(status))
      {
          break;
      }
      vecData.resize(bytesOfRead);

      PSYSTEM_HANDLE_INFORMATION pSysHandleInfo = (PSYSTEM_HANDLE_INFORMATION)vecData.data();
      for (int i=0; i<pSysHandleInfo->HandleCount; ++i)
      {
          const HANDLE hOwnProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE,
                                                               pSysHandleInfo->Handles[i].ProcessId);
          if (NULL == hOwnProcess)
          {
              continue;
          }
          HANDLE hDuplicate = NULL;
          // 必须把Handle放入自己的进程中,否则无法获取其他进程拥有Handle的信息
          if (!DuplicateHandle(hOwnProcess, (HANDLE)pSysHandleInfo->Handles[i].Handle, hCurProcess,
                            &hDuplicate,0,0, DUPLICATE_SAME_ACCESS))
          {
              CloseHandle(hOwnProcess);
              continue;
          }
          WalkHandleHelper helper(pSysHandleInfo->Handles[i], hDuplicate);
          functor(helper);

          CloseHandle(hDuplicate);
          CloseHandle(hOwnProcess);
      }

  } while (FALSE);

  FreeLibrary(hDll);
}

// 枚举当前进程的互斥量
void EnumCurProcessMutex()
{
  std::wcout<<_T("Find The Mutex Opened By Current Process:")<<std::endl;
  const DWORD dwCurProcess = GetCurrentProcessId();
  WalkHandle([&](const WalkHandleHelper& helper)
  {
      const std::wstring strMutant(_T("Mutant"));
      if (helper.GetProcessID() == dwCurProcess && helper.GetTypeName().compare(strMutant) == 0)
      {            
          std::wcout<<_T("ObjectName: ")<<helper.GetObjectName().c_str()<<std::endl;
      }

  });
}

int _tmain(int argc, _TCHAR* argv[])
{
  CreateMutex(NULL, TRUE, NULL);
  CreateMutex(NULL, TRUE, _T("TestMutex"));
  CreateMutex(NULL, TRUE, _T("Global\\TestGlobalMutex"));
  EnumCurProcessMutex();
  return 0;
}