Process Hacker
process.c
Go to the documentation of this file.
1 /*
2  * KProcessHacker
3  *
4  * Copyright (C) 2010-2013 wj32
5  *
6  * This file is part of Process Hacker.
7  *
8  * Process Hacker is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * Process Hacker is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <kph.h>
23 #include <dyndata.h>
24 
25 #ifdef ALLOC_PRAGMA
26 #pragma alloc_text(PAGE, KpiOpenProcess)
27 #pragma alloc_text(PAGE, KpiOpenProcessToken)
28 #pragma alloc_text(PAGE, KpiOpenProcessJob)
29 #pragma alloc_text(PAGE, KpiSuspendProcess)
30 #pragma alloc_text(PAGE, KpiResumeProcess)
31 #pragma alloc_text(PAGE, KphTerminateProcessInternal)
32 #pragma alloc_text(PAGE, KpiTerminateProcess)
33 #pragma alloc_text(PAGE, KpiQueryInformationProcess)
34 #pragma alloc_text(PAGE, KpiSetInformationProcess)
35 #endif
36 
47 NTSTATUS KpiOpenProcess(
48  __out PHANDLE ProcessHandle,
49  __in ACCESS_MASK DesiredAccess,
50  __in PCLIENT_ID ClientId,
51  __in KPROCESSOR_MODE AccessMode
52  )
53 {
54  NTSTATUS status;
55  CLIENT_ID clientId;
56  PEPROCESS process;
57  PETHREAD thread;
58  HANDLE processHandle;
59 
60  PAGED_CODE();
61 
62  if (AccessMode != KernelMode)
63  {
64  __try
65  {
66  ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE));
67  ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
68  clientId = *ClientId;
69  }
70  __except (EXCEPTION_EXECUTE_HANDLER)
71  {
72  return GetExceptionCode();
73  }
74  }
75  else
76  {
77  clientId = *ClientId;
78  }
79 
80  // Use the thread ID if it was specified.
81  if (clientId.UniqueThread)
82  {
83  status = PsLookupProcessThreadByCid(&clientId, &process, &thread);
84 
85  if (NT_SUCCESS(status))
86  {
87  // We don't actually need the thread.
88  ObDereferenceObject(thread);
89  }
90  }
91  else
92  {
93  status = PsLookupProcessByProcessId(clientId.UniqueProcess, &process);
94  }
95 
96  if (!NT_SUCCESS(status))
97  return status;
98 
99  // Always open in KernelMode to skip access checks.
100  status = ObOpenObjectByPointer(
101  process,
102  0,
103  NULL,
104  DesiredAccess,
105  *PsProcessType,
106  KernelMode,
107  &processHandle
108  );
109  ObDereferenceObject(process);
110 
111  if (NT_SUCCESS(status))
112  {
113  if (AccessMode != KernelMode)
114  {
115  __try
116  {
117  *ProcessHandle = processHandle;
118  }
119  __except (EXCEPTION_EXECUTE_HANDLER)
120  {
121  status = GetExceptionCode();
122  }
123  }
124  else
125  {
126  *ProcessHandle = processHandle;
127  }
128  }
129 
130  return status;
131 }
132 
142  __in HANDLE ProcessHandle,
143  __in ACCESS_MASK DesiredAccess,
144  __out PHANDLE TokenHandle,
145  __in KPROCESSOR_MODE AccessMode
146  )
147 {
148  NTSTATUS status;
149  PEPROCESS process;
150  PACCESS_TOKEN primaryToken;
151  HANDLE tokenHandle;
152 
153  PAGED_CODE();
154 
155  if (AccessMode != KernelMode)
156  {
157  __try
158  {
159  ProbeForWrite(TokenHandle, sizeof(HANDLE), sizeof(HANDLE));
160  }
161  __except (EXCEPTION_EXECUTE_HANDLER)
162  {
163  return GetExceptionCode();
164  }
165  }
166 
167  status = ObReferenceObjectByHandle(
168  ProcessHandle,
169  0,
170  *PsProcessType,
171  AccessMode,
172  &process,
173  NULL
174  );
175 
176  if (!NT_SUCCESS(status))
177  return status;
178 
179  primaryToken = PsReferencePrimaryToken(process);
180 
181  status = ObOpenObjectByPointer(
182  primaryToken,
183  0,
184  NULL,
185  DesiredAccess,
186  *SeTokenObjectType,
187  KernelMode,
188  &tokenHandle
189  );
190 
191  PsDereferencePrimaryToken(primaryToken);
192  ObDereferenceObject(process);
193 
194  if (NT_SUCCESS(status))
195  {
196  if (AccessMode != KernelMode)
197  {
198  __try
199  {
200  *TokenHandle = tokenHandle;
201  }
202  __except (EXCEPTION_EXECUTE_HANDLER)
203  {
204  status = GetExceptionCode();
205  }
206  }
207  else
208  {
209  *TokenHandle = tokenHandle;
210  }
211  }
212 
213  return status;
214 }
215 
225  __in HANDLE ProcessHandle,
226  __in ACCESS_MASK DesiredAccess,
227  __out PHANDLE JobHandle,
228  __in KPROCESSOR_MODE AccessMode
229  )
230 {
231  NTSTATUS status;
232  PEPROCESS process;
233  PEJOB job;
234  HANDLE jobHandle = NULL;
235 
236  PAGED_CODE();
237 
238  if (AccessMode != KernelMode)
239  {
240  __try
241  {
242  ProbeForWrite(JobHandle, sizeof(HANDLE), sizeof(HANDLE));
243  }
244  __except (EXCEPTION_EXECUTE_HANDLER)
245  {
246  return GetExceptionCode();
247  }
248  }
249 
250  status = ObReferenceObjectByHandle(
251  ProcessHandle,
252  0,
253  *PsProcessType,
254  AccessMode,
255  &process,
256  NULL
257  );
258 
259  if (!NT_SUCCESS(status))
260  return status;
261 
262  job = PsGetProcessJob(process);
263 
264  if (job)
265  {
266  status = ObOpenObjectByPointer(
267  job,
268  0,
269  NULL,
270  DesiredAccess,
271  *PsJobType,
272  KernelMode,
273  &jobHandle
274  );
275  }
276  else
277  {
278  status = STATUS_NOT_FOUND;
279  }
280 
281  ObDereferenceObject(process);
282 
283  if (NT_SUCCESS(status))
284  {
285  if (AccessMode != KernelMode)
286  {
287  __try
288  {
289  *JobHandle = jobHandle;
290  }
291  __except (EXCEPTION_EXECUTE_HANDLER)
292  {
293  status = GetExceptionCode();
294  }
295  }
296  else
297  {
298  *JobHandle = jobHandle;
299  }
300  }
301 
302  return status;
303 }
304 
312  __in HANDLE ProcessHandle,
313  __in KPROCESSOR_MODE AccessMode
314  )
315 {
316  NTSTATUS status;
317  PEPROCESS process;
318 
319  PAGED_CODE();
320 
321  if (!PsSuspendProcess_I)
322  return STATUS_NOT_SUPPORTED;
323 
324  status = ObReferenceObjectByHandle(
325  ProcessHandle,
326  0,
327  *PsProcessType,
328  AccessMode,
329  &process,
330  NULL
331  );
332 
333  if (!NT_SUCCESS(status))
334  return status;
335 
336  status = PsSuspendProcess_I(process);
337  ObDereferenceObject(process);
338 
339  return status;
340 }
341 
349  __in HANDLE ProcessHandle,
350  __in KPROCESSOR_MODE AccessMode
351  )
352 {
353  NTSTATUS status;
354  PEPROCESS process;
355 
356  PAGED_CODE();
357 
358  if (!PsResumeProcess_I)
359  return STATUS_NOT_SUPPORTED;
360 
361  status = ObReferenceObjectByHandle(
362  ProcessHandle,
363  0,
364  *PsProcessType,
365  AccessMode,
366  &process,
367  NULL
368  );
369 
370  if (!NT_SUCCESS(status))
371  return status;
372 
373  status = PsResumeProcess_I(process);
374  ObDereferenceObject(process);
375 
376  return status;
377 }
378 
387  __in PEPROCESS Process,
388  __in NTSTATUS ExitStatus
389  )
390 {
391  NTSTATUS status;
392  _PsTerminateProcess PsTerminateProcess_I;
393 
394  PAGED_CODE();
395 
397  return STATUS_NOT_SUPPORTED;
398 
400 
401  if (!PsTerminateProcess_I)
402  {
403  dprintf("Unable to find PsTerminateProcess\n");
404  return STATUS_NOT_SUPPORTED;
405  }
406 
407 #ifdef _X86_
408 
409  if (
413  )
414  {
415  dprintf("Calling XP/03/8-style PsTerminateProcess\n");
416 
417  // PspTerminateProcess on XP and Server 2003 is normal.
418  // PsTerminateProcess on 8 is also normal.
419  status = PsTerminateProcess_I(Process, ExitStatus);
420  }
421  else if (
424  )
425  {
426  dprintf("Calling Vista/7-style PsTerminateProcess\n");
427 
428  // PsTerminateProcess on Vista and 7 has its first argument
429  // in ecx.
430  __asm
431  {
432  push [ExitStatus]
433  mov ecx, [Process]
434  call [PsTerminateProcess_I]
435  mov [status], eax
436  }
437  }
438  else if (KphDynNtVersion == PHNT_WINBLUE)
439  {
440  dprintf("Calling 8.1-style PsTerminateProcess\n");
441 
442  // PsTerminateProcess on 8.1 is fastcall.
443  status = ((_PsTerminateProcess63)PsTerminateProcess_I)(Process, ExitStatus);
444  }
445  else
446  {
447  return STATUS_NOT_SUPPORTED;
448  }
449 
450 #else
451 
452  status = PsTerminateProcess_I(Process, ExitStatus);
453 
454 #endif
455 
456  return status;
457 }
458 
468  __in HANDLE ProcessHandle,
469  __in NTSTATUS ExitStatus,
470  __in KPROCESSOR_MODE AccessMode
471  )
472 {
473  NTSTATUS status;
474  PEPROCESS process;
475 
476  PAGED_CODE();
477 
478  status = ObReferenceObjectByHandle(
479  ProcessHandle,
480  0,
481  *PsProcessType,
482  AccessMode,
483  &process,
484  NULL
485  );
486 
487  if (!NT_SUCCESS(status))
488  return status;
489 
490  if (process != PsGetCurrentProcess())
491  {
492  dprintf("Calling KphTerminateProcessInternal from KpiTerminateProcess\n");
493  status = KphTerminateProcessInternal(process, ExitStatus);
494 
495  if (status == STATUS_NOT_SUPPORTED)
496  {
497  HANDLE newProcessHandle;
498 
499  // Re-open the process to get a kernel handle.
500  if (NT_SUCCESS(status = ObOpenObjectByPointer(
501  process,
503  NULL,
505  *PsProcessType,
506  KernelMode,
507  &newProcessHandle
508  )))
509  {
510  status = ZwTerminateProcess(newProcessHandle, ExitStatus);
511  ZwClose(newProcessHandle);
512  }
513  }
514  }
515  else
516  {
517  status = STATUS_CANT_TERMINATE_SELF;
518  }
519 
520  ObDereferenceObject(process);
521 
522  return status;
523 }
524 
538  __in HANDLE ProcessHandle,
539  __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
540  __out_bcount(ProcessInformationLength) PVOID ProcessInformation,
541  __in ULONG ProcessInformationLength,
542  __out_opt PULONG ReturnLength,
543  __in KPROCESSOR_MODE AccessMode
544  )
545 {
546  NTSTATUS status;
547  PEPROCESS process;
548  ULONG returnLength;
549 
550  PAGED_CODE();
551 
552  if (AccessMode != KernelMode)
553  {
554  ULONG alignment;
555 
556  switch (ProcessInformationClass)
557  {
559  alignment = sizeof(KPH_PROCESS_PROTECTION_INFORMATION);
560  break;
561  default:
562  alignment = sizeof(ULONG);
563  break;
564  }
565 
566  __try
567  {
568  ProbeForWrite(ProcessInformation, ProcessInformationLength, alignment);
569 
570  if (ReturnLength)
571  ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
572  }
573  __except (EXCEPTION_EXECUTE_HANDLER)
574  {
575  return GetExceptionCode();
576  }
577  }
578 
579  status = ObReferenceObjectByHandle(
580  ProcessHandle,
581  0,
582  *PsProcessType,
583  AccessMode,
584  &process,
585  NULL
586  );
587 
588  if (!NT_SUCCESS(status))
589  return status;
590 
591  switch (ProcessInformationClass)
592  {
594  {
595  BOOLEAN protectedProcess = FALSE;
596 
598  protectedProcess = PsIsProtectedProcess_I(process);
599  else
600  status = STATUS_NOT_SUPPORTED;
601 
602  if (NT_SUCCESS(status))
603  {
604  if (ProcessInformationLength == sizeof(KPH_PROCESS_PROTECTION_INFORMATION))
605  {
606  __try
607  {
608  ((PKPH_PROCESS_PROTECTION_INFORMATION)ProcessInformation)->IsProtectedProcess = protectedProcess;
609  }
610  __except (EXCEPTION_EXECUTE_HANDLER)
611  {
612  status = GetExceptionCode();
613  }
614  }
615  else
616  {
617  status = STATUS_INFO_LENGTH_MISMATCH;
618  }
619  }
620 
621  returnLength = sizeof(KPH_PROCESS_PROTECTION_INFORMATION);
622  }
623  break;
625  {
626  KAPC_STATE apcState;
627  ULONG executeFlags;
628 
629  KeStackAttachProcess(process, &apcState);
630  status = ZwQueryInformationProcess(
631  NtCurrentProcess(),
632  ProcessExecuteFlags,
633  &executeFlags,
634  sizeof(ULONG),
635  NULL
636  );
637  KeUnstackDetachProcess(&apcState);
638 
639  if (NT_SUCCESS(status))
640  {
641  if (ProcessInformationLength == sizeof(ULONG))
642  {
643  __try
644  {
645  *(PULONG)ProcessInformation = executeFlags;
646  }
647  __except (EXCEPTION_EXECUTE_HANDLER)
648  {
649  status = GetExceptionCode();
650  }
651  }
652  else
653  {
654  status = STATUS_INFO_LENGTH_MISMATCH;
655  }
656  }
657 
658  returnLength = sizeof(ULONG);
659  }
660  break;
662  {
663  HANDLE newProcessHandle;
664  ULONG ioPriority;
665 
666  if (NT_SUCCESS(status = ObOpenObjectByPointer(
667  process,
669  NULL,
671  *PsProcessType,
672  KernelMode,
673  &newProcessHandle
674  )))
675  {
677  newProcessHandle,
678  ProcessIoPriority,
679  &ioPriority,
680  sizeof(ULONG),
681  NULL
682  )))
683  {
684  if (ProcessInformationLength == sizeof(ULONG))
685  {
686  __try
687  {
688  *(PULONG)ProcessInformation = ioPriority;
689  }
690  __except (EXCEPTION_EXECUTE_HANDLER)
691  {
692  status = GetExceptionCode();
693  }
694  }
695  else
696  {
697  status = STATUS_INFO_LENGTH_MISMATCH;
698  }
699  }
700 
701  ZwClose(newProcessHandle);
702  }
703 
704  returnLength = sizeof(ULONG);
705  }
706  break;
707  default:
708  status = STATUS_INVALID_INFO_CLASS;
709  returnLength = 0;
710  break;
711  }
712 
713  ObDereferenceObject(process);
714 
715  if (ReturnLength)
716  {
717  if (AccessMode != KernelMode)
718  {
719  __try
720  {
721  *ReturnLength = returnLength;
722  }
723  __except (EXCEPTION_EXECUTE_HANDLER)
724  {
725  NOTHING;
726  }
727  }
728  else
729  {
730  *ReturnLength = returnLength;
731  }
732  }
733 
734  return status;
735 }
736 
748  __in HANDLE ProcessHandle,
749  __in KPH_PROCESS_INFORMATION_CLASS ProcessInformationClass,
750  __in_bcount(ProcessInformationLength) PVOID ProcessInformation,
751  __in ULONG ProcessInformationLength,
752  __in KPROCESSOR_MODE AccessMode
753  )
754 {
755  NTSTATUS status;
756  PEPROCESS process;
757 
758  PAGED_CODE();
759 
760  if (AccessMode != KernelMode)
761  {
762  ULONG alignment;
763 
764  switch (ProcessInformationClass)
765  {
766  default:
767  alignment = sizeof(ULONG);
768  break;
769  }
770 
771  __try
772  {
773  ProbeForRead(ProcessInformation, ProcessInformationLength, alignment);
774  }
775  __except (EXCEPTION_EXECUTE_HANDLER)
776  {
777  return GetExceptionCode();
778  }
779  }
780 
781  status = ObReferenceObjectByHandle(
782  ProcessHandle,
783  0,
784  *PsProcessType,
785  AccessMode,
786  &process,
787  NULL
788  );
789 
790  if (!NT_SUCCESS(status))
791  return status;
792 
793  switch (ProcessInformationClass)
794  {
796  {
797  ULONG executeFlags;
798  KAPC_STATE apcState;
799 
800  if (ProcessInformationLength == sizeof(ULONG))
801  {
802  __try
803  {
804  executeFlags = *(PULONG)ProcessInformation;
805  }
806  __except (EXCEPTION_EXECUTE_HANDLER)
807  {
808  status = GetExceptionCode();
809  }
810  }
811  else
812  {
813  status = STATUS_INFO_LENGTH_MISMATCH;
814  }
815 
816  if (NT_SUCCESS(status))
817  {
818  // Make sure the process isn't terminating, otherwise the call
819  // may hang due to a recursive acquire of the working set mutex.
821  {
822  // We can only set execute options on the current process.
823  // So, we simply attach to the target process.
824  KeStackAttachProcess(process, &apcState);
825  status = ZwSetInformationProcess(
826  NtCurrentProcess(),
827  ProcessExecuteFlags,
828  &executeFlags,
829  sizeof(ULONG)
830  );
831  KeUnstackDetachProcess(&apcState);
832 
834  }
835  else
836  {
837  status = STATUS_PROCESS_IS_TERMINATING;
838  }
839  }
840  }
841  break;
843  {
844  ULONG ioPriority;
845  HANDLE newProcessHandle;
846 
847  if (ProcessInformationLength == sizeof(ULONG))
848  {
849  __try
850  {
851  ioPriority = *(PULONG)ProcessInformation;
852  }
853  __except (EXCEPTION_EXECUTE_HANDLER)
854  {
855  status = GetExceptionCode();
856  }
857  }
858  else
859  {
860  status = STATUS_INFO_LENGTH_MISMATCH;
861  }
862 
863  if (NT_SUCCESS(status))
864  {
865  if (NT_SUCCESS(status = ObOpenObjectByPointer(
866  process,
868  NULL,
870  *PsProcessType,
871  KernelMode,
872  &newProcessHandle
873  )))
874  {
875  status = ZwSetInformationProcess(
876  newProcessHandle,
877  ProcessIoPriority,
878  &ioPriority,
879  sizeof(ULONG)
880  );
881  ZwClose(newProcessHandle);
882  }
883  }
884  }
885  break;
886  default:
887  status = STATUS_INVALID_INFO_CLASS;
888  break;
889  }
890 
891  ObDereferenceObject(process);
892 
893  return status;
894 }
895 
905  __in PEPROCESS Process
906  )
907 {
908  // Use the exported function if it is available.
909  // Note that we make sure the corresponding release function is also available.
911  {
913  }
914 
915  // Fail if we don't have an offset.
916  if (KphDynEpRundownProtect == -1)
917  return FALSE;
918 
919  return ExAcquireRundownProtection((PEX_RUNDOWN_REF)((ULONG_PTR)Process + KphDynEpRundownProtect));
920 }
921 
928  __in PEPROCESS Process
929  )
930 {
932  {
934  return;
935  }
936 
937  if (KphDynEpRundownProtect == -1)
938  return;
939 
940  ExReleaseRundownProtection((PEX_RUNDOWN_REF)((ULONG_PTR)Process + KphDynEpRundownProtect));
941 }