Process Hacker
findobj.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * object search
4  *
5  * Copyright (C) 2010-2015 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 #include <phapp.h>
24 #include <emenu.h>
25 #include <kphuser.h>
26 #include <procprpp.h>
27 #include <windowsx.h>
28 
29 #define WM_PH_SEARCH_UPDATE (WM_APP + 801)
30 #define WM_PH_SEARCH_FINISHED (WM_APP + 802)
31 
33 {
38 
39 typedef struct _PHP_OBJECT_SEARCH_RESULT
40 {
41  HANDLE ProcessId;
42  PHP_OBJECT_RESULT_TYPE ResultType;
43 
44  HANDLE Handle;
45  PPH_STRING TypeName;
46  PPH_STRING Name;
47  PPH_STRING ProcessName;
48 
49  WCHAR HandleString[PH_PTR_STR_LEN_1];
50 
53 
54 INT_PTR CALLBACK PhpFindObjectsDlgProc(
55  _In_ HWND hwndDlg,
56  _In_ UINT uMsg,
57  _In_ WPARAM wParam,
58  _In_ LPARAM lParam
59  );
60 
62  _In_ PVOID Parameter
63  );
64 
67 static PH_LAYOUT_MANAGER WindowLayoutManager;
68 static RECT MinimumSize;
69 
70 static HANDLE SearchThreadHandle = NULL;
71 static BOOLEAN SearchStop;
72 static PPH_STRING SearchString;
73 static PPH_LIST SearchResults = NULL;
74 static ULONG SearchResultsAddIndex;
75 static PH_QUEUED_LOCK SearchResultsLock = PH_QUEUED_LOCK_INIT;
76 
77 static ULONG64 SearchPointer;
78 static BOOLEAN UseSearchPointer;
79 
81  VOID
82  )
83 {
85  {
86  PhFindObjectsWindowHandle = CreateDialog(
88  MAKEINTRESOURCE(IDD_FINDOBJECTS),
91  );
92  }
93 
94  if (!IsWindowVisible(PhFindObjectsWindowHandle))
95  ShowWindow(PhFindObjectsWindowHandle, SW_SHOW);
96 
97  SetForegroundWindow(PhFindObjectsWindowHandle);
98 }
99 
101  _In_ PPH_EMENU Menu,
102  _In_ PPHP_OBJECT_SEARCH_RESULT *Results,
103  _In_ ULONG NumberOfResults
104  )
105 {
106  BOOLEAN allCanBeClosed = TRUE;
107  ULONG i;
108 
109  if (NumberOfResults == 1)
110  {
111  PH_HANDLE_ITEM_INFO info;
112 
113  info.ProcessId = Results[0]->ProcessId;
114  info.Handle = Results[0]->Handle;
115  info.TypeName = Results[0]->TypeName;
116  info.BestObjectName = Results[0]->Name;
118  }
119  else
120  {
123  }
124 
125  for (i = 0; i < NumberOfResults; i++)
126  {
127  if (Results[i]->ResultType != HandleSearchResult)
128  {
129  allCanBeClosed = FALSE;
130  break;
131  }
132  }
133 
134  PhEnableEMenuItem(Menu, ID_OBJECT_CLOSE, allCanBeClosed);
135 }
136 
138  _In_ PVOID Item1,
139  _In_ PVOID Item2,
140  _In_opt_ PVOID Context
141  )
142 {
143  PPHP_OBJECT_SEARCH_RESULT item1 = Item1;
144  PPHP_OBJECT_SEARCH_RESULT item2 = Item2;
145  INT result;
146 
147  result = PhCompareStringWithNull(item1->ProcessName, item2->ProcessName, TRUE);
148 
149  if (result != 0)
150  return result;
151  else
152  return uintptrcmp((ULONG_PTR)item1->ProcessId, (ULONG_PTR)item2->ProcessId);
153 }
154 
156  _In_ PVOID Item1,
157  _In_ PVOID Item2,
158  _In_opt_ PVOID Context
159  )
160 {
161  PPHP_OBJECT_SEARCH_RESULT item1 = Item1;
162  PPHP_OBJECT_SEARCH_RESULT item2 = Item2;
163 
164  return PhCompareString(item1->TypeName, item2->TypeName, TRUE);
165 }
166 
168  _In_ PVOID Item1,
169  _In_ PVOID Item2,
170  _In_opt_ PVOID Context
171  )
172 {
173  PPHP_OBJECT_SEARCH_RESULT item1 = Item1;
174  PPHP_OBJECT_SEARCH_RESULT item2 = Item2;
175 
176  return PhCompareString(item1->Name, item2->Name, TRUE);
177 }
178 
180  _In_ PVOID Item1,
181  _In_ PVOID Item2,
182  _In_opt_ PVOID Context
183  )
184 {
185  PPHP_OBJECT_SEARCH_RESULT item1 = Item1;
186  PPHP_OBJECT_SEARCH_RESULT item2 = Item2;
187 
188  return uintptrcmp((ULONG_PTR)item1->Handle, (ULONG_PTR)item2->Handle);
189 }
190 
191 static INT_PTR CALLBACK PhpFindObjectsDlgProc(
192  _In_ HWND hwndDlg,
193  _In_ UINT uMsg,
194  _In_ WPARAM wParam,
195  _In_ LPARAM lParam
196  )
197 {
198  switch (uMsg)
199  {
200  case WM_INITDIALOG:
201  {
202  HWND lvHandle;
203 
204  PhCenterWindow(hwndDlg, GetParent(hwndDlg));
205  PhFindObjectsListViewHandle = lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS);
206 
207  PhInitializeLayoutManager(&WindowLayoutManager, hwndDlg);
208  PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDC_FILTER),
210  PhAddLayoutItem(&WindowLayoutManager, GetDlgItem(hwndDlg, IDOK),
212  PhAddLayoutItem(&WindowLayoutManager, lvHandle,
213  NULL, PH_ANCHOR_ALL);
214 
215  MinimumSize.left = 0;
216  MinimumSize.top = 0;
217  MinimumSize.right = 150;
218  MinimumSize.bottom = 100;
219  MapDialogRect(hwndDlg, &MinimumSize);
220 
221  PhRegisterDialog(hwndDlg);
222 
223  PhLoadWindowPlacementFromSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg);
224 
225  PhSetListViewStyle(lvHandle, TRUE, TRUE);
226  PhSetControlTheme(lvHandle, L"explorer");
227  PhAddListViewColumn(lvHandle, 0, 0, 0, LVCFMT_LEFT, 100, L"Process");
228  PhAddListViewColumn(lvHandle, 1, 1, 1, LVCFMT_LEFT, 100, L"Type");
229  PhAddListViewColumn(lvHandle, 2, 2, 2, LVCFMT_LEFT, 200, L"Name");
230  PhAddListViewColumn(lvHandle, 3, 3, 3, LVCFMT_LEFT, 80, L"Handle");
231 
232  PhSetExtendedListView(lvHandle);
238  PhLoadListViewColumnsFromSetting(L"FindObjListViewColumns", lvHandle);
239  }
240  break;
241  case WM_DESTROY:
242  {
243  PhSaveWindowPlacementToSetting(L"FindObjWindowPosition", L"FindObjWindowSize", hwndDlg);
245  }
246  break;
247  case WM_SHOWWINDOW:
248  {
249  SendMessage(hwndDlg, WM_NEXTDLGCTL, (WPARAM)GetDlgItem(hwndDlg, IDC_FILTER), TRUE);
250  Edit_SetSel(GetDlgItem(hwndDlg, IDC_FILTER), 0, -1);
251  }
252  break;
253  case WM_CLOSE:
254  {
255  ShowWindow(hwndDlg, SW_HIDE);
256  // IMPORTANT
257  // Set the result to 0 so the default dialog message
258  // handler doesn't invoke IDCANCEL, which will send
259  // WM_CLOSE, creating an infinite loop.
260  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, 0);
261  }
262  return TRUE;
263  case WM_SETCURSOR:
264  {
265  if (SearchThreadHandle)
266  {
267  SetCursor(LoadCursor(NULL, IDC_WAIT));
268  SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, TRUE);
269  return TRUE;
270  }
271  }
272  break;
273  case WM_COMMAND:
274  {
275  switch (LOWORD(wParam))
276  {
277  case IDOK:
278  {
279  // Don't continue if the user requested cancellation.
280  if (SearchStop)
281  break;
282 
283  if (!SearchThreadHandle)
284  {
285  ULONG i;
286 
287  // Cleanup previous results.
288 
289  ListView_DeleteAllItems(PhFindObjectsListViewHandle);
290 
291  if (SearchResults)
292  {
293  for (i = 0; i < SearchResults->Count; i++)
294  {
295  PPHP_OBJECT_SEARCH_RESULT searchResult = SearchResults->Items[i];
296 
297  PhDereferenceObject(searchResult->TypeName);
298  PhDereferenceObject(searchResult->Name);
299 
300  if (searchResult->ProcessName)
301  PhDereferenceObject(searchResult->ProcessName);
302 
303  PhFree(searchResult);
304  }
305 
306  PhDereferenceObject(SearchResults);
307  }
308 
309  // Start the search.
310 
311  SearchString = PhGetWindowText(GetDlgItem(hwndDlg, IDC_FILTER));
312  SearchResults = PhCreateList(128);
313  SearchResultsAddIndex = 0;
314 
315  SearchThreadHandle = PhCreateThread(0, PhpFindObjectsThreadStart, NULL);
316 
317  if (!SearchThreadHandle)
318  {
319  PhDereferenceObject(SearchString);
320  PhDereferenceObject(SearchResults);
321  SearchString = NULL;
322  SearchResults = NULL;
323  break;
324  }
325 
326  SetDlgItemText(hwndDlg, IDOK, L"Cancel");
327 
328  SetCursor(LoadCursor(NULL, IDC_WAIT));
329  }
330  else
331  {
332  SearchStop = TRUE;
333  EnableWindow(GetDlgItem(hwndDlg, IDOK), FALSE);
334  }
335  }
336  break;
337  case IDCANCEL:
338  {
339  SendMessage(hwndDlg, WM_CLOSE, 0, 0);
340  }
341  break;
342  case ID_OBJECT_CLOSE:
343  {
344  PPHP_OBJECT_SEARCH_RESULT *results;
345  ULONG numberOfResults;
346  ULONG i;
347 
350  &results,
351  &numberOfResults
352  );
353 
354  if (numberOfResults != 0 && PhShowConfirmMessage(
355  hwndDlg,
356  L"close",
357  numberOfResults == 1 ? L"the selected handle" : L"the selected handles",
358  L"Closing handles may cause system instability and data corruption.",
359  FALSE
360  ))
361  {
362  for (i = 0; i < numberOfResults; i++)
363  {
364  NTSTATUS status;
365  HANDLE processHandle;
366 
367  if (results[i]->ResultType != HandleSearchResult)
368  continue;
369 
370  if (NT_SUCCESS(status = PhOpenProcess(
371  &processHandle,
372  PROCESS_DUP_HANDLE,
373  results[i]->ProcessId
374  )))
375  {
376  if (NT_SUCCESS(status = PhDuplicateObject(
377  processHandle,
378  results[i]->Handle,
379  NULL,
380  NULL,
381  0,
382  0,
383  DUPLICATE_CLOSE_SOURCE
384  )))
385  {
388  }
389 
390  NtClose(processHandle);
391  }
392 
393  if (!NT_SUCCESS(status))
394  {
395  if (!PhShowContinueStatus(hwndDlg,
396  PhaFormatString(L"Unable to close \"%s\"", results[i]->Name->Buffer)->Buffer,
397  status,
398  0
399  ))
400  break;
401  }
402  }
403  }
404 
405  PhFree(results);
406  }
407  break;
410  {
413 
414  if (result)
415  {
416  PH_HANDLE_ITEM_INFO info;
417 
418  info.ProcessId = result->ProcessId;
419  info.Handle = result->Handle;
420  info.TypeName = result->TypeName;
421  info.BestObjectName = result->Name;
422 
423  if (LOWORD(wParam) == ID_HANDLE_OBJECTPROPERTIES1)
424  PhShowHandleObjectProperties1(hwndDlg, &info);
425  else
426  PhShowHandleObjectProperties2(hwndDlg, &info);
427  }
428  }
429  break;
431  {
434 
435  if (result)
436  {
437  PPH_PROCESS_NODE processNode;
438 
439  if (processNode = PhFindProcessNode(result->ProcessId))
440  {
444  }
445  }
446  }
447  break;
449  {
452 
453  if (result)
454  {
455  if (result->ResultType == HandleSearchResult)
456  {
457  PPH_HANDLE_ITEM handleItem;
458 
459  handleItem = PhCreateHandleItem(&result->Info);
460 
461  handleItem->BestObjectName = handleItem->ObjectName = result->Name;
462  PhReferenceObjectEx(result->Name, 2);
463 
464  handleItem->TypeName = result->TypeName;
465  PhReferenceObject(result->TypeName);
466 
468  hwndDlg,
469  result->ProcessId,
470  handleItem
471  );
472  PhDereferenceObject(handleItem);
473  }
474  else
475  {
476  // DLL or Mapped File. Just show file properties.
477  PhShellProperties(hwndDlg, result->Name->Buffer);
478  }
479  }
480  }
481  break;
482  case ID_OBJECT_COPY:
483  {
485  }
486  break;
487  }
488  }
489  break;
490  case WM_NOTIFY:
491  {
492  LPNMHDR header = (LPNMHDR)lParam;
493 
494  switch (header->code)
495  {
496  case NM_DBLCLK:
497  {
498  if (header->hwndFrom == PhFindObjectsListViewHandle)
499  {
500  SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_PROPERTIES, 0);
501  }
502  }
503  break;
504  case LVN_KEYDOWN:
505  {
506  if (header->hwndFrom == PhFindObjectsListViewHandle)
507  {
508  LPNMLVKEYDOWN keyDown = (LPNMLVKEYDOWN)header;
509 
510  switch (keyDown->wVKey)
511  {
512  case 'C':
513  if (GetKeyState(VK_CONTROL) < 0)
514  SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_COPY, 0);
515  break;
516  case 'A':
517  if (GetKeyState(VK_CONTROL) < 0)
518  PhSetStateAllListViewItems(PhFindObjectsListViewHandle, LVIS_SELECTED, LVIS_SELECTED);
519  break;
520  case VK_DELETE:
521  SendMessage(hwndDlg, WM_COMMAND, ID_OBJECT_CLOSE, 0);
522  break;
523  }
524  }
525  }
526  break;
527  }
528  }
529  break;
530  case WM_CONTEXTMENU:
531  {
532  if ((HWND)wParam == PhFindObjectsListViewHandle)
533  {
534  POINT point;
535  PPHP_OBJECT_SEARCH_RESULT *results;
536  ULONG numberOfResults;
537 
538  point.x = (SHORT)LOWORD(lParam);
539  point.y = (SHORT)HIWORD(lParam);
540 
541  if (point.x == -1 && point.y == -1)
542  PhGetListViewContextMenuPoint((HWND)wParam, &point);
543 
545 
546  if (numberOfResults != 0)
547  {
548  PPH_EMENU menu;
549 
550  menu = PhCreateEMenu();
551  PhLoadResourceEMenuItem(menu, PhInstanceHandle, MAKEINTRESOURCE(IDR_FINDOBJ), 0);
553 
554  PhpInitializeFindObjMenu(menu, results, numberOfResults);
555  PhShowEMenu(
556  menu,
557  hwndDlg,
560  point.x,
561  point.y
562  );
563  PhDestroyEMenu(menu);
564  }
565 
566  PhFree(results);
567  }
568  }
569  break;
570  case WM_SIZE:
571  {
572  PhLayoutManagerLayout(&WindowLayoutManager);
573  }
574  break;
575  case WM_SIZING:
576  {
577  PhResizingMinimumSize((PRECT)lParam, wParam, MinimumSize.right, MinimumSize.bottom);
578  }
579  break;
580  case WM_PH_SEARCH_UPDATE:
581  {
582  HWND lvHandle;
583  ULONG i;
584 
585  lvHandle = GetDlgItem(hwndDlg, IDC_RESULTS);
586 
588 
589  PhAcquireQueuedLockExclusive(&SearchResultsLock);
590 
591  for (i = SearchResultsAddIndex; i < SearchResults->Count; i++)
592  {
593  PPHP_OBJECT_SEARCH_RESULT searchResult = SearchResults->Items[i];
594  CLIENT_ID clientId;
595  PPH_PROCESS_ITEM processItem;
596  PPH_STRING clientIdName;
597  INT lvItemIndex;
598 
599  clientId.UniqueProcess = searchResult->ProcessId;
600  clientId.UniqueThread = NULL;
601 
602  processItem = PhReferenceProcessItem(clientId.UniqueProcess);
603  clientIdName = PhGetClientIdNameEx(&clientId, processItem ? processItem->ProcessName : NULL);
604 
605  lvItemIndex = PhAddListViewItem(
606  lvHandle,
607  MAXINT,
608  clientIdName->Buffer,
609  searchResult
610  );
611 
612  PhDereferenceObject(clientIdName);
613 
614  if (processItem)
615  {
616  PhSetReference(&searchResult->ProcessName, processItem->ProcessName);
617  PhDereferenceObject(processItem);
618  }
619  else
620  {
621  searchResult->ProcessName = NULL;
622  }
623 
624  PhSetListViewSubItem(lvHandle, lvItemIndex, 1, searchResult->TypeName->Buffer);
625  PhSetListViewSubItem(lvHandle, lvItemIndex, 2, searchResult->Name->Buffer);
626  PhSetListViewSubItem(lvHandle, lvItemIndex, 3, searchResult->HandleString);
627  }
628 
629  SearchResultsAddIndex = i;
630 
631  PhReleaseQueuedLockExclusive(&SearchResultsLock);
632 
633  ExtendedListView_SetRedraw(lvHandle, TRUE);
634  }
635  break;
637  {
638  // Add any un-added items.
639  SendMessage(hwndDlg, WM_PH_SEARCH_UPDATE, 0, 0);
640 
641  PhDereferenceObject(SearchString);
642 
643  NtWaitForSingleObject(SearchThreadHandle, FALSE, NULL);
644  NtClose(SearchThreadHandle);
645  SearchThreadHandle = NULL;
646  SearchStop = FALSE;
647 
648  ExtendedListView_SortItems(GetDlgItem(hwndDlg, IDC_RESULTS));
649 
650  SetDlgItemText(hwndDlg, IDOK, L"Find");
651  EnableWindow(GetDlgItem(hwndDlg, IDOK), TRUE);
652 
653  SetCursor(LoadCursor(NULL, IDC_ARROW));
654  }
655  break;
656  }
657 
658  return FALSE;
659 }
660 
661 typedef struct _SEARCH_HANDLE_CONTEXT
662 {
663  BOOLEAN NeedToFree;
665  HANDLE ProcessHandle;
667 
668 static NTSTATUS NTAPI SearchHandleFunction(
669  _In_ PVOID Parameter
670  )
671 {
672  PSEARCH_HANDLE_CONTEXT context = Parameter;
673  PPH_STRING typeName;
674  PPH_STRING bestObjectName;
675 
676  if (!SearchStop && NT_SUCCESS(PhGetHandleInformation(
677  context->ProcessHandle,
678  (HANDLE)context->HandleInfo->HandleValue,
679  context->HandleInfo->ObjectTypeIndex,
680  NULL,
681  &typeName,
682  NULL,
683  &bestObjectName
684  )))
685  {
686  PPH_STRING upperBestObjectName;
687 
688  upperBestObjectName = PhDuplicateString(bestObjectName);
689  PhUpperString(upperBestObjectName);
690 
691  if (PhFindStringInString(upperBestObjectName, 0, SearchString->Buffer) != -1 ||
692  (UseSearchPointer && context->HandleInfo->Object == (PVOID)SearchPointer))
693  {
694  PPHP_OBJECT_SEARCH_RESULT searchResult;
695 
696  searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT));
697  searchResult->ProcessId = (HANDLE)context->HandleInfo->UniqueProcessId;
698  searchResult->ResultType = HandleSearchResult;
699  searchResult->Handle = (HANDLE)context->HandleInfo->HandleValue;
700  searchResult->TypeName = typeName;
701  searchResult->Name = bestObjectName;
702  PhPrintPointer(searchResult->HandleString, (PVOID)searchResult->Handle);
703  searchResult->Info = *context->HandleInfo;
704 
705  PhAcquireQueuedLockExclusive(&SearchResultsLock);
706 
707  PhAddItemList(SearchResults, searchResult);
708 
709  // Update the search results in batches of 40.
710  if (SearchResults->Count % 40 == 0)
712 
713  PhReleaseQueuedLockExclusive(&SearchResultsLock);
714  }
715  else
716  {
717  PhDereferenceObject(typeName);
718  PhDereferenceObject(bestObjectName);
719  }
720 
721  PhDereferenceObject(upperBestObjectName);
722  }
723 
724  if (context->NeedToFree)
725  PhFree(context);
726 
727  return STATUS_SUCCESS;
728 }
729 
730 static BOOLEAN NTAPI EnumModulesCallback(
731  _In_ PPH_MODULE_INFO Module,
732  _In_opt_ PVOID Context
733  )
734 {
735  PPH_STRING upperFileName;
736 
737  upperFileName = PhDuplicateString(Module->FileName);
738  PhUpperString(upperFileName);
739 
740  if (PhFindStringInString(upperFileName, 0, SearchString->Buffer) != -1 ||
741  (UseSearchPointer && Module->BaseAddress == (PVOID)SearchPointer))
742  {
743  PPHP_OBJECT_SEARCH_RESULT searchResult;
744  PWSTR typeName;
745 
746  switch (Module->Type)
747  {
749  typeName = L"Mapped File";
750  break;
752  typeName = L"Mapped Image";
753  break;
754  default:
755  typeName = L"DLL";
756  break;
757  }
758 
759  searchResult = PhAllocate(sizeof(PHP_OBJECT_SEARCH_RESULT));
760  searchResult->ProcessId = (HANDLE)Context;
761  searchResult->ResultType = (Module->Type == PH_MODULE_TYPE_MAPPED_FILE || Module->Type == PH_MODULE_TYPE_MAPPED_IMAGE) ? MappedFileSearchResult : ModuleSearchResult;
762  searchResult->Handle = (HANDLE)Module->BaseAddress;
763  searchResult->TypeName = PhCreateString(typeName);
764  PhSetReference(&searchResult->Name, Module->FileName);
765  PhPrintPointer(searchResult->HandleString, Module->BaseAddress);
766  memset(&searchResult->Info, 0, sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO_EX));
767 
768  PhAcquireQueuedLockExclusive(&SearchResultsLock);
769 
770  PhAddItemList(SearchResults, searchResult);
771 
772  // Update the search results in batches of 40.
773  if (SearchResults->Count % 40 == 0)
775 
776  PhReleaseQueuedLockExclusive(&SearchResultsLock);
777  }
778 
779  PhDereferenceObject(upperFileName);
780 
781  return TRUE;
782 }
783 
785  _In_ PVOID Parameter
786  )
787 {
789  PPH_HASHTABLE processHandleHashtable;
790  PVOID processes;
792  ULONG i;
793 
794  // Refuse to search with no filter.
795  if (SearchString->Length == 0)
796  goto Exit;
797 
798  // Try to get a search pointer from the search string.
799  UseSearchPointer = PhStringToInteger64(&SearchString->sr, 0, &SearchPointer);
800 
801  PhUpperString(SearchString);
802 
803  if (NT_SUCCESS(PhEnumHandlesEx(&handles)))
804  {
805  static PH_INITONCE initOnce = PH_INITONCE_INIT;
806  static ULONG fileObjectTypeIndex = -1;
807 
808  BOOLEAN useWorkQueue = FALSE;
809  PH_WORK_QUEUE workQueue;
810  processHandleHashtable = PhCreateSimpleHashtable(8);
811 
813  {
814  useWorkQueue = TRUE;
815  PhInitializeWorkQueue(&workQueue, 1, 20, 1000);
816 
817  if (PhBeginInitOnce(&initOnce))
818  {
819  UNICODE_STRING fileTypeName;
820 
821  RtlInitUnicodeString(&fileTypeName, L"File");
822  fileObjectTypeIndex = PhGetObjectTypeNumber(&fileTypeName);
823  PhEndInitOnce(&initOnce);
824  }
825  }
826 
827  for (i = 0; i < handles->NumberOfHandles; i++)
828  {
829  PSYSTEM_HANDLE_TABLE_ENTRY_INFO_EX handleInfo = &handles->Handles[i];
830  PVOID *processHandlePtr;
831  HANDLE processHandle;
832 
833  if (SearchStop)
834  break;
835 
836  // Open a handle to the process if we don't already have one.
837 
838  processHandlePtr = PhFindItemSimpleHashtable(
839  processHandleHashtable,
840  (PVOID)handleInfo->UniqueProcessId
841  );
842 
843  if (processHandlePtr)
844  {
845  processHandle = (HANDLE)*processHandlePtr;
846  }
847  else
848  {
850  &processHandle,
851  PROCESS_DUP_HANDLE,
852  (HANDLE)handleInfo->UniqueProcessId
853  )))
854  {
856  processHandleHashtable,
857  (PVOID)handleInfo->UniqueProcessId,
858  processHandle
859  );
860  }
861  else
862  {
863  continue;
864  }
865  }
866 
867  if (useWorkQueue && handleInfo->ObjectTypeIndex == (USHORT)fileObjectTypeIndex)
868  {
869  PSEARCH_HANDLE_CONTEXT searchHandleContext;
870 
871  searchHandleContext = PhAllocate(sizeof(SEARCH_HANDLE_CONTEXT));
872  searchHandleContext->NeedToFree = TRUE;
873  searchHandleContext->HandleInfo = handleInfo;
874  searchHandleContext->ProcessHandle = processHandle;
875  PhQueueItemWorkQueue(&workQueue, SearchHandleFunction, searchHandleContext);
876  }
877  else
878  {
879  SEARCH_HANDLE_CONTEXT searchHandleContext;
880 
881  searchHandleContext.NeedToFree = FALSE;
882  searchHandleContext.HandleInfo = handleInfo;
883  searchHandleContext.ProcessHandle = processHandle;
884  SearchHandleFunction(&searchHandleContext);
885  }
886  }
887 
888  if (useWorkQueue)
889  {
890  PhWaitForWorkQueue(&workQueue);
891  PhDeleteWorkQueue(&workQueue);
892  }
893 
894  {
895  PPH_KEY_VALUE_PAIR entry;
896 
897  i = 0;
898 
899  while (PhEnumHashtable(processHandleHashtable, &entry, &i))
900  NtClose((HANDLE)entry->Value);
901  }
902 
903  PhDereferenceObject(processHandleHashtable);
904  PhFree(handles);
905  }
906 
907  if (NT_SUCCESS(PhEnumProcesses(&processes)))
908  {
909  process = PH_FIRST_PROCESS(processes);
910 
911  do
912  {
914  process->UniqueProcessId,
915  NULL,
917  EnumModulesCallback,
918  (PVOID)process->UniqueProcessId
919  );
920  } while (process = PH_NEXT_PROCESS(process));
921 
922  PhFree(processes);
923  }
924 
925 Exit:
927 
928  return STATUS_SUCCESS;
929 }