Process Hacker
actions.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * UI actions
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 /*
24  * These are a set of consistent functions which will perform actions
25  * on objects such as processes, threads and services, while displaying
26  * any necessary prompts and error messages. Automatic elevation can also
27  * easily be added if necessary.
28  */
29 
30 #include <phapp.h>
31 #include <settings.h>
32 #include <kphuser.h>
33 #include <phsvccl.h>
34 #include <winsta.h>
35 #include <iphlpapi.h>
36 
37 typedef DWORD (WINAPI *_SetTcpEntry)(
38  _In_ PMIB_TCPROW pTcpRow
39  );
40 
41 static PWSTR DangerousProcesses[] =
42 {
43  L"csrss.exe", L"dwm.exe", L"logonui.exe", L"lsass.exe", L"lsm.exe",
44  L"services.exe", L"smss.exe", L"wininit.exe", L"winlogon.exe"
45 };
46 
47 static PPH_STRING DebuggerCommand = NULL;
48 static PH_INITONCE DebuggerCommandInitOnce = PH_INITONCE_INIT;
49 static ULONG PhSvcReferenceCount = 0;
50 static PH_PHSVC_MODE PhSvcCurrentMode;
51 static PH_QUEUED_LOCK PhSvcStartLock = PH_QUEUED_LOCK_INIT;
52 
54  _In_ HWND hwnd,
55  _In_ UINT uNotification,
56  _In_ WPARAM wParam,
57  _In_ LPARAM lParam,
58  _In_ LONG_PTR dwRefData
59  )
60 {
61  switch (uNotification)
62  {
63  case TDN_CREATED:
64  SendMessage(hwnd, TDM_SET_BUTTON_ELEVATION_REQUIRED_STATE, IDYES, TRUE);
65  break;
66  }
67 
68  return S_OK;
69 }
70 
72  _In_ HWND hWnd,
73  _In_ PWSTR Message,
74  _In_ NTSTATUS Status,
75  _Out_ PINT Button
76  )
77 {
78  TASKDIALOGCONFIG config = { sizeof(config) };
79  TASKDIALOG_BUTTON buttons[1];
80  INT button;
81 
82  // Currently the error dialog box is similar to the one displayed
83  // when you try to label a drive in Windows Explorer. It's much better
84  // than the clunky dialog in PH 1.x.
85 
86  config.hwndParent = hWnd;
87  config.hInstance = PhInstanceHandle;
88  config.pszWindowTitle = L"Process Hacker";
89  config.pszMainIcon = TD_ERROR_ICON;
90  config.pszMainInstruction = PhaConcatStrings2(Message, L".")->Buffer;
91  /*config.pszContent = PhaConcatStrings(
92  3,
93  L"Unable to perform the action: ",
94  ((PPH_STRING)PhAutoDereferenceObject(PhGetNtMessage(Status)))->Buffer,
95  L"\nYou will need to provide administrator permission. "
96  L"Click Continue to complete this operation."
97  )->Buffer;*/
98  config.pszContent = L"You will need to provide administrator permission. "
99  L"Click Continue to complete this operation.";
100  config.dwCommonButtons = TDCBF_CANCEL_BUTTON;
101 
102  buttons[0].nButtonID = IDYES;
103  buttons[0].pszButtonText = L"Continue";
104 
105  config.cButtons = 1;
106  config.pButtons = buttons;
107  config.nDefaultButton = IDYES;
108 
109  config.pfCallback = PhpElevateActionCallbackProc;
110 
112  &config,
113  &button,
114  NULL,
115  NULL
116  ) == S_OK)
117  {
118  *Button = button;
119  return TRUE;
120  }
121  else
122  {
123  return FALSE;
124  }
125 }
126 
142  _In_ HWND hWnd,
143  _In_ PWSTR Message,
144  _In_ NTSTATUS Status,
145  _In_ PWSTR Command,
146  _Out_ PBOOLEAN Success
147  )
148 {
149  PH_ACTION_ELEVATION_LEVEL elevationLevel;
150  INT button = IDNO;
151 
152  if (!(
153  Status == STATUS_ACCESS_DENIED ||
154  Status == STATUS_PRIVILEGE_NOT_HELD ||
155  (NT_NTWIN32(Status) && WIN32_FROM_NTSTATUS(Status) == ERROR_ACCESS_DENIED)
156  ))
157  return FALSE;
158 
159  if (!WINDOWS_HAS_UAC || PhElevated)
160  return FALSE;
161 
162  elevationLevel = PhGetIntegerSetting(L"ElevationLevel");
163 
164  if (elevationLevel == NeverElevateAction)
165  return FALSE;
166 
167  if (elevationLevel == PromptElevateAction && TaskDialogIndirect_I)
168  {
169  if (!PhpShowElevatePrompt(hWnd, Message, Status, &button))
170  return FALSE;
171  }
172 
173  if (elevationLevel == AlwaysElevateAction || button == IDYES)
174  {
175  NTSTATUS status;
176  HANDLE processHandle;
177  LARGE_INTEGER timeout;
178  PROCESS_BASIC_INFORMATION basicInfo;
179 
181  hWnd,
182  Command,
183  SW_SHOW,
186  0,
187  &processHandle
188  ))
189  {
190  timeout.QuadPart = -10 * PH_TIMEOUT_SEC;
191  status = NtWaitForSingleObject(processHandle, FALSE, &timeout);
192 
193  if (
194  status == STATUS_WAIT_0 &&
195  NT_SUCCESS(status = PhGetProcessBasicInformation(processHandle, &basicInfo))
196  )
197  {
198  status = basicInfo.ExitStatus;
199  }
200 
201  NtClose(processHandle);
202 
203  if (NT_SUCCESS(status))
204  {
205  *Success = TRUE;
206  }
207  else
208  {
209  *Success = FALSE;
210  PhShowStatus(hWnd, Message, status, 0);
211  }
212  }
213  }
214 
215  return TRUE;
216 }
217 
234  _In_ HWND hWnd,
235  _In_ PWSTR Message,
236  _In_ NTSTATUS Status,
237  _Out_ PBOOLEAN Connected
238  )
239 {
240  PH_ACTION_ELEVATION_LEVEL elevationLevel;
241  INT button = IDNO;
242 
243  *Connected = FALSE;
244 
245  if (!(
246  Status == STATUS_ACCESS_DENIED ||
247  Status == STATUS_PRIVILEGE_NOT_HELD ||
248  (NT_NTWIN32(Status) && WIN32_FROM_NTSTATUS(Status) == ERROR_ACCESS_DENIED)
249  ))
250  return FALSE;
251 
252  if (!WINDOWS_HAS_UAC || PhElevated)
253  return FALSE;
254 
255  elevationLevel = PhGetIntegerSetting(L"ElevationLevel");
256 
257  if (elevationLevel == NeverElevateAction)
258  return FALSE;
259 
260  // Try to connect now so we can avoid prompting the user.
261  if (PhUiConnectToPhSvc(hWnd, TRUE))
262  {
263  *Connected = TRUE;
264  return TRUE;
265  }
266 
267  if (elevationLevel == PromptElevateAction && TaskDialogIndirect_I)
268  {
269  if (!PhpShowElevatePrompt(hWnd, Message, Status, &button))
270  return FALSE;
271  }
272 
273  if (elevationLevel == AlwaysElevateAction || button == IDYES)
274  {
275  *Connected = PhUiConnectToPhSvc(hWnd, FALSE);
276  }
277 
278  return TRUE;
279 }
280 
290  _In_opt_ HWND hWnd,
291  _In_ BOOLEAN ConnectOnly
292  )
293 {
294  return PhUiConnectToPhSvcEx(hWnd, ElevatedPhSvcMode, ConnectOnly);
295 }
296 
298  _In_ PH_PHSVC_MODE Mode,
299  _Out_ PUNICODE_STRING PortName
300  )
301 {
302  switch (Mode)
303  {
304  case ElevatedPhSvcMode:
305  if (!PhIsExecutingInWow64())
307  else
309  break;
310  case Wow64PhSvcMode:
312  break;
313  default:
314  PhRaiseStatus(STATUS_INVALID_PARAMETER);
315  break;
316  }
317 }
318 
320  _In_opt_ HWND hWnd,
321  _In_ PH_PHSVC_MODE Mode
322  )
323 {
324  switch (Mode)
325  {
326  case ElevatedPhSvcMode:
328  hWnd,
329  L"-phsvc",
330  SW_HIDE,
333  0,
334  NULL
335  ))
336  {
337  return TRUE;
338  }
339 
340  break;
341  case Wow64PhSvcMode:
342  {
343  static PWSTR relativeFileNames[] =
344  {
345  L"\\x86\\ProcessHacker.exe",
346  L"\\..\\x86\\ProcessHacker.exe",
347 #ifdef DEBUG
348  L"\\..\\Debug32\\ProcessHacker.exe",
349 #endif
350  L"\\..\\Release32\\ProcessHacker.exe"
351  };
352 
353  ULONG i;
354 
355  for (i = 0; i < sizeof(relativeFileNames) / sizeof(PWSTR); i++)
356  {
357  PPH_STRING fileName;
358 
359  fileName = PhConcatStrings2(PhApplicationDirectory->Buffer, relativeFileNames[i]);
360  PhMoveReference(&fileName, PhGetFullPath(fileName->Buffer, NULL));
361 
362  if (fileName && RtlDoesFileExists_U(fileName->Buffer))
363  {
365  hWnd,
366  fileName->Buffer,
367  L"-phsvc",
368  SW_HIDE,
369  0,
371  0,
372  NULL
373  ))
374  {
375  PhDereferenceObject(fileName);
376  return TRUE;
377  }
378  }
379 
380  PhClearReference(&fileName);
381  }
382  }
383  break;
384  }
385 
386  return FALSE;
387 }
388 
399  _In_opt_ HWND hWnd,
400  _In_ PH_PHSVC_MODE Mode,
401  _In_ BOOLEAN ConnectOnly
402  )
403 {
404  NTSTATUS status;
405  BOOLEAN started;
406  UNICODE_STRING portName;
407 
408  if (_InterlockedIncrementNoZero(&PhSvcReferenceCount))
409  {
410  if (PhSvcCurrentMode == Mode)
411  {
412  started = TRUE;
413  }
414  else
415  {
416  _InterlockedDecrement(&PhSvcReferenceCount);
417  started = FALSE;
418  }
419  }
420  else
421  {
422  PhAcquireQueuedLockExclusive(&PhSvcStartLock);
423 
424  if (PhSvcReferenceCount == 0)
425  {
426  started = FALSE;
427  PhpGetPhSvcPortName(Mode, &portName);
428 
429  // Try to connect first, then start the server if we failed.
430  status = PhSvcConnectToServer(&portName, 0);
431 
432  if (NT_SUCCESS(status))
433  {
434  started = TRUE;
435  PhSvcCurrentMode = Mode;
436  _InterlockedIncrement(&PhSvcReferenceCount);
437  }
438  else if (!ConnectOnly)
439  {
440  // Prompt for elevation, and then try to connect to the server.
441 
442  if (PhpStartPhSvcProcess(hWnd, Mode))
443  started = TRUE;
444 
445  if (started)
446  {
447  ULONG attempts = 10;
448  LARGE_INTEGER interval;
449 
450  // Try to connect several times because the server may take
451  // a while to initialize.
452  do
453  {
454  status = PhSvcConnectToServer(&portName, 0);
455 
456  if (NT_SUCCESS(status))
457  break;
458 
459  interval.QuadPart = -50 * PH_TIMEOUT_MS;
460  NtDelayExecution(FALSE, &interval);
461  } while (--attempts != 0);
462 
463  // Increment the reference count even if we failed.
464  // We don't want to prompt the user again.
465 
466  PhSvcCurrentMode = Mode;
467  _InterlockedIncrement(&PhSvcReferenceCount);
468  }
469  }
470  }
471  else
472  {
473  if (PhSvcCurrentMode == Mode)
474  {
475  started = TRUE;
476  _InterlockedIncrement(&PhSvcReferenceCount);
477  }
478  else
479  {
480  started = FALSE;
481  }
482  }
483 
484  PhReleaseQueuedLockExclusive(&PhSvcStartLock);
485  }
486 
487  return started;
488 }
489 
494  VOID
495  )
496 {
497  PhAcquireQueuedLockExclusive(&PhSvcStartLock);
498 
499  if (_InterlockedDecrement(&PhSvcReferenceCount) == 0)
500  {
502  }
503 
504  PhReleaseQueuedLockExclusive(&PhSvcStartLock);
505 }
506 
508  _In_ HWND hWnd
509  )
510 {
511  if (LockWorkStation())
512  return TRUE;
513  else
514  PhShowStatus(hWnd, L"Unable to lock the computer", 0, GetLastError());
515 
516  return FALSE;
517 }
518 
520  _In_ HWND hWnd
521  )
522 {
523  if (ExitWindowsEx(EWX_LOGOFF, 0))
524  return TRUE;
525  else
526  PhShowStatus(hWnd, L"Unable to logoff the computer", 0, GetLastError());
527 
528  return FALSE;
529 }
530 
532  _In_ HWND hWnd
533  )
534 {
535  NTSTATUS status;
536 
537  if (NT_SUCCESS(status = NtInitiatePowerAction(
538  PowerActionSleep,
539  PowerSystemSleeping1,
540  0,
541  FALSE
542  )))
543  return TRUE;
544  else
545  PhShowStatus(hWnd, L"Unable to sleep the computer", status, 0);
546 
547  return FALSE;
548 }
549 
551  _In_ HWND hWnd
552  )
553 {
554  NTSTATUS status;
555 
556  if (NT_SUCCESS(status = NtInitiatePowerAction(
557  PowerActionHibernate,
558  PowerSystemSleeping1,
559  0,
560  FALSE
561  )))
562  return TRUE;
563  else
564  PhShowStatus(hWnd, L"Unable to hibernate the computer", status, 0);
565 
566  return FALSE;
567 }
568 
570  _In_ HWND hWnd,
571  _In_ ULONG Flags
572  )
573 {
574  if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
575  hWnd,
576  L"restart",
577  L"the computer",
578  NULL,
579  FALSE
580  ))
581  {
582  if (ExitWindowsEx(EWX_REBOOT | Flags, 0))
583  return TRUE;
584  else
585  PhShowStatus(hWnd, L"Unable to restart the computer", 0, GetLastError());
586  }
587 
588  return FALSE;
589 }
590 
592  _In_ HWND hWnd,
593  _In_ ULONG Flags
594  )
595 {
596  if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
597  hWnd,
598  L"shut down",
599  L"the computer",
600  NULL,
601  FALSE
602  ))
603  {
604  if (ExitWindowsEx(EWX_POWEROFF | Flags, 0))
605  {
606  return TRUE;
607  }
608  else if (ExitWindowsEx(EWX_SHUTDOWN | Flags, 0))
609  {
610  return TRUE;
611  }
612  else
613  {
614  PhShowStatus(hWnd, L"Unable to shut down the computer", 0, GetLastError());
615  }
616  }
617 
618  return FALSE;
619 }
620 
622  _In_ HWND hWnd,
623  _In_ ULONG SessionId
624  )
625 {
626  BOOLEAN success = FALSE;
627  PPH_STRING selectedChoice = NULL;
628  PPH_STRING oldSelectedChoice = NULL;
629 
630  // Try once with no password.
631  if (WinStationConnectW(NULL, SessionId, -1, L"", TRUE))
632  return TRUE;
633 
634  while (PhaChoiceDialog(
635  hWnd,
636  L"Connect to session",
637  L"Password:",
638  NULL,
639  0,
640  NULL,
642  &selectedChoice,
643  NULL,
644  NULL
645  ))
646  {
647  if (oldSelectedChoice)
648  {
649  RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length);
650  PhDereferenceObject(oldSelectedChoice);
651  }
652 
653  oldSelectedChoice = selectedChoice;
654 
655  if (WinStationConnectW(NULL, SessionId, -1, selectedChoice->Buffer, TRUE))
656  {
657  success = TRUE;
658  break;
659  }
660  else
661  {
662  if (!PhShowContinueStatus(hWnd, L"Unable to connect to the session", 0, GetLastError()))
663  break;
664  }
665  }
666 
667  if (oldSelectedChoice)
668  {
669  RtlSecureZeroMemory(oldSelectedChoice->Buffer, oldSelectedChoice->Length);
670  PhDereferenceObject(oldSelectedChoice);
671  }
672 
673  return success;
674 }
675 
677  _In_ HWND hWnd,
678  _In_ ULONG SessionId
679  )
680 {
681  if (WinStationDisconnect(NULL, SessionId, FALSE))
682  return TRUE;
683  else
684  PhShowStatus(hWnd, L"Unable to disconnect the session", 0, GetLastError());
685 
686  return FALSE;
687 }
688 
690  _In_ HWND hWnd,
691  _In_ ULONG SessionId
692  )
693 {
694  if (!PhGetIntegerSetting(L"EnableWarnings") || PhShowConfirmMessage(
695  hWnd,
696  L"logoff",
697  L"the user",
698  NULL,
699  FALSE
700  ))
701  {
702  if (WinStationReset(NULL, SessionId, FALSE))
703  return TRUE;
704  else
705  PhShowStatus(hWnd, L"Unable to logoff the session", 0, GetLastError());
706  }
707 
708  return FALSE;
709 }
710 
716 static BOOLEAN PhpIsDangerousProcess(
717  _In_ HANDLE ProcessId
718  )
719 {
720  NTSTATUS status;
721  HANDLE processHandle;
722  PPH_STRING fileName;
723  PPH_STRING systemDirectory;
724  ULONG i;
725 
726  if (ProcessId == SYSTEM_PROCESS_ID)
727  return TRUE;
728 
730  {
731  status = PhGetProcessImageFileNameByProcessId(ProcessId, &fileName);
732  }
733  else
734  {
735  if (!NT_SUCCESS(status = PhOpenProcess(
736  &processHandle,
738  ProcessId
739  )))
740  return FALSE;
741 
742  status = PhGetProcessImageFileName(processHandle, &fileName);
743  NtClose(processHandle);
744  }
745 
746  if (!NT_SUCCESS(status))
747  return FALSE;
748 
749  PhMoveReference(&fileName, PhGetFileName(fileName));
750  PhAutoDereferenceObject(fileName);
751 
752  systemDirectory = PhAutoDereferenceObject(PhGetSystemDirectory());
753 
754  for (i = 0; i < sizeof(DangerousProcesses) / sizeof(PWSTR); i++)
755  {
756  PPH_STRING fullName;
757 
758  fullName = PhaConcatStrings(3, systemDirectory->Buffer, L"\\", DangerousProcesses[i]);
759 
760  if (PhEqualString(fileName, fullName, TRUE))
761  return TRUE;
762  }
763 
764  return FALSE;
765 }
766 
783 static BOOLEAN PhpShowContinueMessageProcesses(
784  _In_ HWND hWnd,
785  _In_ PWSTR Verb,
786  _In_opt_ PWSTR Message,
787  _In_ BOOLEAN WarnOnlyIfDangerous,
788  _In_ PPH_PROCESS_ITEM *Processes,
789  _In_ ULONG NumberOfProcesses
790  )
791 {
792  PWSTR object;
793  ULONG i;
794  BOOLEAN critical = FALSE;
795  BOOLEAN dangerous = FALSE;
796  BOOLEAN cont = FALSE;
797 
798  if (NumberOfProcesses == 0)
799  return FALSE;
800 
801  for (i = 0; i < NumberOfProcesses; i++)
802  {
803  HANDLE processHandle;
804  ULONG breakOnTermination;
805 
806  breakOnTermination = 0;
807 
808  if (NT_SUCCESS(PhOpenProcess(&processHandle, PROCESS_QUERY_INFORMATION, Processes[i]->ProcessId)))
809  {
810  NtQueryInformationProcess(processHandle, ProcessBreakOnTermination, &breakOnTermination, sizeof(ULONG), NULL);
811  NtClose(processHandle);
812  }
813 
814  if (breakOnTermination != 0)
815  {
816  critical = TRUE;
817  dangerous = TRUE;
818  break;
819  }
820 
821  if (PhpIsDangerousProcess(Processes[i]->ProcessId))
822  {
823  dangerous = TRUE;
824  break;
825  }
826  }
827 
828  if (WarnOnlyIfDangerous && !dangerous)
829  return TRUE;
830 
831  if (PhGetIntegerSetting(L"EnableWarnings"))
832  {
833  if (NumberOfProcesses == 1)
834  {
835  object = Processes[0]->ProcessName->Buffer;
836  }
837  else if (NumberOfProcesses == 2)
838  {
839  object = PhaConcatStrings(
840  3,
841  Processes[0]->ProcessName->Buffer,
842  L" and ",
843  Processes[1]->ProcessName->Buffer
844  )->Buffer;
845  }
846  else
847  {
848  object = L"the selected processes";
849  }
850 
851  if (!dangerous)
852  {
853  cont = PhShowConfirmMessage(
854  hWnd,
855  Verb,
856  object,
857  Message,
858  FALSE
859  );
860  }
861  else if (!critical)
862  {
863  cont = PhShowConfirmMessage(
864  hWnd,
865  Verb,
866  object,
868  3,
869  L"You are about to ",
870  Verb,
871  L" one or more system processes."
872  )->Buffer,
873  TRUE
874  );
875  }
876  else
877  {
878  PPH_STRING message;
879 
880  if (PhEqualStringZ(Verb, L"terminate", FALSE))
881  {
882  message = PhaConcatStrings(
883  3,
884  L"You are about to ",
885  Verb,
886  L" one or more critical processes. This will shut down the operating system immediately."
887  );
888  }
889  else
890  {
891  message = PhaConcatStrings(
892  3,
893  L"You are about to ",
894  Verb,
895  L" one or more critical processes."
896  );
897  }
898 
899  cont = PhShowConfirmMessage(
900  hWnd,
901  Verb,
902  object,
903  message->Buffer,
904  TRUE
905  );
906  }
907  }
908  else
909  {
910  cont = TRUE;
911  }
912 
913  return cont;
914 }
915 
934 static BOOLEAN PhpShowErrorProcess(
935  _In_ HWND hWnd,
936  _In_ PWSTR Verb,
937  _In_ PPH_PROCESS_ITEM Process,
938  _In_ NTSTATUS Status,
939  _In_opt_ ULONG Win32Result
940  )
941 {
942  if (!PH_IS_FAKE_PROCESS_ID(Process->ProcessId))
943  {
944  return PhShowContinueStatus(
945  hWnd,
947  L"Unable to %s %s (PID %u)",
948  Verb,
949  Process->ProcessName->Buffer,
950  (ULONG)Process->ProcessId
951  )->Buffer,
952  Status,
953  Win32Result
954  );
955  }
956  else
957  {
958  return PhShowContinueStatus(
959  hWnd,
961  L"Unable to %s %s",
962  Verb,
963  Process->ProcessName->Buffer
964  )->Buffer,
965  Status,
966  Win32Result
967  );
968  }
969 }
970 
972  _In_ HWND hWnd,
973  _In_ PPH_PROCESS_ITEM *Processes,
974  _In_ ULONG NumberOfProcesses
975  )
976 {
977  BOOLEAN success = TRUE;
978  BOOLEAN cancelled = FALSE;
979  ULONG i;
980 
981  if (!PhpShowContinueMessageProcesses(
982  hWnd,
983  L"terminate",
984  L"Terminating a process will cause unsaved data to be lost.",
985  FALSE,
986  Processes,
987  NumberOfProcesses
988  ))
989  return FALSE;
990 
991  for (i = 0; i < NumberOfProcesses; i++)
992  {
993  NTSTATUS status;
994  HANDLE processHandle;
995 
996  if (NT_SUCCESS(status = PhOpenProcess(
997  &processHandle,
999  Processes[i]->ProcessId
1000  )))
1001  {
1002  // An exit status of 1 is used here for compatibility reasons:
1003  // 1. Both Task Manager and Process Explorer use 1.
1004  // 2. winlogon tries to restart explorer.exe if the exit status is not 1.
1005 
1006  status = PhTerminateProcess(processHandle, 1);
1007  NtClose(processHandle);
1008  }
1009 
1010  if (!NT_SUCCESS(status))
1011  {
1012  BOOLEAN connected;
1013 
1014  success = FALSE;
1015 
1016  if (!cancelled && PhpShowErrorAndConnectToPhSvc(
1017  hWnd,
1018  PhaConcatStrings2(L"Unable to terminate ", Processes[i]->ProcessName->Buffer)->Buffer,
1019  status,
1020  &connected
1021  ))
1022  {
1023  if (connected)
1024  {
1025  if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessTerminate, 0)))
1026  success = TRUE;
1027  else
1028  PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0);
1029 
1031  }
1032  else
1033  {
1034  cancelled = TRUE;
1035  }
1036  }
1037  else
1038  {
1039  if (!PhpShowErrorProcess(hWnd, L"terminate", Processes[i], status, 0))
1040  break;
1041  }
1042  }
1043  }
1044 
1045  return success;
1046 }
1047 
1049  _In_ HWND hWnd,
1050  _In_ PPH_PROCESS_ITEM Process,
1051  _In_ PVOID Processes,
1052  _Inout_ PBOOLEAN Success
1053  )
1054 {
1055  NTSTATUS status;
1057  HANDLE processHandle;
1058  PPH_PROCESS_ITEM processItem;
1059 
1060  // Note:
1061  // FALSE should be written to Success if any part of the operation failed.
1062  // The return value of this function indicates whether to continue with
1063  // the operation (FALSE if user cancelled).
1064 
1065  // Terminate the process.
1066 
1067  if (NT_SUCCESS(status = PhOpenProcess(
1068  &processHandle,
1070  Process->ProcessId
1071  )))
1072  {
1073  status = PhTerminateProcess(processHandle, 1);
1074  NtClose(processHandle);
1075  }
1076 
1077  if (!NT_SUCCESS(status))
1078  {
1079  *Success = FALSE;
1080 
1081  if (!PhpShowErrorProcess(hWnd, L"terminate", Process, status, 0))
1082  return FALSE;
1083  }
1084 
1085  // Terminate the process' children.
1086 
1087  process = PH_FIRST_PROCESS(Processes);
1088 
1089  do
1090  {
1091  if (
1092  process->UniqueProcessId != Process->ProcessId &&
1093  process->InheritedFromUniqueProcessId == Process->ProcessId
1094  )
1095  {
1096  if (processItem = PhReferenceProcessItem(process->UniqueProcessId))
1097  {
1098  // Check the creation time to make sure it is a descendant.
1099  if (processItem->CreateTime.QuadPart >= Process->CreateTime.QuadPart)
1100  {
1101  if (!PhpUiTerminateTreeProcess(hWnd, processItem, Processes, Success))
1102  {
1103  PhDereferenceObject(processItem);
1104  return FALSE;
1105  }
1106  }
1107 
1108  PhDereferenceObject(processItem);
1109  }
1110  }
1111  } while (process = PH_NEXT_PROCESS(process));
1112 
1113  return TRUE;
1114 }
1115 
1117  _In_ HWND hWnd,
1118  _In_ PPH_PROCESS_ITEM Process
1119  )
1120 {
1121  NTSTATUS status;
1122  BOOLEAN success = TRUE;
1123  BOOLEAN cont = FALSE;
1124  PVOID processes;
1125 
1126  if (PhGetIntegerSetting(L"EnableWarnings"))
1127  {
1128  cont = PhShowConfirmMessage(
1129  hWnd,
1130  L"terminate",
1131  PhaConcatStrings2(Process->ProcessName->Buffer, L" and its descendants")->Buffer,
1132  L"Terminating a process tree will cause the process and its descendants to be terminated.",
1133  FALSE
1134  );
1135  }
1136  else
1137  {
1138  cont = TRUE;
1139  }
1140 
1141  if (!cont)
1142  return FALSE;
1143 
1144  if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))
1145  {
1146  PhShowStatus(hWnd, L"Unable to enumerate processes", status, 0);
1147  return FALSE;
1148  }
1149 
1150  PhpUiTerminateTreeProcess(hWnd, Process, processes, &success);
1151  PhFree(processes);
1152 
1153  return success;
1154 }
1155 
1157  _In_ HWND hWnd,
1158  _In_ PPH_PROCESS_ITEM *Processes,
1159  _In_ ULONG NumberOfProcesses
1160  )
1161 {
1162  BOOLEAN success = TRUE;
1163  BOOLEAN cancelled = FALSE;
1164  ULONG i;
1165 
1166  if (!PhpShowContinueMessageProcesses(
1167  hWnd,
1168  L"suspend",
1169  NULL,
1170  TRUE,
1171  Processes,
1172  NumberOfProcesses
1173  ))
1174  return FALSE;
1175 
1176  for (i = 0; i < NumberOfProcesses; i++)
1177  {
1178  NTSTATUS status;
1179  HANDLE processHandle;
1180 
1181  if (NT_SUCCESS(status = PhOpenProcess(
1182  &processHandle,
1184  Processes[i]->ProcessId
1185  )))
1186  {
1187  status = PhSuspendProcess(processHandle);
1188  NtClose(processHandle);
1189  }
1190 
1191  if (!NT_SUCCESS(status))
1192  {
1193  BOOLEAN connected;
1194 
1195  success = FALSE;
1196 
1197  if (!cancelled && PhpShowErrorAndConnectToPhSvc(
1198  hWnd,
1199  PhaConcatStrings2(L"Unable to suspend ", Processes[i]->ProcessName->Buffer)->Buffer,
1200  status,
1201  &connected
1202  ))
1203  {
1204  if (connected)
1205  {
1206  if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessSuspend, 0)))
1207  success = TRUE;
1208  else
1209  PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0);
1210 
1212  }
1213  else
1214  {
1215  cancelled = TRUE;
1216  }
1217  }
1218  else
1219  {
1220  if (!PhpShowErrorProcess(hWnd, L"suspend", Processes[i], status, 0))
1221  break;
1222  }
1223  }
1224  }
1225 
1226  return success;
1227 }
1228 
1230  _In_ HWND hWnd,
1231  _In_ PPH_PROCESS_ITEM *Processes,
1232  _In_ ULONG NumberOfProcesses
1233  )
1234 {
1235  BOOLEAN success = TRUE;
1236  BOOLEAN cancelled = FALSE;
1237  ULONG i;
1238 
1239  if (!PhpShowContinueMessageProcesses(
1240  hWnd,
1241  L"resume",
1242  NULL,
1243  TRUE,
1244  Processes,
1245  NumberOfProcesses
1246  ))
1247  return FALSE;
1248 
1249  for (i = 0; i < NumberOfProcesses; i++)
1250  {
1251  NTSTATUS status;
1252  HANDLE processHandle;
1253 
1254  if (NT_SUCCESS(status = PhOpenProcess(
1255  &processHandle,
1257  Processes[i]->ProcessId
1258  )))
1259  {
1260  status = PhResumeProcess(processHandle);
1261  NtClose(processHandle);
1262  }
1263 
1264  if (!NT_SUCCESS(status))
1265  {
1266  BOOLEAN connected;
1267 
1268  success = FALSE;
1269 
1270  if (!cancelled && PhpShowErrorAndConnectToPhSvc(
1271  hWnd,
1272  PhaConcatStrings2(L"Unable to resume ", Processes[i]->ProcessName->Buffer)->Buffer,
1273  status,
1274  &connected
1275  ))
1276  {
1277  if (connected)
1278  {
1279  if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessResume, 0)))
1280  success = TRUE;
1281  else
1282  PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0);
1283 
1285  }
1286  else
1287  {
1288  cancelled = TRUE;
1289  }
1290  }
1291  else
1292  {
1293  if (!PhpShowErrorProcess(hWnd, L"resume", Processes[i], status, 0))
1294  break;
1295  }
1296  }
1297  }
1298 
1299  return success;
1300 }
1301 
1303  _In_ HWND hWnd,
1304  _In_ PPH_PROCESS_ITEM Process
1305  )
1306 {
1307  NTSTATUS status;
1308  BOOLEAN cont = FALSE;
1309  HANDLE processHandle = NULL;
1310  BOOLEAN isPosix;
1311  PPH_STRING commandLine;
1312  PPH_STRING currentDirectory;
1313 
1314  if (PhGetIntegerSetting(L"EnableWarnings"))
1315  {
1316  cont = PhShowConfirmMessage(
1317  hWnd,
1318  L"restart",
1319  Process->ProcessName->Buffer,
1320  L"The process will be restarted with the same command line and "
1321  L"working directory, but if it is running under a different user it "
1322  L"will be restarted under the current user.",
1323  FALSE
1324  );
1325  }
1326  else
1327  {
1328  cont = TRUE;
1329  }
1330 
1331  if (!cont)
1332  return FALSE;
1333 
1334  // Open the process and get the command line and current directory.
1335 
1336  if (!NT_SUCCESS(status = PhOpenProcess(
1337  &processHandle,
1339  Process->ProcessId
1340  )))
1341  goto ErrorExit;
1342 
1343  if (!NT_SUCCESS(status = PhGetProcessIsPosix(processHandle, &isPosix)))
1344  goto ErrorExit;
1345 
1346  if (isPosix)
1347  {
1348  PhShowError(hWnd, L"POSIX processes cannot be restarted.");
1349  goto ErrorExit;
1350  }
1351 
1352  if (!NT_SUCCESS(status = PhGetProcessCommandLine(
1353  processHandle,
1354  &commandLine
1355  )))
1356  goto ErrorExit;
1357 
1358  PhAutoDereferenceObject(commandLine);
1359 
1360  if (!NT_SUCCESS(status = PhGetProcessPebString(
1361  processHandle,
1363  &currentDirectory
1364  )))
1365  goto ErrorExit;
1366 
1367  PhAutoDereferenceObject(currentDirectory);
1368 
1369  NtClose(processHandle);
1370  processHandle = NULL;
1371 
1372  // Open the process and terminate it.
1373 
1374  if (!NT_SUCCESS(status = PhOpenProcess(
1375  &processHandle,
1377  Process->ProcessId
1378  )))
1379  goto ErrorExit;
1380 
1381  if (!NT_SUCCESS(status = PhTerminateProcess(
1382  processHandle,
1383  1
1384  )))
1385  goto ErrorExit;
1386 
1387  NtClose(processHandle);
1388  processHandle = NULL;
1389 
1390  // Start the process.
1391 
1392  status = PhCreateProcessWin32(
1393  PhGetString(Process->FileName), // we didn't wait for S1 processing
1394  commandLine->Buffer,
1395  NULL,
1396  currentDirectory->Buffer,
1397  0,
1398  NULL,
1399  NULL,
1400  NULL
1401  );
1402 
1403 ErrorExit:
1404  if (processHandle)
1405  NtClose(processHandle);
1406 
1407  if (!NT_SUCCESS(status))
1408  {
1409  PhpShowErrorProcess(hWnd, L"restart", Process, status, 0);
1410  return FALSE;
1411  }
1412 
1413  return TRUE;
1414 }
1415 
1416 // Contributed by evilpie (#2981421)
1418  _In_ HWND hWnd,
1419  _In_ PPH_PROCESS_ITEM Process
1420  )
1421 {
1422  NTSTATUS status;
1423  BOOLEAN cont = FALSE;
1424  PH_STRING_BUILDER commandLineBuilder;
1425 
1426  if (PhGetIntegerSetting(L"EnableWarnings"))
1427  {
1428  cont = PhShowConfirmMessage(
1429  hWnd,
1430  L"debug",
1431  Process->ProcessName->Buffer,
1432  L"Debugging a process may result in loss of data.",
1433  FALSE
1434  );
1435  }
1436  else
1437  {
1438  cont = TRUE;
1439  }
1440 
1441  if (!cont)
1442  return FALSE;
1443 
1444  if (PhBeginInitOnce(&DebuggerCommandInitOnce))
1445  {
1446  static PH_STRINGREF aeDebugKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows NT\\CurrentVersion\\AeDebug");
1447 
1448  HANDLE keyHandle;
1449  PPH_STRING debugger;
1450  PH_STRINGREF commandPart;
1451  PH_STRINGREF dummy;
1452 
1453  if (NT_SUCCESS(PhOpenKey(
1454  &keyHandle,
1455  KEY_READ,
1457  &aeDebugKeyName,
1458  0
1459  )))
1460  {
1461  debugger = PhQueryRegistryString(keyHandle, L"Debugger");
1462 
1463  if (debugger)
1464  {
1465  if (PhSplitStringRefAtChar(&debugger->sr, '"', &dummy, &commandPart) &&
1466  PhSplitStringRefAtChar(&commandPart, '"', &commandPart, &dummy))
1467  {
1468  DebuggerCommand = PhCreateString2(&commandPart);
1469  }
1470 
1471  PhDereferenceObject(debugger);
1472  }
1473 
1474  NtClose(keyHandle);
1475  }
1476 
1477  PhEndInitOnce(&DebuggerCommandInitOnce);
1478  }
1479 
1480  if (!DebuggerCommand)
1481  {
1482  PhShowError(hWnd, L"Unable to locate the debugger.");
1483  return FALSE;
1484  }
1485 
1486  PhInitializeStringBuilder(&commandLineBuilder, DebuggerCommand->Length + 30);
1487 
1488  PhAppendCharStringBuilder(&commandLineBuilder, '"');
1489  PhAppendStringBuilder(&commandLineBuilder, &DebuggerCommand->sr);
1490  PhAppendCharStringBuilder(&commandLineBuilder, '"');
1491  PhAppendFormatStringBuilder(&commandLineBuilder, L" -p %u", (ULONG)Process->ProcessId);
1492 
1493  status = PhCreateProcessWin32(
1494  NULL,
1495  commandLineBuilder.String->Buffer,
1496  NULL,
1497  NULL,
1498  0,
1499  NULL,
1500  NULL,
1501  NULL
1502  );
1503 
1504  PhDeleteStringBuilder(&commandLineBuilder);
1505 
1506  if (!NT_SUCCESS(status))
1507  {
1508  PhpShowErrorProcess(hWnd, L"debug", Process, status, 0);
1509  return FALSE;
1510  }
1511 
1512  return TRUE;
1513 }
1514 
1516  _In_ HWND hWnd,
1517  _In_ PPH_PROCESS_ITEM *Processes,
1518  _In_ ULONG NumberOfProcesses
1519  )
1520 {
1521  BOOLEAN success = TRUE;
1522  ULONG i;
1523 
1524  for (i = 0; i < NumberOfProcesses; i++)
1525  {
1526  NTSTATUS status;
1527  HANDLE processHandle;
1528 
1529  if (NT_SUCCESS(status = PhOpenProcess(
1530  &processHandle,
1532  Processes[i]->ProcessId
1533  )))
1534  {
1535  QUOTA_LIMITS quotaLimits;
1536 
1537  memset(&quotaLimits, 0, sizeof(QUOTA_LIMITS));
1538  quotaLimits.MinimumWorkingSetSize = -1;
1539  quotaLimits.MaximumWorkingSetSize = -1;
1540 
1541  status = NtSetInformationProcess(
1542  processHandle,
1543  ProcessQuotaLimits,
1544  &quotaLimits,
1545  sizeof(QUOTA_LIMITS)
1546  );
1547 
1548  NtClose(processHandle);
1549  }
1550 
1551  if (!NT_SUCCESS(status))
1552  {
1553  success = FALSE;
1554 
1555  if (!PhpShowErrorProcess(hWnd, L"reduce the working set of", Processes[i], status, 0))
1556  break;
1557  }
1558  }
1559 
1560  return success;
1561 }
1562 
1564  _In_ HWND hWnd,
1565  _In_ PPH_PROCESS_ITEM Process,
1566  _In_ BOOLEAN Enable
1567  )
1568 {
1569  NTSTATUS status;
1570  BOOLEAN cont = FALSE;
1571  HANDLE processHandle;
1572  HANDLE tokenHandle;
1573 
1574  if (PhGetIntegerSetting(L"EnableWarnings"))
1575  {
1576  cont = PhShowConfirmMessage(
1577  hWnd,
1578  L"set",
1579  L"virtualization for the process",
1580  L"Enabling or disabling virtualization for a process may "
1581  L"alter its functionality and produce undesirable effects.",
1582  FALSE
1583  );
1584  }
1585  else
1586  {
1587  cont = TRUE;
1588  }
1589 
1590  if (!cont)
1591  return FALSE;
1592 
1593  if (NT_SUCCESS(status = PhOpenProcess(
1594  &processHandle,
1596  Process->ProcessId
1597  )))
1598  {
1599  if (NT_SUCCESS(status = PhOpenProcessToken(
1600  &tokenHandle,
1601  TOKEN_WRITE,
1602  processHandle
1603  )))
1604  {
1605  status = PhSetTokenIsVirtualizationEnabled(tokenHandle, Enable);
1606 
1607  NtClose(tokenHandle);
1608  }
1609 
1610  NtClose(processHandle);
1611  }
1612 
1613  if (!NT_SUCCESS(status))
1614  {
1615  PhpShowErrorProcess(hWnd, L"set virtualization for", Process, status, 0);
1616  return FALSE;
1617  }
1618 
1619  return TRUE;
1620 }
1621 
1623  _In_ HWND hWnd,
1624  _In_ PPH_PROCESS_ITEM Process
1625  )
1626 {
1627  NTSTATUS status;
1628  HANDLE processHandle;
1629  HANDLE debugObjectHandle;
1630 
1631  if (NT_SUCCESS(status = PhOpenProcess(
1632  &processHandle,
1634  Process->ProcessId
1635  )))
1636  {
1637  if (NT_SUCCESS(status = PhGetProcessDebugObject(
1638  processHandle,
1639  &debugObjectHandle
1640  )))
1641  {
1642  ULONG flags;
1643 
1644  // Disable kill-on-close.
1645  flags = 0;
1647  debugObjectHandle,
1649  &flags,
1650  sizeof(ULONG),
1651  NULL
1652  );
1653 
1654  status = NtRemoveProcessDebug(processHandle, debugObjectHandle);
1655 
1656  NtClose(debugObjectHandle);
1657  }
1658 
1659  NtClose(processHandle);
1660  }
1661 
1662  if (status == STATUS_PORT_NOT_SET)
1663  {
1664  PhShowInformation(hWnd, L"The process is not being debugged.");
1665  return FALSE;
1666  }
1667 
1668  if (!NT_SUCCESS(status))
1669  {
1670  PhpShowErrorProcess(hWnd, L"detach debugger from", Process, status, 0);
1671  return FALSE;
1672  }
1673 
1674  return TRUE;
1675 }
1676 
1678  _In_ HWND hWnd,
1679  _In_ PPH_PROCESS_ITEM Process
1680  )
1681 {
1682  static PH_FILETYPE_FILTER filters[] =
1683  {
1684  { L"DLL files (*.dll)", L"*.dll" },
1685  { L"All files (*.*)", L"*.*" }
1686  };
1687 
1688  NTSTATUS status;
1689  PVOID fileDialog;
1690  PPH_STRING fileName;
1691  HANDLE processHandle;
1692 
1693  fileDialog = PhCreateOpenFileDialog();
1694  PhSetFileDialogFilter(fileDialog, filters, sizeof(filters) / sizeof(PH_FILETYPE_FILTER));
1695 
1696  if (!PhShowFileDialog(hWnd, fileDialog))
1697  {
1698  PhFreeFileDialog(fileDialog);
1699  return FALSE;
1700  }
1701 
1702  fileName = PhAutoDereferenceObject(PhGetFileDialogFileName(fileDialog));
1703  PhFreeFileDialog(fileDialog);
1704 
1705  if (NT_SUCCESS(status = PhOpenProcess(
1706  &processHandle,
1709  Process->ProcessId
1710  )))
1711  {
1712  LARGE_INTEGER timeout;
1713 
1714  timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
1715  status = PhInjectDllProcess(
1716  processHandle,
1717  fileName->Buffer,
1718  &timeout
1719  );
1720 
1721  NtClose(processHandle);
1722  }
1723 
1724  if (!NT_SUCCESS(status))
1725  {
1726  PhpShowErrorProcess(hWnd, L"inject the DLL into", Process, status, 0);
1727  return FALSE;
1728  }
1729 
1730  return TRUE;
1731 }
1732 
1734  _In_ HWND hWnd,
1735  _In_ PPH_PROCESS_ITEM *Processes,
1736  _In_ ULONG NumberOfProcesses,
1737  _In_ ULONG IoPriority
1738  )
1739 {
1740  BOOLEAN success = TRUE;
1741  BOOLEAN cancelled = FALSE;
1742  ULONG i;
1743 
1744  for (i = 0; i < NumberOfProcesses; i++)
1745  {
1746  NTSTATUS status;
1747  HANDLE processHandle;
1748 
1749  if (NT_SUCCESS(status = PhOpenProcess(
1750  &processHandle,
1752  Processes[i]->ProcessId
1753  )))
1754  {
1755  status = PhSetProcessIoPriority(processHandle, IoPriority);
1756 
1757  NtClose(processHandle);
1758  }
1759 
1760  if (!NT_SUCCESS(status))
1761  {
1762  BOOLEAN connected;
1763 
1764  success = FALSE;
1765 
1766  // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.
1767  if (!cancelled && PhpShowErrorAndConnectToPhSvc(
1768  hWnd,
1769  PhaConcatStrings2(L"Unable to set the I/O priority of ", Processes[i]->ProcessName->Buffer)->Buffer,
1770  status,
1771  &connected
1772  ))
1773  {
1774  if (connected)
1775  {
1776  if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessIoPriority, IoPriority)))
1777  success = TRUE;
1778  else
1779  PhpShowErrorProcess(hWnd, L"set the I/O priority of", Processes[i], status, 0);
1780 
1782  }
1783  else
1784  {
1785  cancelled = TRUE;
1786  }
1787  }
1788  else
1789  {
1790  if (!PhpShowErrorProcess(hWnd, L"set the I/O priority of", Processes[i], status, 0))
1791  break;
1792  }
1793  }
1794  }
1795 
1796  return success;
1797 }
1798 
1800  _In_ HWND hWnd,
1801  _In_ PPH_PROCESS_ITEM Process,
1802  _In_ ULONG PagePriority
1803  )
1804 {
1805  NTSTATUS status;
1806  HANDLE processHandle;
1807 
1808  if (NT_SUCCESS(status = PhOpenProcess(
1809  &processHandle,
1811  Process->ProcessId
1812  )))
1813  {
1814  status = NtSetInformationProcess(
1815  processHandle,
1816  ProcessPagePriority,
1817  &PagePriority,
1818  sizeof(ULONG)
1819  );
1820 
1821  NtClose(processHandle);
1822  }
1823 
1824  if (!NT_SUCCESS(status))
1825  {
1826  PhpShowErrorProcess(hWnd, L"set the page priority of", Process, status, 0);
1827  return FALSE;
1828  }
1829 
1830  return TRUE;
1831 }
1832 
1834  _In_ HWND hWnd,
1835  _In_ PPH_PROCESS_ITEM *Processes,
1836  _In_ ULONG NumberOfProcesses,
1837  _In_ ULONG PriorityClass
1838  )
1839 {
1840  BOOLEAN success = TRUE;
1841  BOOLEAN cancelled = FALSE;
1842  ULONG i;
1843 
1844  for (i = 0; i < NumberOfProcesses; i++)
1845  {
1846  NTSTATUS status;
1847  HANDLE processHandle;
1848  PROCESS_PRIORITY_CLASS priorityClass;
1849 
1850  if (NT_SUCCESS(status = PhOpenProcess(
1851  &processHandle,
1853  Processes[i]->ProcessId
1854  )))
1855  {
1856  priorityClass.Foreground = FALSE;
1857  priorityClass.PriorityClass = (UCHAR)PriorityClass;
1858  status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS));
1859 
1860  NtClose(processHandle);
1861  }
1862 
1863  if (!NT_SUCCESS(status))
1864  {
1865  BOOLEAN connected;
1866 
1867  success = FALSE;
1868 
1869  // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.
1870  if (!cancelled && PhpShowErrorAndConnectToPhSvc(
1871  hWnd,
1872  PhaConcatStrings2(L"Unable to set the priority of ", Processes[i]->ProcessName->Buffer)->Buffer,
1873  status,
1874  &connected
1875  ))
1876  {
1877  if (connected)
1878  {
1879  if (NT_SUCCESS(status = PhSvcCallControlProcess(Processes[i]->ProcessId, PhSvcControlProcessPriority, PriorityClass)))
1880  success = TRUE;
1881  else
1882  PhpShowErrorProcess(hWnd, L"set the priority of", Processes[i], status, 0);
1883 
1885  }
1886  else
1887  {
1888  cancelled = TRUE;
1889  }
1890  }
1891  else
1892  {
1893  if (!PhpShowErrorProcess(hWnd, L"set the priority of", Processes[i], status, 0))
1894  break;
1895  }
1896  }
1897  }
1898 
1899  return success;
1900 }
1901 
1903  _In_ HWND hWnd,
1904  _In_ PPH_PROCESS_ITEM Process
1905  )
1906 {
1907  static WCHAR *choices[] = { L"Disabled", L"Enabled", L"Enabled, DEP-ATL thunk emulation disabled" };
1908  NTSTATUS status;
1909  HANDLE processHandle;
1910  ULONG depStatus;
1911  PPH_STRING selectedChoice;
1912  BOOLEAN selectedOption;
1913 
1914  // Get the initial DEP status of the process.
1915 
1916  if (NT_SUCCESS(status = PhOpenProcess(
1917  &processHandle,
1919  Process->ProcessId
1920  )))
1921  {
1922  if (NT_SUCCESS(status = PhGetProcessDepStatus(processHandle, &depStatus)))
1923  {
1924  ULONG choiceIndex;
1925 
1926  if (depStatus & PH_PROCESS_DEP_ENABLED)
1927  {
1929  choiceIndex = 2;
1930  else
1931  choiceIndex = 1;
1932  }
1933  else
1934  {
1935  choiceIndex = 0;
1936  }
1937 
1938  selectedChoice = PhaCreateString(choices[choiceIndex]);
1939  selectedOption = FALSE;
1940  }
1941 
1942  NtClose(processHandle);
1943  }
1944 
1945  if (!NT_SUCCESS(status))
1946  {
1947  PhpShowErrorProcess(hWnd, L"set the DEP status of", Process, status, 0);
1948  return FALSE;
1949  }
1950 
1951  while (PhaChoiceDialog(
1952  hWnd,
1953  L"DEP",
1954  L"DEP status:",
1955  choices,
1956  sizeof(choices) / sizeof(PWSTR),
1957  KphIsConnected() ? L"Permanent" : NULL, // if no KPH, SetProcessDEPPolicy determines permanency
1958  0,
1959  &selectedChoice,
1960  &selectedOption,
1961  NULL
1962  ))
1963  {
1964  // Build the new DEP status from the selected choice and option.
1965 
1966  depStatus = 0;
1967 
1968  if (PhEqualString2(selectedChoice, choices[0], FALSE))
1969  depStatus = 0;
1970  else if (PhEqualString2(selectedChoice, choices[1], FALSE))
1971  depStatus = PH_PROCESS_DEP_ENABLED;
1972  else if (PhEqualString2(selectedChoice, choices[2], FALSE))
1974 
1975  if (selectedOption)
1976  depStatus |= PH_PROCESS_DEP_PERMANENT;
1977 
1978  // Try to set the DEP status.
1979 
1980  if (NT_SUCCESS(status = PhOpenProcess(
1981  &processHandle,
1983  Process->ProcessId
1984  )))
1985  {
1986  if (KphIsConnected())
1987  {
1988  status = PhSetProcessDepStatus(processHandle, depStatus);
1989  }
1990  else
1991  {
1992  LARGE_INTEGER timeout;
1993 
1994  timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
1995  status = PhSetProcessDepStatusInvasive(processHandle, depStatus, &timeout);
1996  }
1997 
1998  NtClose(processHandle);
1999  }
2000 
2001  if (NT_SUCCESS(status))
2002  {
2003  return TRUE;
2004  }
2005  else if (status == STATUS_NOT_SUPPORTED)
2006  {
2007  if (PhShowError(
2008  hWnd,
2009  L"This feature is not supported by your operating system. "
2010  L"The minimum supported versions are Windows XP SP3 and Windows Vista SP1."
2011  ) != IDOK)
2012  break;
2013  }
2014  else
2015  {
2016  if (!PhpShowErrorProcess(hWnd, L"set the DEP status of", Process, status, 0))
2017  break;
2018  }
2019  }
2020 
2021  return FALSE;
2022 }
2023 
2025  _In_ HWND hWnd,
2026  _In_ PPH_PROCESS_ITEM Process
2027  )
2028 {
2029  static WCHAR *choices[] = { L"Protected", L"Not Protected" };
2030  NTSTATUS status;
2031  BOOLEAN result;
2032  HANDLE processHandle;
2033  KPH_PROCESS_PROTECTION_INFORMATION protectionInfo;
2034  PPH_STRING selectedChoice;
2035 
2037  return FALSE;
2038 
2039  if (!KphIsConnected())
2040  {
2042  return FALSE;
2043  }
2044 
2045  if (!NT_SUCCESS(status = PhOpenProcess(
2046  &processHandle,
2048  Process->ProcessId
2049  )))
2050  {
2051  PhShowStatus(hWnd, L"Unable to open the process", status, 0);
2052  return FALSE;
2053  }
2054 
2055  result = FALSE;
2056 
2058  processHandle,
2060  &protectionInfo,
2062  NULL
2063  )))
2064  {
2065  selectedChoice = PhaCreateString(protectionInfo.IsProtectedProcess ? L"Protected" : L"Not Protected");
2066 
2067  while (PhaChoiceDialog(hWnd, L"Protection", L"Protection:", choices, sizeof(choices) / sizeof(PWSTR),
2068  NULL, 0, &selectedChoice, NULL, NULL))
2069  {
2070  protectionInfo.IsProtectedProcess = PhEqualString2(selectedChoice, L"Protected", FALSE);
2071  status = KphSetInformationProcess(
2072  processHandle,
2074  &protectionInfo,
2076  );
2077 
2078  if (NT_SUCCESS(status))
2079  {
2080  result = TRUE;
2081  break;
2082  }
2083  else
2084  {
2085  if (!PhpShowErrorProcess(hWnd, L"set the protection of", Process, status, 0))
2086  break;
2087  }
2088  }
2089  }
2090  else
2091  {
2092  PhShowStatus(hWnd, L"Unable to query process protection", status, 0);
2093  }
2094 
2095  NtClose(processHandle);
2096 
2097  return result;
2098 }
2099 
2100 static VOID PhpShowErrorService(
2101  _In_ HWND hWnd,
2102  _In_ PWSTR Verb,
2103  _In_ PPH_SERVICE_ITEM Service,
2104  _In_ NTSTATUS Status,
2105  _In_opt_ ULONG Win32Result
2106  )
2107 {
2108  PhShowStatus(
2109  hWnd,
2111  L"Unable to %s %s",
2112  Verb,
2113  Service->Name->Buffer
2114  )->Buffer,
2115  Status,
2116  Win32Result
2117  );
2118 }
2119 
2121  _In_ HWND hWnd,
2122  _In_ PPH_SERVICE_ITEM Service
2123  )
2124 {
2125  SC_HANDLE serviceHandle;
2126  BOOLEAN success = FALSE;
2127 
2128  serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_START);
2129 
2130  if (serviceHandle)
2131  {
2132  if (StartService(serviceHandle, 0, NULL))
2133  success = TRUE;
2134 
2135  CloseServiceHandle(serviceHandle);
2136  }
2137 
2138  if (!success)
2139  {
2140  NTSTATUS status;
2141  BOOLEAN connected;
2142 
2143  status = PhGetLastWin32ErrorAsNtStatus();
2144 
2146  hWnd,
2147  PhaConcatStrings2(L"Unable to start ", Service->Name->Buffer)->Buffer,
2148  status,
2149  &connected
2150  ))
2151  {
2152  if (connected)
2153  {
2154  if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceStart)))
2155  success = TRUE;
2156  else
2157  PhpShowErrorService(hWnd, L"start", Service, status, 0);
2158 
2160  }
2161  }
2162  else
2163  {
2164  PhpShowErrorService(hWnd, L"start", Service, status, 0);
2165  }
2166  }
2167 
2168  return success;
2169 }
2170 
2172  _In_ HWND hWnd,
2173  _In_ PPH_SERVICE_ITEM Service
2174  )
2175 {
2176  SC_HANDLE serviceHandle;
2177  BOOLEAN success = FALSE;
2178 
2179  serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE);
2180 
2181  if (serviceHandle)
2182  {
2183  SERVICE_STATUS serviceStatus;
2184 
2185  if (ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus))
2186  success = TRUE;
2187 
2188  CloseServiceHandle(serviceHandle);
2189  }
2190 
2191  if (!success)
2192  {
2193  NTSTATUS status;
2194  BOOLEAN connected;
2195 
2196  status = PhGetLastWin32ErrorAsNtStatus();
2197 
2199  hWnd,
2200  PhaConcatStrings2(L"Unable to continue ", Service->Name->Buffer)->Buffer,
2201  status,
2202  &connected
2203  ))
2204  {
2205  if (connected)
2206  {
2207  if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceContinue)))
2208  success = TRUE;
2209  else
2210  PhpShowErrorService(hWnd, L"continue", Service, status, 0);
2211 
2213  }
2214  }
2215  else
2216  {
2217  PhpShowErrorService(hWnd, L"continue", Service, status, 0);
2218  }
2219  }
2220 
2221  return success;
2222 }
2223 
2225  _In_ HWND hWnd,
2226  _In_ PPH_SERVICE_ITEM Service
2227  )
2228 {
2229  SC_HANDLE serviceHandle;
2230  BOOLEAN success = FALSE;
2231 
2232  serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_PAUSE_CONTINUE);
2233 
2234  if (serviceHandle)
2235  {
2236  SERVICE_STATUS serviceStatus;
2237 
2238  if (ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus))
2239  success = TRUE;
2240 
2241  CloseServiceHandle(serviceHandle);
2242  }
2243 
2244  if (!success)
2245  {
2246  NTSTATUS status;
2247  BOOLEAN connected;
2248 
2249  status = PhGetLastWin32ErrorAsNtStatus();
2250 
2252  hWnd,
2253  PhaConcatStrings2(L"Unable to pause ", Service->Name->Buffer)->Buffer,
2254  status,
2255  &connected
2256  ))
2257  {
2258  if (connected)
2259  {
2260  if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServicePause)))
2261  success = TRUE;
2262  else
2263  PhpShowErrorService(hWnd, L"pause", Service, status, 0);
2264 
2266  }
2267  }
2268  else
2269  {
2270  PhpShowErrorService(hWnd, L"pause", Service, status, 0);
2271  }
2272  }
2273 
2274  return success;
2275 }
2276 
2278  _In_ HWND hWnd,
2279  _In_ PPH_SERVICE_ITEM Service
2280  )
2281 {
2282  SC_HANDLE serviceHandle;
2283  BOOLEAN success = FALSE;
2284 
2285  serviceHandle = PhOpenService(Service->Name->Buffer, SERVICE_STOP);
2286 
2287  if (serviceHandle)
2288  {
2289  SERVICE_STATUS serviceStatus;
2290 
2291  if (ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus))
2292  success = TRUE;
2293 
2294  CloseServiceHandle(serviceHandle);
2295  }
2296 
2297  if (!success)
2298  {
2299  NTSTATUS status;
2300  BOOLEAN connected;
2301 
2302  status = PhGetLastWin32ErrorAsNtStatus();
2303 
2305  hWnd,
2306  PhaConcatStrings2(L"Unable to stop ", Service->Name->Buffer)->Buffer,
2307  status,
2308  &connected
2309  ))
2310  {
2311  if (connected)
2312  {
2313  if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceStop)))
2314  success = TRUE;
2315  else
2316  PhpShowErrorService(hWnd, L"stop", Service, status, 0);
2317 
2319  }
2320  }
2321  else
2322  {
2323  PhpShowErrorService(hWnd, L"stop", Service, status, 0);
2324  }
2325  }
2326 
2327  return success;
2328 }
2329 
2331  _In_ HWND hWnd,
2332  _In_ PPH_SERVICE_ITEM Service
2333  )
2334 {
2335  SC_HANDLE serviceHandle;
2336  BOOLEAN success = FALSE;
2337 
2338  // Warnings cannot be disabled for service deletion.
2339  if (!PhShowConfirmMessage(
2340  hWnd,
2341  L"delete",
2342  Service->Name->Buffer,
2343  L"Deleting a service can prevent the system from starting "
2344  L"or functioning properly.",
2345  TRUE
2346  ))
2347  return FALSE;
2348 
2349  serviceHandle = PhOpenService(Service->Name->Buffer, DELETE);
2350 
2351  if (serviceHandle)
2352  {
2353  if (DeleteService(serviceHandle))
2354  success = TRUE;
2355 
2356  CloseServiceHandle(serviceHandle);
2357  }
2358 
2359  if (!success)
2360  {
2361  NTSTATUS status;
2362  BOOLEAN connected;
2363 
2364  status = PhGetLastWin32ErrorAsNtStatus();
2365 
2367  hWnd,
2368  PhaConcatStrings2(L"Unable to delete ", Service->Name->Buffer)->Buffer,
2369  status,
2370  &connected
2371  ))
2372  {
2373  if (connected)
2374  {
2375  if (NT_SUCCESS(status = PhSvcCallControlService(Service->Name->Buffer, PhSvcControlServiceDelete)))
2376  success = TRUE;
2377  else
2378  PhpShowErrorService(hWnd, L"delete", Service, status, 0);
2379 
2381  }
2382  }
2383  else
2384  {
2385  PhpShowErrorService(hWnd, L"delete", Service, status, 0);
2386  }
2387  }
2388 
2389  return success;
2390 }
2391 
2393  _In_ HWND hWnd,
2394  _In_ PPH_NETWORK_ITEM *Connections,
2395  _In_ ULONG NumberOfConnections
2396  )
2397 {
2398 
2399  BOOLEAN success = TRUE;
2400  BOOLEAN cancelled = FALSE;
2401  ULONG result;
2402  ULONG i;
2403  _SetTcpEntry SetTcpEntry_I;
2404  MIB_TCPROW tcpRow;
2405 
2406  SetTcpEntry_I = PhGetModuleProcAddress(L"iphlpapi.dll", "SetTcpEntry");
2407 
2408  if (!SetTcpEntry_I)
2409  {
2410  PhShowError(
2411  hWnd,
2412  L"This feature is not supported by your operating system."
2413  );
2414  return FALSE;
2415  }
2416 
2417  for (i = 0; i < NumberOfConnections; i++)
2418  {
2419  if (
2420  Connections[i]->ProtocolType != PH_TCP4_NETWORK_PROTOCOL ||
2421  Connections[i]->State != MIB_TCP_STATE_ESTAB
2422  )
2423  continue;
2424 
2425  tcpRow.dwState = MIB_TCP_STATE_DELETE_TCB;
2426  tcpRow.dwLocalAddr = Connections[i]->LocalEndpoint.Address.Ipv4;
2427  tcpRow.dwLocalPort = _byteswap_ushort((USHORT)Connections[i]->LocalEndpoint.Port);
2428  tcpRow.dwRemoteAddr = Connections[i]->RemoteEndpoint.Address.Ipv4;
2429  tcpRow.dwRemotePort = _byteswap_ushort((USHORT)Connections[i]->RemoteEndpoint.Port);
2430 
2431  if ((result = SetTcpEntry_I(&tcpRow)) != 0)
2432  {
2433  NTSTATUS status;
2434  BOOLEAN connected;
2435 
2436  success = FALSE;
2437 
2438  // SetTcpEntry returns ERROR_MR_MID_NOT_FOUND for access denied errors for some reason.
2439  if (result == ERROR_MR_MID_NOT_FOUND)
2440  result = ERROR_ACCESS_DENIED;
2441 
2442  if (!cancelled && PhpShowErrorAndConnectToPhSvc(
2443  hWnd,
2444  L"Unable to close the TCP connection",
2445  NTSTATUS_FROM_WIN32(result),
2446  &connected
2447  ))
2448  {
2449  if (connected)
2450  {
2451  if (NT_SUCCESS(status = PhSvcCallSetTcpEntry(&tcpRow)))
2452  success = TRUE;
2453  else
2454  PhShowStatus(hWnd, L"Unable to close the TCP connection", status, 0);
2455 
2457  }
2458  else
2459  {
2460  cancelled = TRUE;
2461  }
2462  }
2463  else
2464  {
2465  if (PhShowMessage(
2466  hWnd,
2467  MB_ICONERROR | MB_OKCANCEL,
2468  L"Unable to close the TCP connection (from %s:%u). "
2469  L"Make sure Process Hacker is running with administrative privileges.",
2470  Connections[i]->LocalAddressString,
2471  Connections[i]->LocalEndpoint.Port
2472  ) != IDOK)
2473  break;
2474  }
2475  }
2476  }
2477 
2478  return success;
2479 }
2480 
2481 static BOOLEAN PhpShowContinueMessageThreads(
2482  _In_ HWND hWnd,
2483  _In_ PWSTR Verb,
2484  _In_ PWSTR Message,
2485  _In_ BOOLEAN Warning,
2486  _In_ PPH_THREAD_ITEM *Threads,
2487  _In_ ULONG NumberOfThreads
2488  )
2489 {
2490  PWSTR object;
2491  BOOLEAN cont = FALSE;
2492 
2493  if (NumberOfThreads == 0)
2494  return FALSE;
2495 
2496  if (PhGetIntegerSetting(L"EnableWarnings"))
2497  {
2498  if (NumberOfThreads == 1)
2499  {
2500  object = L"the selected thread";
2501  }
2502  else
2503  {
2504  object = L"the selected threads";
2505  }
2506 
2507  cont = PhShowConfirmMessage(
2508  hWnd,
2509  Verb,
2510  object,
2511  Message,
2512  Warning
2513  );
2514  }
2515  else
2516  {
2517  cont = TRUE;
2518  }
2519 
2520  return cont;
2521 }
2522 
2523 static BOOLEAN PhpShowErrorThread(
2524  _In_ HWND hWnd,
2525  _In_ PWSTR Verb,
2526  _In_ PPH_THREAD_ITEM Thread,
2527  _In_ NTSTATUS Status,
2528  _In_opt_ ULONG Win32Result
2529  )
2530 {
2531  return PhShowContinueStatus(
2532  hWnd,
2534  L"Unable to %s thread %u",
2535  Verb,
2536  (ULONG)Thread->ThreadId
2537  )->Buffer,
2538  Status,
2539  Win32Result
2540  );
2541 }
2542 
2544  _In_ HWND hWnd,
2545  _In_ PPH_THREAD_ITEM *Threads,
2546  _In_ ULONG NumberOfThreads
2547  )
2548 {
2549  BOOLEAN success = TRUE;
2550  BOOLEAN cancelled = FALSE;
2551  ULONG i;
2552 
2553  if (!PhpShowContinueMessageThreads(
2554  hWnd,
2555  L"terminate",
2556  L"Terminating a thread may cause the process to stop working.",
2557  FALSE,
2558  Threads,
2559  NumberOfThreads
2560  ))
2561  return FALSE;
2562 
2563  for (i = 0; i < NumberOfThreads; i++)
2564  {
2565  NTSTATUS status;
2566  HANDLE threadHandle;
2567 
2568  if (NT_SUCCESS(status = PhOpenThread(
2569  &threadHandle,
2570  THREAD_TERMINATE,
2571  Threads[i]->ThreadId
2572  )))
2573  {
2574  status = PhTerminateThread(threadHandle, STATUS_SUCCESS);
2575  NtClose(threadHandle);
2576  }
2577 
2578  if (!NT_SUCCESS(status))
2579  {
2580  BOOLEAN connected;
2581 
2582  success = FALSE;
2583 
2584  if (!cancelled && PhpShowErrorAndConnectToPhSvc(
2585  hWnd,
2586  PhaFormatString(L"Unable to terminate thread %u", (ULONG)Threads[i]->ThreadId)->Buffer,
2587  status,
2588  &connected
2589  ))
2590  {
2591  if (connected)
2592  {
2593  if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadTerminate, 0)))
2594  success = TRUE;
2595  else
2596  PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0);
2597 
2599  }
2600  else
2601  {
2602  cancelled = TRUE;
2603  }
2604  }
2605  else
2606  {
2607  if (!PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0))
2608  break;
2609  }
2610  }
2611  }
2612 
2613  return success;
2614 }
2615 
2617  _In_ HWND hWnd,
2618  _In_ HANDLE ProcessId,
2619  _In_ PPH_THREAD_ITEM *Threads,
2620  _In_ ULONG NumberOfThreads
2621  )
2622 {
2623  BOOLEAN success = TRUE;
2624  ULONG i;
2625 
2626  if (!KphIsConnected())
2627  {
2629  return FALSE;
2630  }
2631 
2632  if (ProcessId != SYSTEM_PROCESS_ID)
2633  {
2634  if (!PhpShowContinueMessageThreads(
2635  hWnd,
2636  L"force terminate",
2637  L"Forcibly terminating threads may cause the system to crash or become unstable.",
2638  TRUE,
2639  Threads,
2640  NumberOfThreads
2641  ))
2642  return FALSE;
2643  }
2644  else
2645  {
2646  if (!PhpShowContinueMessageThreads(
2647  hWnd,
2648  L"terminate",
2649  L"Forcibly terminating system threads may cause the system to crash or become unstable.",
2650  TRUE,
2651  Threads,
2652  NumberOfThreads
2653  ))
2654  return FALSE;
2655  }
2656 
2657  for (i = 0; i < NumberOfThreads; i++)
2658  {
2659  NTSTATUS status;
2660  HANDLE threadHandle;
2661 
2662  if (NT_SUCCESS(status = PhOpenThread(
2663  &threadHandle,
2664  THREAD_TERMINATE,
2665  Threads[i]->ThreadId
2666  )))
2667  {
2668  status = KphTerminateThreadUnsafe(threadHandle, STATUS_SUCCESS);
2669  NtClose(threadHandle);
2670  }
2671 
2672  if (!NT_SUCCESS(status))
2673  {
2674  success = FALSE;
2675 
2676  if (!PhpShowErrorThread(hWnd, L"terminate", Threads[i], status, 0))
2677  break;
2678  }
2679  }
2680 
2681  return success;
2682 }
2683 
2685  _In_ HWND hWnd,
2686  _In_ PPH_THREAD_ITEM *Threads,
2687  _In_ ULONG NumberOfThreads
2688  )
2689 {
2690  BOOLEAN success = TRUE;
2691  BOOLEAN cancelled = FALSE;
2692  ULONG i;
2693 
2694  for (i = 0; i < NumberOfThreads; i++)
2695  {
2696  NTSTATUS status;
2697  HANDLE threadHandle;
2698 
2699  if (NT_SUCCESS(status = PhOpenThread(
2700  &threadHandle,
2701  THREAD_SUSPEND_RESUME,
2702  Threads[i]->ThreadId
2703  )))
2704  {
2705  status = PhSuspendThread(threadHandle, NULL);
2706  NtClose(threadHandle);
2707  }
2708 
2709  if (!NT_SUCCESS(status))
2710  {
2711  BOOLEAN connected;
2712 
2713  success = FALSE;
2714 
2715  if (!cancelled && PhpShowErrorAndConnectToPhSvc(
2716  hWnd,
2717  PhaFormatString(L"Unable to suspend thread %u", (ULONG)Threads[i]->ThreadId)->Buffer,
2718  status,
2719  &connected
2720  ))
2721  {
2722  if (connected)
2723  {
2724  if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadSuspend, 0)))
2725  success = TRUE;
2726  else
2727  PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0);
2728 
2730  }
2731  else
2732  {
2733  cancelled = TRUE;
2734  }
2735  }
2736  else
2737  {
2738  if (!PhpShowErrorThread(hWnd, L"suspend", Threads[i], status, 0))
2739  break;
2740  }
2741  }
2742  }
2743 
2744  return success;
2745 }
2746 
2748  _In_ HWND hWnd,
2749  _In_ PPH_THREAD_ITEM *Threads,
2750  _In_ ULONG NumberOfThreads
2751  )
2752 {
2753  BOOLEAN success = TRUE;
2754  BOOLEAN cancelled = FALSE;
2755  ULONG i;
2756 
2757  for (i = 0; i < NumberOfThreads; i++)
2758  {
2759  NTSTATUS status;
2760  HANDLE threadHandle;
2761 
2762  if (NT_SUCCESS(status = PhOpenThread(
2763  &threadHandle,
2764  THREAD_SUSPEND_RESUME,
2765  Threads[i]->ThreadId
2766  )))
2767  {
2768  status = PhResumeThread(threadHandle, NULL);
2769  NtClose(threadHandle);
2770  }
2771 
2772  if (!NT_SUCCESS(status))
2773  {
2774  BOOLEAN connected;
2775 
2776  success = FALSE;
2777 
2778  if (!cancelled && PhpShowErrorAndConnectToPhSvc(
2779  hWnd,
2780  PhaFormatString(L"Unable to resume thread %u", (ULONG)Threads[i]->ThreadId)->Buffer,
2781  status,
2782  &connected
2783  ))
2784  {
2785  if (connected)
2786  {
2787  if (NT_SUCCESS(status = PhSvcCallControlThread(Threads[i]->ThreadId, PhSvcControlThreadResume, 0)))
2788  success = TRUE;
2789  else
2790  PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0);
2791 
2793  }
2794  else
2795  {
2796  cancelled = TRUE;
2797  }
2798  }
2799  else
2800  {
2801  if (!PhpShowErrorThread(hWnd, L"resume", Threads[i], status, 0))
2802  break;
2803  }
2804  }
2805  }
2806 
2807  return success;
2808 }
2809 
2811  _In_ HWND hWnd,
2812  _In_ PPH_THREAD_ITEM Thread,
2813  _In_ ULONG ThreadPriorityWin32
2814  )
2815 {
2816  NTSTATUS status;
2817  ULONG win32Result = 0;
2818  HANDLE threadHandle;
2819 
2820  if (NT_SUCCESS(status = PhOpenThread(
2821  &threadHandle,
2823  Thread->ThreadId
2824  )))
2825  {
2826  if (!SetThreadPriority(threadHandle, ThreadPriorityWin32))
2827  win32Result = GetLastError();
2828 
2829  NtClose(threadHandle);
2830  }
2831 
2832  if (!NT_SUCCESS(status) || win32Result)
2833  {
2834  PhpShowErrorThread(hWnd, L"set the priority of", Thread, status, 0);
2835  return FALSE;
2836  }
2837 
2838  return TRUE;
2839 }
2840 
2842  _In_ HWND hWnd,
2843  _In_ PPH_THREAD_ITEM Thread,
2844  _In_ ULONG IoPriority
2845  )
2846 {
2847  NTSTATUS status;
2848  BOOLEAN success = TRUE;
2849  HANDLE threadHandle;
2850 
2851  if (NT_SUCCESS(status = PhOpenThread(
2852  &threadHandle,
2853  THREAD_SET_INFORMATION,
2854  Thread->ThreadId
2855  )))
2856  {
2857  status = PhSetThreadIoPriority(threadHandle, IoPriority);
2858 
2859  NtClose(threadHandle);
2860  }
2861 
2862  if (!NT_SUCCESS(status))
2863  {
2864  BOOLEAN connected;
2865 
2866  success = FALSE;
2867 
2868  // The operation may have failed due to the lack of SeIncreaseBasePriorityPrivilege.
2870  hWnd,
2871  PhaFormatString(L"Unable to set the I/O priority of thread %u", (ULONG)Thread->ThreadId)->Buffer,
2872  status,
2873  &connected
2874  ))
2875  {
2876  if (connected)
2877  {
2878  if (NT_SUCCESS(status = PhSvcCallControlThread(Thread->ThreadId, PhSvcControlThreadIoPriority, IoPriority)))
2879  success = TRUE;
2880  else
2881  PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0);
2882 
2884  }
2885  }
2886  else
2887  {
2888  PhpShowErrorThread(hWnd, L"set the I/O priority of", Thread, status, 0);
2889  }
2890  }
2891 
2892  return success;
2893 }
2894 
2896  _In_ HWND hWnd,
2897  _In_ PPH_THREAD_ITEM Thread,
2898  _In_ ULONG PagePriority
2899  )
2900 {
2901  NTSTATUS status;
2902  HANDLE threadHandle;
2903 
2904  if (NT_SUCCESS(status = PhOpenThread(
2905  &threadHandle,
2906  THREAD_SET_INFORMATION,
2907  Thread->ThreadId
2908  )))
2909  {
2910  status = NtSetInformationThread(
2911  threadHandle,
2912  ThreadPagePriority,
2913  &PagePriority,
2914  sizeof(ULONG)
2915  );
2916 
2917  NtClose(threadHandle);
2918  }
2919 
2920  if (!NT_SUCCESS(status))
2921  {
2922  PhpShowErrorThread(hWnd, L"set the page priority of", Thread, status, 0);
2923  return FALSE;
2924  }
2925 
2926  return TRUE;
2927 }
2928 
2930  _In_ HWND hWnd,
2931  _In_ HANDLE ProcessId,
2932  _In_ PPH_MODULE_ITEM Module
2933  )
2934 {
2935  NTSTATUS status;
2936  BOOLEAN cont = FALSE;
2937  HANDLE processHandle;
2938 
2939  if (PhGetIntegerSetting(L"EnableWarnings"))
2940  {
2941  PWSTR verb;
2942  PWSTR message;
2943 
2944  switch (Module->Type)
2945  {
2946  case PH_MODULE_TYPE_MODULE:
2948  verb = L"unload";
2949  message = L"Unloading a module may cause the process to crash.";
2950 
2951  if (WindowsVersion >= WINDOWS_8)
2952  message = L"Unloading a module may cause the process to crash. NOTE: This feature may not work correctly on your version of Windows.";
2953 
2954  break;
2956  verb = L"unload";
2957  message = L"Unloading a driver may cause system instability.";
2958  break;
2961  verb = L"unmap";
2962  message = L"Unmapping a section view may cause the process to crash.";
2963  break;
2964  default:
2965  return FALSE;
2966  }
2967 
2968  cont = PhShowConfirmMessage(
2969  hWnd,
2970  verb,
2971  Module->Name->Buffer,
2972  message,
2973  TRUE
2974  );
2975  }
2976  else
2977  {
2978  cont = TRUE;
2979  }
2980 
2981  if (!cont)
2982  return FALSE;
2983 
2984  switch (Module->Type)
2985  {
2986  case PH_MODULE_TYPE_MODULE:
2988  if (NT_SUCCESS(status = PhOpenProcess(
2989  &processHandle,
2992  ProcessId
2993  )))
2994  {
2995  LARGE_INTEGER timeout;
2996 
2997  timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
2998  status = PhUnloadDllProcess(
2999  processHandle,
3000  Module->BaseAddress,
3001  &timeout
3002  );
3003 
3004  NtClose(processHandle);
3005  }
3006 
3007  if (status == STATUS_DLL_NOT_FOUND)
3008  {
3009  PhShowError(hWnd, L"Unable to find the module to unload.");
3010  return FALSE;
3011  }
3012 
3013  if (!NT_SUCCESS(status))
3014  {
3015  PhShowStatus(
3016  hWnd,
3017  PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer,
3018  status,
3019  0
3020  );
3021  return FALSE;
3022  }
3023 
3024  break;
3025 
3027  status = PhUnloadDriver(Module->BaseAddress, Module->Name->Buffer);
3028 
3029  if (!NT_SUCCESS(status))
3030  {
3031  BOOLEAN success = FALSE;
3032  BOOLEAN connected;
3033 
3035  hWnd,
3036  PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer,
3037  status,
3038  &connected
3039  ))
3040  {
3041  if (connected)
3042  {
3043  if (NT_SUCCESS(status = PhSvcCallUnloadDriver(Module->BaseAddress, Module->Name->Buffer)))
3044  success = TRUE;
3045  else
3046  PhShowStatus(hWnd, PhaConcatStrings2(L"Unable to unload ", Module->Name->Buffer)->Buffer, status, 0);
3047 
3049  }
3050  }
3051  else
3052  {
3053  PhShowStatus(
3054  hWnd,
3056  3,
3057  L"Unable to unload ",
3058  Module->Name->Buffer,
3059  L". Make sure Process Hacker is running with "
3060  L"administrative privileges. Error"
3061  )->Buffer,
3062  status,
3063  0
3064  );
3065  return FALSE;
3066  }
3067 
3068  return success;
3069  }
3070 
3071  break;
3072 
3075  if (NT_SUCCESS(status = PhOpenProcess(
3076  &processHandle,
3078  ProcessId
3079  )))
3080  {
3081  status = NtUnmapViewOfSection(processHandle, Module->BaseAddress);
3082  NtClose(processHandle);
3083  }
3084 
3085  if (!NT_SUCCESS(status))
3086  {
3087  PhShowStatus(
3088  hWnd,
3089  PhaFormatString(L"Unable to unmap the section view at 0x%Ix", Module->BaseAddress)->Buffer,
3090  status,
3091  0
3092  );
3093  return FALSE;
3094  }
3095 
3096  break;
3097 
3098  default:
3099  return FALSE;
3100  }
3101 
3102  return TRUE;
3103 }
3104 
3106  _In_ HWND hWnd,
3107  _In_ HANDLE ProcessId,
3108  _In_ PPH_MEMORY_ITEM MemoryItem,
3109  _In_ BOOLEAN Free
3110  )
3111 {
3112  NTSTATUS status;
3113  BOOLEAN cont = FALSE;
3114  HANDLE processHandle;
3115 
3116  if (PhGetIntegerSetting(L"EnableWarnings"))
3117  {
3118  PWSTR verb;
3119  PWSTR message;
3120 
3121  if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))
3122  {
3123  if (Free)
3124  {
3125  verb = L"free";
3126  message = L"Freeing memory regions may cause the process to crash.";
3127  }
3128  else
3129  {
3130  verb = L"decommit";
3131  message = L"Decommitting memory regions may cause the process to crash.";
3132  }
3133  }
3134  else
3135  {
3136  verb = L"unmap";
3137  message = L"Unmapping a section view may cause the process to crash.";
3138  }
3139 
3140  cont = PhShowConfirmMessage(
3141  hWnd,
3142  verb,
3143  L"the memory region",
3144  message,
3145  TRUE
3146  );
3147  }
3148  else
3149  {
3150  cont = TRUE;
3151  }
3152 
3153  if (!cont)
3154  return FALSE;
3155 
3156  if (NT_SUCCESS(status = PhOpenProcess(
3157  &processHandle,
3159  ProcessId
3160  )))
3161  {
3162  PVOID baseAddress;
3163  SIZE_T regionSize;
3164 
3165  baseAddress = MemoryItem->BaseAddress;
3166 
3167  if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))
3168  {
3169  // The size needs to be 0 if we're freeing.
3170  if (Free)
3171  regionSize = 0;
3172  else
3173  regionSize = MemoryItem->RegionSize;
3174 
3175  status = NtFreeVirtualMemory(
3176  processHandle,
3177  &baseAddress,
3178  &regionSize,
3179  Free ? MEM_RELEASE : MEM_DECOMMIT
3180  );
3181  }
3182  else
3183  {
3184  status = NtUnmapViewOfSection(processHandle, baseAddress);
3185  }
3186 
3187  NtClose(processHandle);
3188  }
3189 
3190  if (!NT_SUCCESS(status))
3191  {
3192  PWSTR message;
3193 
3194  if (!(MemoryItem->Type & (MEM_MAPPED | MEM_IMAGE)))
3195  {
3196  if (Free)
3197  message = L"Unable to free the memory region";
3198  else
3199  message = L"Unable to decommit the memory region";
3200  }
3201  else
3202  {
3203  message = L"Unable to unmap the section view";
3204  }
3205 
3206  PhShowStatus(
3207  hWnd,
3208  message,
3209  status,
3210  0
3211  );
3212  return FALSE;
3213  }
3214 
3215  return TRUE;
3216 }
3217 
3218 static BOOLEAN PhpShowErrorHandle(
3219  _In_ HWND hWnd,
3220  _In_ PWSTR Verb,
3221  _In_ PPH_HANDLE_ITEM Handle,
3222  _In_ NTSTATUS Status,
3223  _In_opt_ ULONG Win32Result
3224  )
3225 {
3226  if (!PhIsNullOrEmptyString(Handle->BestObjectName))
3227  {
3228  return PhShowContinueStatus(
3229  hWnd,
3231  L"Unable to %s handle \"%s\" (0x%Ix)",
3232  Verb,
3233  Handle->BestObjectName->Buffer,
3234  (ULONG)Handle->Handle
3235  )->Buffer,
3236  Status,
3237  Win32Result
3238  );
3239  }
3240  else
3241  {
3242  return PhShowContinueStatus(
3243  hWnd,
3245  L"Unable to %s handle 0x%Ix",
3246  Verb,
3247  (ULONG)Handle->Handle
3248  )->Buffer,
3249  Status,
3250  Win32Result
3251  );
3252  }
3253 }
3254 
3256  _In_ HWND hWnd,
3257  _In_ HANDLE ProcessId,
3258  _In_ PPH_HANDLE_ITEM *Handles,
3259  _In_ ULONG NumberOfHandles,
3260  _In_ BOOLEAN Warn
3261  )
3262 {
3263  NTSTATUS status;
3264  BOOLEAN cont = FALSE;
3265  BOOLEAN success = TRUE;
3266  HANDLE processHandle;
3267 
3268  if (NumberOfHandles == 0)
3269  return FALSE;
3270 
3271  if (Warn && PhGetIntegerSetting(L"EnableWarnings"))
3272  {
3273  cont = PhShowConfirmMessage(
3274  hWnd,
3275  L"close",
3276  NumberOfHandles == 1 ? L"the selected handle" : L"the selected handles",
3277  L"Closing handles may cause system instability and data corruption.",
3278  FALSE
3279  );
3280  }
3281  else
3282  {
3283  cont = TRUE;
3284  }
3285 
3286  if (!cont)
3287  return FALSE;
3288 
3289  if (NT_SUCCESS(status = PhOpenProcess(
3290  &processHandle,
3291  PROCESS_DUP_HANDLE,
3292  ProcessId
3293  )))
3294  {
3295  ULONG i;
3296 
3297  for (i = 0; i < NumberOfHandles; i++)
3298  {
3299  status = PhDuplicateObject(
3300  processHandle,
3301  Handles[i]->Handle,
3302  NULL,
3303  NULL,
3304  0,
3305  0,
3306  DUPLICATE_CLOSE_SOURCE
3307  );
3308 
3309  if (!NT_SUCCESS(status))
3310  {
3311  success = FALSE;
3312 
3313  if (!PhpShowErrorHandle(
3314  hWnd,
3315  L"close",
3316  Handles[i],
3317  status,
3318  0
3319  ))
3320  break;
3321  }
3322  }
3323 
3324  NtClose(processHandle);
3325  }
3326  else
3327  {
3328  PhShowStatus(hWnd, L"Unable to open the process", status, 0);
3329  return FALSE;
3330  }
3331 
3332  return success;
3333 }
3334 
3336  _In_ HWND hWnd,
3337  _In_ HANDLE ProcessId,
3338  _In_ PPH_HANDLE_ITEM Handle,
3339  _In_ ULONG Attributes
3340  )
3341 {
3342  NTSTATUS status;
3343  HANDLE processHandle;
3344 
3345  if (!KphIsConnected())
3346  {
3348  return FALSE;
3349  }
3350 
3351  if (NT_SUCCESS(status = PhOpenProcess(
3352  &processHandle,
3354  ProcessId
3355  )))
3356  {
3357  OBJECT_HANDLE_FLAG_INFORMATION handleFlagInfo;
3358 
3359  handleFlagInfo.Inherit = !!(Attributes & OBJ_INHERIT);
3360  handleFlagInfo.ProtectFromClose = !!(Attributes & OBJ_PROTECT_CLOSE);
3361 
3362  status = KphSetInformationObject(
3363  processHandle,
3364  Handle->Handle,
3366  &handleFlagInfo,
3368  );
3369 
3370  NtClose(processHandle);
3371  }
3372 
3373  if (!NT_SUCCESS(status))
3374  {
3375  PhpShowErrorHandle(hWnd, L"set attributes of", Handle, status, 0);
3376  return FALSE;
3377  }
3378 
3379  return TRUE;
3380 }