Process Hacker
main.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * main program
4  *
5  * Copyright (C) 2009-2012 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 <kphuser.h>
25 #include <phsvc.h>
26 #include <settings.h>
27 #include <extmgri.h>
28 #include <hexedit.h>
29 #include <colorbox.h>
30 #include <shlobj.h>
31 
33  VOID
34  );
35 
37  VOID
38  );
39 
41  VOID
42  );
43 
45  VOID
46  );
47 
48 BOOLEAN PhInitializeAppSystem(
49  VOID
50  );
51 
53  VOID
54  );
55 
57  VOID
58  );
59 
61  VOID
62  );
63 
68 HINSTANCE PhInstanceHandle;
75 
78 
79 static PPH_LIST DialogList = NULL;
80 static PPH_LIST FilterList = NULL;
81 static PH_AUTO_POOL BaseAutoPool;
82 
83 INT WINAPI wWinMain(
84  _In_ HINSTANCE hInstance,
85  _In_opt_ HINSTANCE hPrevInstance,
86  _In_ PWSTR lpCmdLine,
87  _In_ INT nCmdShow
88  )
89 {
90  LONG result;
91 #ifdef DEBUG
92  PHP_BASE_THREAD_DBG dbg;
93 #endif
94 
95  CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
96  SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX);
97 
98  PhInstanceHandle = (HINSTANCE)NtCurrentPeb()->ImageBaseAddress;
99 
101  return 1;
102  if (!PhInitializeAppSystem())
103  return 1;
104 
106 
108  {
109  PTOKEN_USER tokenUser;
110 
112  {
113  PhCurrentUserName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL);
114  PhFree(tokenUser);
115  }
116  }
117 
118  PhLocalSystemName = PhGetSidFullName(&PhSeLocalSystemSid, TRUE, NULL);
119 
120  // There has been a report of the above call failing.
121  if (!PhLocalSystemName)
122  PhLocalSystemName = PhCreateString(L"NT AUTHORITY\\SYSTEM");
123 
124  PhApplicationFileName = PhGetApplicationFileName();
125  PhApplicationDirectory = PhGetApplicationDirectory();
126 
127  // Just in case
128  if (!PhApplicationFileName)
129  PhApplicationFileName = PhCreateString(L"ProcessHacker.exe");
130  if (!PhApplicationDirectory)
131  PhApplicationDirectory = PhReferenceEmptyString();
132 
136 
137  if (PhStartupParameters.RunAsServiceMode)
138  {
140  }
141 
143 
144  // Activate a previous instance if required.
145  if (PhGetIntegerSetting(L"AllowOnlyOneInstance") &&
146  !PhStartupParameters.NewInstance &&
147  !PhStartupParameters.ShowOptions &&
148  !PhStartupParameters.CommandMode &&
149  !PhStartupParameters.PhSvc)
150  {
152  }
153 
154  if (PhGetIntegerSetting(L"EnableKph") && !PhStartupParameters.NoKph && !PhIsExecutingInWow64())
155  PhInitializeKph();
156 
157  if (PhStartupParameters.CommandMode && PhStartupParameters.CommandType && PhStartupParameters.CommandAction)
158  {
159  NTSTATUS status;
160 
161  status = PhCommandModeStart();
162 
163  if (!NT_SUCCESS(status) && !PhStartupParameters.Silent)
164  {
165  PhShowStatus(NULL, L"Unable to execute the command", status, 0);
166  }
167 
168  RtlExitUserProcess(status);
169  }
170 
171 #ifdef DEBUG
172  dbg.ClientId = NtCurrentTeb()->ClientId;
173  dbg.StartAddress = wWinMain;
174  dbg.Parameter = NULL;
175  InsertTailList(&PhDbgThreadListHead, &dbg.ListEntry);
176  TlsSetValue(PhDbgThreadDbgTlsIndex, &dbg);
177 #endif
178 
179  PhInitializeAutoPool(&BaseAutoPool);
180 
187 
188  PhSmallIconSize.X = GetSystemMetrics(SM_CXSMICON);
189  PhSmallIconSize.Y = GetSystemMetrics(SM_CYSMICON);
190  PhLargeIconSize.X = GetSystemMetrics(SM_CXICON);
191  PhLargeIconSize.Y = GetSystemMetrics(SM_CYICON);
192 
193  if (PhStartupParameters.ShowOptions)
194  {
195  // Elevated options dialog for changing the value of Replace Task Manager with Process Hacker.
196  PhShowOptionsDialog(PhStartupParameters.WindowHandle);
197  RtlExitUserProcess(STATUS_SUCCESS);
198  }
199 
200  if (PhIsExecutingInWow64() && !PhStartupParameters.PhSvc)
201  {
203  NULL,
204  L"You are attempting to run the 32-bit version of Process Hacker on 64-bit Windows. "
205  L"Most features will not work correctly.\n\n"
206  L"Please run the 64-bit version of Process Hacker instead."
207  );
208  }
209 
210  PhPluginsEnabled = PhGetIntegerSetting(L"EnablePlugins") && !PhStartupParameters.NoPlugins;
211 
212  if (PhPluginsEnabled)
213  {
215  PhLoadPlugins();
216  }
217 
218  if (PhStartupParameters.PhSvc)
219  {
220  MSG message;
221 
222  // Turn the feedback cursor off.
223  PostMessage(NULL, WM_NULL, 0, 0);
224  GetMessage(&message, NULL, 0, 0);
225 
226  RtlExitUserProcess(PhSvcMain(NULL, NULL, NULL));
227  }
228 
229  // Create a mutant for the installer.
230  {
231  HANDLE mutantHandle;
233  UNICODE_STRING mutantName;
234 
235  RtlInitUnicodeString(&mutantName, L"\\BaseNamedObjects\\ProcessHacker2Mutant");
237  &oa,
238  &mutantName,
239  0,
240  NULL,
241  NULL
242  );
243 
244  NtCreateMutant(&mutantHandle, MUTANT_ALL_ACCESS, &oa, FALSE);
245  }
246 
247  // Set priority.
248  {
249  PROCESS_PRIORITY_CLASS priorityClass;
250 
251  priorityClass.Foreground = FALSE;
253 
254  if (PhStartupParameters.PriorityClass != 0)
255  priorityClass.PriorityClass = (UCHAR)PhStartupParameters.PriorityClass;
256 
257  NtSetInformationProcess(NtCurrentProcess(), ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS));
258  }
259 
260  if (!PhMainWndInitialization(nCmdShow))
261  {
262  PhShowError(NULL, L"Unable to initialize the main window.");
263  return 1;
264  }
265 
266  PhDrainAutoPool(&BaseAutoPool);
267 
268  result = PhMainMessageLoop();
269  RtlExitUserProcess(result);
270 }
271 
273  VOID
274  )
275 {
276  BOOL result;
277  MSG message;
278  HACCEL acceleratorTable;
279 
280  acceleratorTable = LoadAccelerators(PhInstanceHandle, MAKEINTRESOURCE(IDR_MAINWND_ACCEL));
281 
282  while (result = GetMessage(&message, NULL, 0, 0))
283  {
284  BOOLEAN processed = FALSE;
285  ULONG i;
286 
287  if (result == -1)
288  return 1;
289 
290  if (FilterList)
291  {
292  for (i = 0; i < FilterList->Count; i++)
293  {
294  PPH_MESSAGE_LOOP_FILTER_ENTRY entry = FilterList->Items[i];
295 
296  if (entry->Filter(&message, entry->Context))
297  {
298  processed = TRUE;
299  break;
300  }
301  }
302  }
303 
304  if (!processed)
305  {
306  if (
307  message.hwnd == PhMainWndHandle ||
308  IsChild(PhMainWndHandle, message.hwnd)
309  )
310  {
311  if (TranslateAccelerator(PhMainWndHandle, acceleratorTable, &message))
312  processed = TRUE;
313  }
314 
315  if (DialogList)
316  {
317  for (i = 0; i < DialogList->Count; i++)
318  {
319  if (IsDialogMessage((HWND)DialogList->Items[i], &message))
320  {
321  processed = TRUE;
322  break;
323  }
324  }
325  }
326  }
327 
328  if (!processed)
329  {
330  TranslateMessage(&message);
331  DispatchMessage(&message);
332  }
333 
334  PhDrainAutoPool(&BaseAutoPool);
335  }
336 
337  return (LONG)message.wParam;
338 }
339 
341  _In_ HWND DialogWindowHandle
342  )
343 {
344  if (!DialogList)
345  DialogList = PhCreateList(2);
346 
347  PhAddItemList(DialogList, (PVOID)DialogWindowHandle);
348 }
349 
351  _In_ HWND DialogWindowHandle
352  )
353 {
354  ULONG indexOfDialog;
355 
356  if (!DialogList)
357  return;
358 
359  indexOfDialog = PhFindItemList(DialogList, (PVOID)DialogWindowHandle);
360 
361  if (indexOfDialog != -1)
362  PhRemoveItemList(DialogList, indexOfDialog);
363 }
364 
367  _In_opt_ PVOID Context
368  )
369 {
371 
372  if (!FilterList)
373  FilterList = PhCreateList(2);
374 
375  entry = PhAllocate(sizeof(PH_MESSAGE_LOOP_FILTER_ENTRY));
376  entry->Filter = Filter;
377  entry->Context = Context;
378  PhAddItemList(FilterList, entry);
379 
380  return entry;
381 }
382 
384  _In_ struct _PH_MESSAGE_LOOP_FILTER_ENTRY *FilterEntry
385  )
386 {
387  ULONG indexOfFilter;
388 
389  if (!FilterList)
390  return;
391 
392  indexOfFilter = PhFindItemList(FilterList, FilterEntry);
393 
394  if (indexOfFilter != -1)
395  PhRemoveItemList(FilterList, indexOfFilter);
396 
397  PhFree(FilterEntry);
398 }
399 
401  VOID
402  )
403 {
404  HWND hwnd;
405 
406  hwnd = FindWindow(PH_MAINWND_CLASSNAME, NULL);
407 
408  if (hwnd)
409  {
410  ULONG_PTR result;
411 
412  SendMessageTimeout(hwnd, WM_PH_ACTIVATE, PhStartupParameters.SelectPid, 0, SMTO_BLOCK, 5000, &result);
413 
414  if (result == PH_ACTIVATE_REPLY)
415  {
416  SetForegroundWindow(hwnd);
417  RtlExitUserProcess(STATUS_SUCCESS);
418  }
419  }
420 }
421 
423  VOID
424  )
425 {
426  INITCOMMONCONTROLSEX icex;
427 
428  icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
429  icex.dwICC =
430  ICC_LINK_CLASS |
431  ICC_LISTVIEW_CLASSES |
432  ICC_PROGRESS_CLASS |
433  ICC_TAB_CLASSES
434  ;
435 
436  InitCommonControlsEx(&icex);
437 }
438 
440  _In_ HWND hWnd,
441  _In_ PWSTR Name,
442  _In_ ULONG Size,
443  _In_ ULONG Weight
444  )
445 {
446  HFONT font;
447  HDC hdc;
448 
449  hdc = GetDC(hWnd);
450 
451  if (hdc)
452  {
453  font = CreateFont(
454  -MulDiv(Size, GetDeviceCaps(hdc, LOGPIXELSY), 72),
455  0,
456  0,
457  0,
458  Weight,
459  FALSE,
460  FALSE,
461  FALSE,
462  ANSI_CHARSET,
463  OUT_DEFAULT_PRECIS,
464  CLIP_DEFAULT_PRECIS,
465  DEFAULT_QUALITY,
466  DEFAULT_PITCH,
467  Name
468  );
469  ReleaseDC(hWnd, hdc);
470 
471  return font;
472  }
473  else
474  {
475  return NULL;
476  }
477 }
478 
480  _In_ HWND hWnd
481  )
482 {
483  NONCLIENTMETRICS metrics = { sizeof(metrics) };
484  BOOLEAN success;
485 
486  success = !!SystemParametersInfo(SPI_GETNONCLIENTMETRICS, 0, &metrics, 0);
487 
488  if (
489  !(PhApplicationFont = PhpCreateFont(hWnd, L"Microsoft Sans Serif", 8, FW_NORMAL)) &&
490  !(PhApplicationFont = PhpCreateFont(hWnd, L"Tahoma", 8, FW_NORMAL))
491  )
492  {
493  if (success)
494  PhApplicationFont = CreateFontIndirect(&metrics.lfMessageFont);
495  else
496  PhApplicationFont = NULL;
497  }
498 }
499 
501  VOID
502  )
503 {
504  static PH_STRINGREF kprocesshacker = PH_STRINGREF_INIT(L"kprocesshacker.sys");
505  PPH_STRING kprocesshackerFileName;
506  KPH_PARAMETERS parameters;
507 
508  // Append kprocesshacker.sys to the application directory.
509  kprocesshackerFileName = PhConcatStringRef2(&PhApplicationDirectory->sr, &kprocesshacker);
510 
512  parameters.CreateDynamicConfiguration = TRUE;
513 
514  KphConnect2Ex(L"KProcessHacker2", kprocesshackerFileName->Buffer, &parameters);
515  PhDereferenceObject(kprocesshackerFileName);
516 }
517 
519  VOID
520  )
521 {
522  PhApplicationName = L"Process Hacker";
523 
525  return FALSE;
527  return FALSE;
529  return FALSE;
531  return FALSE;
533  return FALSE;
535  return FALSE;
537  return FALSE;
539  return FALSE;
540 
542 
543  return TRUE;
544 }
545 
547  VOID
548  )
549 {
550  NTSTATUS status;
551 
552  if (!PhStartupParameters.NoSettings)
553  {
554  static PH_STRINGREF settingsSuffix = PH_STRINGREF_INIT(L".settings.xml");
555  PPH_STRING settingsFileName;
556 
557  // There are three possible locations for the settings file:
558  // 1. The file name given in the command line.
559  // 2. A file named ProcessHacker.exe.settings.xml in the program directory. (This changes
560  // based on the executable file name.)
561  // 3. The default location.
562 
563  // 1. File specified in command line
564  if (PhStartupParameters.SettingsFileName)
565  {
566  // Get an absolute path now.
567  PhSettingsFileName = PhGetFullPath(PhStartupParameters.SettingsFileName->Buffer, NULL);
568  }
569 
570  // 2. File in program directory
571  if (!PhSettingsFileName)
572  {
573  settingsFileName = PhConcatStringRef2(&PhApplicationFileName->sr, &settingsSuffix);
574 
575  if (RtlDoesFileExists_U(settingsFileName->Buffer))
576  {
577  PhSettingsFileName = settingsFileName;
578  }
579  else
580  {
581  PhDereferenceObject(settingsFileName);
582  }
583  }
584 
585  // 3. Default location
586  if (!PhSettingsFileName)
587  {
588  PhSettingsFileName = PhGetKnownLocation(CSIDL_APPDATA, L"\\Process Hacker 2\\settings.xml");
589  }
590 
591  if (PhSettingsFileName)
592  {
593  status = PhLoadSettings(PhSettingsFileName->Buffer);
594 
595  // If we didn't find the file, it will be created. Otherwise,
596  // there was probably a parsing error and we don't want to
597  // change anything.
598  if (status == STATUS_FILE_CORRUPT_ERROR)
599  {
600  if (PhShowMessage(
601  NULL,
602  MB_ICONWARNING | MB_YESNO,
603  L"Process Hacker's settings file is corrupt. Do you want to reset it?\n"
604  L"If you select No, the settings system will not function properly."
605  ) == IDYES)
606  {
607  HANDLE fileHandle;
608  IO_STATUS_BLOCK isb;
609  CHAR data[] = "<settings></settings>";
610 
611  // This used to delete the file. But it's better to keep the file there
612  // and overwrite it with some valid XML, especially with case (2) above.
614  &fileHandle,
615  PhSettingsFileName->Buffer,
616  FILE_GENERIC_WRITE,
617  0,
618  FILE_SHARE_READ | FILE_SHARE_DELETE,
621  )))
622  {
623  NtWriteFile(fileHandle, NULL, NULL, NULL, &isb, data, sizeof(data) - 1, NULL, NULL);
624  NtClose(fileHandle);
625  }
626  }
627  else
628  {
629  // Pretend we don't have a settings store so bad things
630  // don't happen.
631  PhDereferenceObject(PhSettingsFileName);
632  PhSettingsFileName = NULL;
633  }
634  }
635  }
636  }
637 
638  // Apply basic global settings.
639  PhMaxSizeUnit = PhGetIntegerSetting(L"MaxSizeUnit");
640 
641  if (PhGetIntegerSetting(L"SampleCountAutomatic"))
642  {
643  ULONG sampleCount;
644 
645  sampleCount = (GetSystemMetrics(SM_CXVIRTUALSCREEN) + 1) / 2;
646 
647  if (sampleCount > 2048)
648  sampleCount = 2048;
649 
650  PhSetIntegerSetting(L"SampleCount", sampleCount);
651  }
652 }
653 
654 #define PH_ARG_SETTINGS 1
655 #define PH_ARG_NOSETTINGS 2
656 #define PH_ARG_SHOWVISIBLE 3
657 #define PH_ARG_SHOWHIDDEN 4
658 #define PH_ARG_COMMANDMODE 5
659 #define PH_ARG_COMMANDTYPE 6
660 #define PH_ARG_COMMANDOBJECT 7
661 #define PH_ARG_COMMANDACTION 8
662 #define PH_ARG_COMMANDVALUE 9
663 #define PH_ARG_RUNASSERVICEMODE 10
664 #define PH_ARG_NOKPH 11
665 #define PH_ARG_INSTALLKPH 12
666 #define PH_ARG_UNINSTALLKPH 13
667 #define PH_ARG_DEBUG 14
668 #define PH_ARG_HWND 15
669 #define PH_ARG_POINT 16
670 #define PH_ARG_SHOWOPTIONS 17
671 #define PH_ARG_PHSVC 18
672 #define PH_ARG_NOPLUGINS 19
673 #define PH_ARG_NEWINSTANCE 20
674 #define PH_ARG_ELEVATE 21
675 #define PH_ARG_SILENT 22
676 #define PH_ARG_HELP 23
677 #define PH_ARG_SELECTPID 24
678 #define PH_ARG_PRIORITY 25
679 #define PH_ARG_PLUGIN 26
680 #define PH_ARG_SELECTTAB 27
681 
683  _In_opt_ PPH_COMMAND_LINE_OPTION Option,
684  _In_opt_ PPH_STRING Value,
685  _In_opt_ PVOID Context
686  )
687 {
688  ULONG64 integer;
689 
690  if (Option)
691  {
692  switch (Option->Id)
693  {
694  case PH_ARG_SETTINGS:
695  PhSwapReference(&PhStartupParameters.SettingsFileName, Value);
696  break;
697  case PH_ARG_NOSETTINGS:
698  PhStartupParameters.NoSettings = TRUE;
699  break;
700  case PH_ARG_SHOWVISIBLE:
701  PhStartupParameters.ShowVisible = TRUE;
702  break;
703  case PH_ARG_SHOWHIDDEN:
704  PhStartupParameters.ShowHidden = TRUE;
705  break;
706  case PH_ARG_COMMANDMODE:
707  PhStartupParameters.CommandMode = TRUE;
708  break;
709  case PH_ARG_COMMANDTYPE:
710  PhSwapReference(&PhStartupParameters.CommandType, Value);
711  break;
713  PhSwapReference(&PhStartupParameters.CommandObject, Value);
714  break;
716  PhSwapReference(&PhStartupParameters.CommandAction, Value);
717  break;
718  case PH_ARG_COMMANDVALUE:
719  PhSwapReference(&PhStartupParameters.CommandValue, Value);
720  break;
722  PhSwapReference(&PhStartupParameters.RunAsServiceMode, Value);
723  break;
724  case PH_ARG_NOKPH:
725  PhStartupParameters.NoKph = TRUE;
726  break;
727  case PH_ARG_INSTALLKPH:
728  PhStartupParameters.InstallKph = TRUE;
729  break;
730  case PH_ARG_UNINSTALLKPH:
731  PhStartupParameters.UninstallKph = TRUE;
732  break;
733  case PH_ARG_DEBUG:
734  PhStartupParameters.Debug = TRUE;
735  break;
736  case PH_ARG_HWND:
737  if (PhStringToInteger64(&Value->sr, 16, &integer))
738  PhStartupParameters.WindowHandle = (HWND)(ULONG_PTR)integer;
739  break;
740  case PH_ARG_POINT:
741  {
742  PH_STRINGREF xString;
743  PH_STRINGREF yString;
744 
745  if (PhSplitStringRefAtChar(&Value->sr, ',', &xString, &yString))
746  {
747  LONG64 x;
748  LONG64 y;
749 
750  if (PhStringToInteger64(&xString, 10, &x) && PhStringToInteger64(&yString, 10, &y))
751  {
752  PhStartupParameters.Point.x = (LONG)x;
753  PhStartupParameters.Point.y = (LONG)y;
754  }
755  }
756  }
757  break;
758  case PH_ARG_SHOWOPTIONS:
759  PhStartupParameters.ShowOptions = TRUE;
760  break;
761  case PH_ARG_PHSVC:
762  PhStartupParameters.PhSvc = TRUE;
763  break;
764  case PH_ARG_NOPLUGINS:
765  PhStartupParameters.NoPlugins = TRUE;
766  break;
767  case PH_ARG_NEWINSTANCE:
768  PhStartupParameters.NewInstance = TRUE;
769  break;
770  case PH_ARG_ELEVATE:
771  PhStartupParameters.Elevate = TRUE;
772  break;
773  case PH_ARG_SILENT:
774  PhStartupParameters.Silent = TRUE;
775  break;
776  case PH_ARG_HELP:
777  PhStartupParameters.Help = TRUE;
778  break;
779  case PH_ARG_SELECTPID:
780  if (PhStringToInteger64(&Value->sr, 0, &integer))
781  PhStartupParameters.SelectPid = (ULONG)integer;
782  break;
783  case PH_ARG_PRIORITY:
784  if (PhEqualString2(Value, L"r", TRUE))
785  PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_REALTIME;
786  else if (PhEqualString2(Value, L"h", TRUE))
787  PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_HIGH;
788  else if (PhEqualString2(Value, L"n", TRUE))
789  PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
790  else if (PhEqualString2(Value, L"l", TRUE))
791  PhStartupParameters.PriorityClass = PROCESS_PRIORITY_CLASS_IDLE;
792  break;
793  case PH_ARG_PLUGIN:
794  if (!PhStartupParameters.PluginParameters)
795  PhStartupParameters.PluginParameters = PhCreateList(3);
796  PhReferenceObject(Value);
797  PhAddItemList(PhStartupParameters.PluginParameters, Value);
798  break;
799  case PH_ARG_SELECTTAB:
800  PhSwapReference(&PhStartupParameters.SelectTab, Value);
801  break;
802  }
803  }
804  else
805  {
806  PPH_STRING upperValue;
807 
808  upperValue = PhDuplicateString(Value);
809  PhUpperString(upperValue);
810 
811  if (PhFindStringInString(upperValue, 0, L"TASKMGR.EXE") != -1)
812  {
813  // User probably has Process Hacker replacing Task Manager. Force
814  // the main window to start visible.
815  PhStartupParameters.ShowVisible = TRUE;
816  }
817 
818  PhDereferenceObject(upperValue);
819  }
820 
821  return TRUE;
822 }
823 
825  VOID
826  )
827 {
828  static PH_COMMAND_LINE_OPTION options[] =
829  {
830  { PH_ARG_SETTINGS, L"settings", MandatoryArgumentType },
831  { PH_ARG_NOSETTINGS, L"nosettings", NoArgumentType },
833  { PH_ARG_SHOWHIDDEN, L"hide", NoArgumentType },
840  { PH_ARG_NOKPH, L"nokph", NoArgumentType },
841  { PH_ARG_INSTALLKPH, L"installkph", NoArgumentType },
842  { PH_ARG_UNINSTALLKPH, L"uninstallkph", NoArgumentType },
843  { PH_ARG_DEBUG, L"debug", NoArgumentType },
844  { PH_ARG_HWND, L"hwnd", MandatoryArgumentType },
845  { PH_ARG_POINT, L"point", MandatoryArgumentType },
846  { PH_ARG_SHOWOPTIONS, L"showoptions", NoArgumentType },
847  { PH_ARG_PHSVC, L"phsvc", NoArgumentType },
848  { PH_ARG_NOPLUGINS, L"noplugins", NoArgumentType },
849  { PH_ARG_NEWINSTANCE, L"newinstance", NoArgumentType },
850  { PH_ARG_ELEVATE, L"elevate", NoArgumentType },
851  { PH_ARG_SILENT, L"s", NoArgumentType },
852  { PH_ARG_HELP, L"help", NoArgumentType },
853  { PH_ARG_SELECTPID, L"selectpid", MandatoryArgumentType },
854  { PH_ARG_PRIORITY, L"priority", MandatoryArgumentType },
855  { PH_ARG_PLUGIN, L"plugin", MandatoryArgumentType },
856  { PH_ARG_SELECTTAB, L"selecttab", MandatoryArgumentType }
857  };
858  PH_STRINGREF commandLine;
859 
860  PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine);
861 
862  memset(&PhStartupParameters, 0, sizeof(PH_STARTUP_PARAMETERS));
863 
864  if (!PhParseCommandLine(
865  &commandLine,
866  options,
867  sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION),
870  NULL
871  ) || PhStartupParameters.Help)
872  {
874  NULL,
875  L"Command line options:\n\n"
876  L"-c\n"
877  L"-ctype command-type\n"
878  L"-cobject command-object\n"
879  L"-caction command-action\n"
880  L"-cvalue command-value\n"
881  L"-debug\n"
882  L"-elevate\n"
883  L"-help\n"
884  L"-hide\n"
885  L"-installkph\n"
886  L"-newinstance\n"
887  L"-nokph\n"
888  L"-noplugins\n"
889  L"-nosettings\n"
890  L"-plugin pluginname:value\n"
891  L"-priority r|h|n|l\n"
892  L"-s\n"
893  L"-selectpid pid-to-select\n"
894  L"-selecttab name-of-tab-to-select\n"
895  L"-settings filename\n"
896  L"-uninstallkph\n"
897  L"-v\n"
898  );
899 
900  if (PhStartupParameters.Help)
901  RtlExitUserProcess(STATUS_SUCCESS);
902  }
903 
904  if (PhStartupParameters.InstallKph)
905  {
906  NTSTATUS status;
907  PPH_STRING kprocesshackerFileName;
908  KPH_PARAMETERS parameters;
909 
910  kprocesshackerFileName = PhConcatStrings2(PhApplicationDirectory->Buffer, L"\\kprocesshacker.sys");
911 
912  parameters.SecurityLevel = KphSecurityNone;
913  parameters.CreateDynamicConfiguration = TRUE;
914 
915  status = KphInstallEx(L"KProcessHacker2", kprocesshackerFileName->Buffer, &parameters);
916 
917  if (!NT_SUCCESS(status) && !PhStartupParameters.Silent)
918  PhShowStatus(NULL, L"Unable to install KProcessHacker", status, 0);
919 
920  RtlExitUserProcess(status);
921  }
922 
923  if (PhStartupParameters.UninstallKph)
924  {
925  NTSTATUS status;
926 
927  status = KphUninstall(L"KProcessHacker2");
928 
929  if (!NT_SUCCESS(status) && !PhStartupParameters.Silent)
930  PhShowStatus(NULL, L"Unable to uninstall KProcessHacker", status, 0);
931 
932  RtlExitUserProcess(status);
933  }
934 
935  if (PhStartupParameters.Elevate && !PhElevated)
936  {
938  NULL,
939  NULL,
940  SW_SHOW,
943  0,
944  NULL
945  );
946  RtlExitUserProcess(STATUS_SUCCESS);
947  }
948 
949  if (PhStartupParameters.Debug)
950  {
951  // The symbol provider won't work if this is chosen.
953  }
954 }
955 
957  VOID
958  )
959 {
960  HANDLE tokenHandle;
961 
963  &tokenHandle,
964  TOKEN_ADJUST_PRIVILEGES,
965  NtCurrentProcess()
966  )))
967  {
968  CHAR privilegesBuffer[FIELD_OFFSET(TOKEN_PRIVILEGES, Privileges) + sizeof(LUID_AND_ATTRIBUTES) * 8];
969  PTOKEN_PRIVILEGES privileges;
970  ULONG i;
971 
972  privileges = (PTOKEN_PRIVILEGES)privilegesBuffer;
973  privileges->PrivilegeCount = 8;
974 
975  for (i = 0; i < privileges->PrivilegeCount; i++)
976  {
977  privileges->Privileges[i].Attributes = SE_PRIVILEGE_ENABLED;
978  privileges->Privileges[i].Luid.HighPart = 0;
979  }
980 
981  privileges->Privileges[0].Luid.LowPart = SE_DEBUG_PRIVILEGE;
982  privileges->Privileges[1].Luid.LowPart = SE_INC_BASE_PRIORITY_PRIVILEGE;
983  privileges->Privileges[2].Luid.LowPart = SE_INC_WORKING_SET_PRIVILEGE;
984  privileges->Privileges[3].Luid.LowPart = SE_LOAD_DRIVER_PRIVILEGE;
985  privileges->Privileges[4].Luid.LowPart = SE_PROF_SINGLE_PROCESS_PRIVILEGE;
986  privileges->Privileges[5].Luid.LowPart = SE_RESTORE_PRIVILEGE;
987  privileges->Privileges[6].Luid.LowPart = SE_SHUTDOWN_PRIVILEGE;
988  privileges->Privileges[7].Luid.LowPart = SE_TAKE_OWNERSHIP_PRIVILEGE;
989 
991  tokenHandle,
992  FALSE,
993  privileges,
994  0,
995  NULL,
996  NULL
997  );
998 
999  NtClose(tokenHandle);
1000  }
1001 }