Process Hacker
hook.c
Go to the documentation of this file.
1 /*
2  * Process Hacker Window Explorer -
3  * hook procedure
4  *
5  * Copyright (C) 2011 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 /*
24  * Window Explorer uses a hook procedure in order to get window procedure
25  * and other information that can't be retrieved using GetWindowLongPtr.
26  * Because WindowExplorer.dll needs to be loaded into processes other
27  * than Process Hacker, both ProcessHacker.exe and comctl32.dll are set as
28  * delay-loaded DLLs. The other DLLs that we depend on (gdi32.dll,
29  * kernel32.dll, ntdll.dll, user32.dll) are all guaranteed to be already
30  * loaded whenever WindowExplorer.dll needs to be loaded.
31  */
32 
33 #include "wndexp.h"
34 
36  VOID
37  );
38 
39 BOOLEAN WepOpenServerObjects(
40  VOID
41  );
42 
44  VOID
45  );
46 
48  _In_ HWND hwnd
49  );
50 
51 LRESULT CALLBACK WepCallWndProc(
52  _In_ int nCode,
53  _In_ WPARAM wParam,
54  _In_ LPARAM lParam
55  );
56 
57 // Shared
63 // Server
64 HHOOK WeHookHandle = NULL;
65 // The current message ID is used to detect out-of-sync clients.
67 
68 // Server
69 
71  VOID
72  )
73 {
74  if (WeHookHandle)
75  return;
76 
77  WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME);
78 
80  return;
81 
82  WeHookHandle = SetWindowsHookEx(WH_CALLWNDPROC, WepCallWndProc, PluginInstance->DllBase, 0);
83 }
84 
86  VOID
87  )
88 {
89  if (WeHookHandle)
90  {
91  UnhookWindowsHookEx(WeHookHandle);
92  WeHookHandle = NULL;
93  }
94 }
95 
97  VOID
98  )
99 {
100  OBJECT_ATTRIBUTES objectAttributes;
101  WCHAR buffer[256];
102  UNICODE_STRING objectName;
103  SECURITY_DESCRIPTOR securityDescriptor;
104  UCHAR saclBuffer[sizeof(ACL) + FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)];
105  PACL sacl;
106  UCHAR mandatoryLabelAceBuffer[FIELD_OFFSET(SYSTEM_MANDATORY_LABEL_ACE, SidStart) + FIELD_OFFSET(SID, SubAuthority) + sizeof(ULONG)];
107  PSYSTEM_MANDATORY_LABEL_ACE mandatoryLabelAce;
108  PSID sid;
109 
111  {
112  LARGE_INTEGER maximumSize;
113 
115  InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
116  maximumSize.QuadPart = sizeof(WE_HOOK_SHARED_DATA);
117 
120  SECTION_ALL_ACCESS,
121  &objectAttributes,
122  &maximumSize,
123  PAGE_READWRITE,
124  SEC_COMMIT,
125  NULL
126  )))
127  {
128  return FALSE;
129  }
130  }
131 
132  if (!WeServerSharedData)
133  {
134  PVOID viewBase;
135  SIZE_T viewSize;
136 
137  viewBase = NULL;
138  viewSize = sizeof(WE_HOOK_SHARED_DATA);
139 
142  NtCurrentProcess(),
143  &viewBase,
144  0,
145  0,
146  NULL,
147  &viewSize,
148  ViewShare,
149  0,
150  PAGE_READWRITE
151  )))
152  {
154  return FALSE;
155  }
156 
157  WeServerSharedData = viewBase;
158  }
159 
161  {
163  InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
164 
165  if (!NT_SUCCESS(NtCreateMutant(
167  MUTANT_ALL_ACCESS,
168  &objectAttributes,
169  FALSE
170  )))
171  {
173  return FALSE;
174  }
175  }
176 
178  {
180  InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
181 
182  if (!NT_SUCCESS(NtCreateEvent(
184  EVENT_ALL_ACCESS,
185  &objectAttributes,
187  FALSE
188  )))
189  {
191  return FALSE;
192  }
193  }
194 
195  // If mandatory labels are supported, set it to the lowest possible level.
197  {
198  static SID_IDENTIFIER_AUTHORITY mandatoryLabelAuthority = SECURITY_MANDATORY_LABEL_AUTHORITY;
199 
200  RtlCreateSecurityDescriptor(&securityDescriptor, SECURITY_DESCRIPTOR_REVISION);
201 
202  sacl = (PACL)saclBuffer;
203  RtlCreateAcl(sacl, sizeof(saclBuffer), ACL_REVISION);
204 
205  mandatoryLabelAce = (PSYSTEM_MANDATORY_LABEL_ACE)mandatoryLabelAceBuffer;
206  mandatoryLabelAce->Header.AceType = SYSTEM_MANDATORY_LABEL_ACE_TYPE;
207  mandatoryLabelAce->Header.AceFlags = 0;
208  mandatoryLabelAce->Header.AceSize = sizeof(mandatoryLabelAceBuffer);
209  mandatoryLabelAce->Mask = SYSTEM_MANDATORY_LABEL_NO_WRITE_UP;
210 
211  sid = (PSID)&mandatoryLabelAce->SidStart;
212  RtlInitializeSid(sid, &mandatoryLabelAuthority, 1);
213  *RtlSubAuthoritySid(sid, 0) = SECURITY_MANDATORY_LOW_RID;
214 
215  if (NT_SUCCESS(RtlAddAce(sacl, ACL_REVISION, MAXULONG32, mandatoryLabelAce, sizeof(mandatoryLabelAceBuffer))))
216  {
217  if (NT_SUCCESS(RtlSetSaclSecurityDescriptor(&securityDescriptor, TRUE, sacl, FALSE)))
218  {
219  NtSetSecurityObject(WeServerSharedSection, LABEL_SECURITY_INFORMATION, &securityDescriptor);
220  NtSetSecurityObject(WeServerSharedSectionLock, LABEL_SECURITY_INFORMATION, &securityDescriptor);
221  NtSetSecurityObject(WeServerSharedSectionEvent, LABEL_SECURITY_INFORMATION, &securityDescriptor);
222  }
223  }
224  }
225 
226  return TRUE;
227 }
228 
230  VOID
231  )
232 {
233  OBJECT_ATTRIBUTES objectAttributes;
234  WCHAR buffer[256];
235  UNICODE_STRING objectName;
236 
238  {
240  InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
241 
244  SECTION_ALL_ACCESS,
245  &objectAttributes
246  )))
247  {
248  return FALSE;
249  }
250  }
251 
252  if (!WeServerSharedData)
253  {
254  PVOID viewBase;
255  SIZE_T viewSize;
256 
257  viewBase = NULL;
258  viewSize = sizeof(WE_HOOK_SHARED_DATA);
259 
262  NtCurrentProcess(),
263  &viewBase,
264  0,
265  0,
266  NULL,
267  &viewSize,
268  ViewShare,
269  0,
270  PAGE_READWRITE
271  )))
272  {
274  return FALSE;
275  }
276 
277  WeServerSharedData = viewBase;
278  }
279 
281  {
283  InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
284 
285  if (!NT_SUCCESS(NtOpenMutant(
287  MUTANT_ALL_ACCESS,
288  &objectAttributes
289  )))
290  {
292  return FALSE;
293  }
294  }
295 
297  {
299  InitializeObjectAttributes(&objectAttributes, &objectName, OBJ_CASE_INSENSITIVE, NULL, NULL);
300 
301  if (!NT_SUCCESS(NtOpenEvent(
303  EVENT_ALL_ACCESS,
304  &objectAttributes
305  )))
306  {
308  return FALSE;
309  }
310  }
311 
312  return TRUE;
313 }
314 
316  VOID
317  )
318 {
320  {
321  NtClose(WeServerSharedSection);
322  WeServerSharedSection = NULL;
323  }
324 
325  if (WeServerSharedData)
326  {
327  NtUnmapViewOfSection(NtCurrentProcess(), WeServerSharedData);
328  WeServerSharedData = NULL;
329  }
330 
332  {
333  NtClose(WeServerSharedSectionLock);
335  }
336 
338  {
341  }
342 }
343 
345  VOID
346  )
347 {
348  if (WepOpenServerObjects())
349  {
351 
352  return TRUE;
353  }
354  else
355  {
356  return FALSE;
357  }
358 }
359 
361  _Out_ PWE_HOOK_SHARED_DATA *Data
362  )
363 {
364  LARGE_INTEGER timeout;
365 
367  return FALSE;
368 
369  timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS;
370 
371  if (NtWaitForSingleObject(WeServerSharedSectionLock, FALSE, &timeout) != WAIT_OBJECT_0)
372  return FALSE;
373 
374  *Data = WeServerSharedData;
375 
376  return TRUE;
377 }
378 
380  VOID
381  )
382 {
383  NtReleaseMutant(WeServerSharedSectionLock, NULL);
384 }
385 
387  _In_ HWND hWnd
388  )
389 {
390  ULONG threadId;
391  ULONG processId;
392  LARGE_INTEGER timeout;
393 
394  if (!WeServerSharedData || !WeServerSharedSectionEvent)
395  return FALSE;
396 
397  threadId = GetWindowThreadProcessId(hWnd, &processId);
398 
399  if (UlongToHandle(processId) == NtCurrentProcessId())
400  {
401  // We are trying to get information about the server. Call the procedure directly.
402  WepWriteClientData(hWnd);
403  return TRUE;
404  }
405 
406  // Call the client and wait for the client to finish.
407 
409  WeServerSharedData->MessageId = WeCurrentMessageId;
410  NtResetEvent(WeServerSharedSectionEvent, NULL);
411 
412  if (!SendNotifyMessage(hWnd, WeServerMessage, (WPARAM)NtCurrentProcessId(), WeCurrentMessageId))
413  return FALSE;
414 
415  timeout.QuadPart = -WE_CLIENT_MESSAGE_TIMEOUT * PH_TIMEOUT_MS;
416 
417  if (NtWaitForSingleObject(WeServerSharedSectionEvent, FALSE, &timeout) != STATUS_WAIT_0)
418  return FALSE;
419 
420  return TRUE;
421 }
422 
423 // Client
424 
426  VOID
427  )
428 {
429  WeServerMessage = RegisterWindowMessage(WE_SERVER_MESSAGE_NAME);
430 }
431 
433  VOID
434  )
435 {
436  NOTHING;
437 }
438 
440  _In_ HWND hwnd
441  )
442 {
443  WCHAR className[256];
444  LOGICAL isUnicode;
445 
446  memset(&WeServerSharedData->c, 0, sizeof(WeServerSharedData->c));
447  isUnicode = IsWindowUnicode(hwnd);
448 
449  if (isUnicode)
450  {
451  WeServerSharedData->c.WndProc = GetWindowLongPtrW(hwnd, GWLP_WNDPROC);
452  WeServerSharedData->c.DlgProc = GetWindowLongPtrW(hwnd, DWLP_DLGPROC);
453  }
454  else
455  {
456  WeServerSharedData->c.WndProc = GetWindowLongPtrA(hwnd, GWLP_WNDPROC);
457  WeServerSharedData->c.DlgProc = GetWindowLongPtrA(hwnd, DWLP_DLGPROC);
458  }
459 
460  if (!GetClassName(hwnd, className, sizeof(className) / sizeof(WCHAR)))
461  className[0] = 0;
462 
463  WeServerSharedData->c.ClassInfo.cbSize = sizeof(WNDCLASSEX);
464  GetClassInfoEx(NULL, className, &WeServerSharedData->c.ClassInfo);
465 
466  if (isUnicode)
467  WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrW(hwnd, GCLP_WNDPROC);
468  else
469  WeServerSharedData->c.ClassInfo.lpfnWndProc = (PVOID)GetClassLongPtrA(hwnd, GCLP_WNDPROC);
470 }
471 
472 LRESULT CALLBACK WepCallWndProc(
473  _In_ int nCode,
474  _In_ WPARAM wParam,
475  _In_ LPARAM lParam
476  )
477 {
478  LRESULT result;
479  PCWPSTRUCT info;
480 
481  result = CallNextHookEx(NULL, nCode, wParam, lParam);
482 
483  info = (PCWPSTRUCT)lParam;
484 
485  if (info->message == WeServerMessage)
486  {
487  HANDLE serverProcessId;
488  ULONG messageId;
489 
490  serverProcessId = (HANDLE)info->wParam;
491  messageId = (ULONG)info->lParam;
492 
493  if (serverProcessId != NtCurrentProcessId())
494  {
495  if (WepOpenServerObjects())
496  {
497  if (WeServerSharedData->MessageId == messageId)
498  {
499  WepWriteClientData(info->hwnd);
500  NtSetEvent(WeServerSharedSectionEvent, NULL);
501  }
502 
504  }
505  }
506  }
507 
508  return result;
509 }