Process Hacker
thread.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 typedef struct _EXIT_THREAD_CONTEXT
26 {
27  KAPC Apc;
28  KEVENT CompletedEvent;
29  NTSTATUS ExitStatus;
31 
32 typedef struct _CAPTURE_BACKTRACE_THREAD_CONTEXT
33 {
34  BOOLEAN Local;
35  KAPC Apc;
36  KEVENT CompletedEvent;
37  ULONG FramesToSkip;
38  ULONG FramesToCapture;
39  PVOID *BackTrace;
40  ULONG CapturedFrames;
41  ULONG BackTraceHash;
43 
46 
48  __in PRKAPC Apc,
49  __inout PKNORMAL_ROUTINE *NormalRoutine,
50  __inout PVOID *NormalContext,
51  __inout PVOID *SystemArgument1,
52  __inout PVOID *SystemArgument2
53  );
54 
56  __in PRKAPC Apc,
57  __inout PKNORMAL_ROUTINE *NormalRoutine,
58  __inout PVOID *NormalContext,
59  __inout PVOID *SystemArgument1,
60  __inout PVOID *SystemArgument2
61  );
62 
63 #ifdef ALLOC_PRAGMA
64 #pragma alloc_text(PAGE, KpiOpenThread)
65 #pragma alloc_text(PAGE, KpiOpenThreadProcess)
66 #pragma alloc_text(PAGE, KphTerminateThreadByPointerInternal)
67 #pragma alloc_text(PAGE, KpiTerminateThread)
68 #pragma alloc_text(PAGE, KpiTerminateThreadUnsafe)
69 #pragma alloc_text(PAGE, KphpExitThreadSpecialApc)
70 #pragma alloc_text(PAGE, KpiGetContextThread)
71 #pragma alloc_text(PAGE, KpiSetContextThread)
72 #pragma alloc_text(PAGE, KphCaptureStackBackTraceThread)
73 #pragma alloc_text(PAGE, KphpCaptureStackBackTraceThreadSpecialApc)
74 #pragma alloc_text(PAGE, KpiCaptureStackBackTraceThread)
75 #pragma alloc_text(PAGE, KpiQueryInformationThread)
76 #pragma alloc_text(PAGE, KpiSetInformationThread)
77 #endif
78 
89 NTSTATUS KpiOpenThread(
90  __out PHANDLE ThreadHandle,
91  __in ACCESS_MASK DesiredAccess,
92  __in PCLIENT_ID ClientId,
93  __in KPROCESSOR_MODE AccessMode
94  )
95 {
96  NTSTATUS status;
97  CLIENT_ID clientId;
98  PETHREAD thread;
99  HANDLE threadHandle;
100 
101  PAGED_CODE();
102 
103  if (AccessMode != KernelMode)
104  {
105  __try
106  {
107  ProbeForWrite(ThreadHandle, sizeof(HANDLE), sizeof(HANDLE));
108  ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
109  clientId = *ClientId;
110  }
111  __except (EXCEPTION_EXECUTE_HANDLER)
112  {
113  return GetExceptionCode();
114  }
115  }
116  else
117  {
118  clientId = *ClientId;
119  }
120 
121  // Use the process ID if it was specified.
122  if (clientId.UniqueProcess)
123  {
124  status = PsLookupProcessThreadByCid(&clientId, NULL, &thread);
125  }
126  else
127  {
128  status = PsLookupThreadByThreadId(clientId.UniqueThread, &thread);
129  }
130 
131  if (!NT_SUCCESS(status))
132  return status;
133 
134  // Always open in KernelMode to skip access checks.
135  status = ObOpenObjectByPointer(
136  thread,
137  0,
138  NULL,
139  DesiredAccess,
140  *PsThreadType,
141  KernelMode,
142  &threadHandle
143  );
144  ObDereferenceObject(thread);
145 
146  if (NT_SUCCESS(status))
147  {
148  if (AccessMode != KernelMode)
149  {
150  __try
151  {
152  *ThreadHandle = threadHandle;
153  }
154  __except (EXCEPTION_EXECUTE_HANDLER)
155  {
156  status = GetExceptionCode();
157  }
158  }
159  else
160  {
161  *ThreadHandle = threadHandle;
162  }
163  }
164 
165  return status;
166 }
167 
177  __in HANDLE ThreadHandle,
178  __in ACCESS_MASK DesiredAccess,
179  __out PHANDLE ProcessHandle,
180  __in KPROCESSOR_MODE AccessMode
181  )
182 {
183  NTSTATUS status;
184  PETHREAD thread;
185  PEPROCESS process;
186  HANDLE processHandle;
187 
188  PAGED_CODE();
189 
190  if (AccessMode != KernelMode)
191  {
192  __try
193  {
194  ProbeForWrite(ProcessHandle, sizeof(HANDLE), sizeof(HANDLE));
195  }
196  __except (EXCEPTION_EXECUTE_HANDLER)
197  {
198  return GetExceptionCode();
199  }
200  }
201 
202  status = ObReferenceObjectByHandle(
203  ThreadHandle,
204  0,
205  *PsThreadType,
206  AccessMode,
207  &thread,
208  NULL
209  );
210 
211  if (!NT_SUCCESS(status))
212  return status;
213 
214  process = IoThreadToProcess(thread);
215 
216  status = ObOpenObjectByPointer(
217  process,
218  0,
219  NULL,
220  DesiredAccess,
221  *PsProcessType,
222  KernelMode,
223  &processHandle
224  );
225 
226  ObDereferenceObject(thread);
227 
228  if (NT_SUCCESS(status))
229  {
230  if (AccessMode != KernelMode)
231  {
232  __try
233  {
234  *ProcessHandle = processHandle;
235  }
236  __except (EXCEPTION_EXECUTE_HANDLER)
237  {
238  status = GetExceptionCode();
239  }
240  }
241  else
242  {
243  *ProcessHandle = processHandle;
244  }
245  }
246 
247  return status;
248 }
249 
258  __in PETHREAD Thread,
259  __in NTSTATUS ExitStatus
260  )
261 {
262  PVOID PspTerminateThreadByPointer_I;
263 
264  PAGED_CODE();
265 
267  return STATUS_NOT_SUPPORTED;
268 
269  PspTerminateThreadByPointer_I = KphGetDynamicProcedureScan(&KphDynPspTerminateThreadByPointerScan);
270 
271  if (!PspTerminateThreadByPointer_I)
272  {
273  dprintf("Unable to find PspTerminateThreadByPointer\n");
274  return STATUS_NOT_SUPPORTED;
275  }
276 
278  {
279  dprintf("Calling XP-style PspTerminateThreadByPointer\n");
280  return ((_PspTerminateThreadByPointer51)PspTerminateThreadByPointer_I)(
281  Thread,
282  ExitStatus
283  );
284  }
285  else if (
289  )
290  {
291  dprintf("Calling 03/Vista/7-style PspTerminateThreadByPointer\n");
292  return ((_PspTerminateThreadByPointer52)PspTerminateThreadByPointer_I)(
293  Thread,
294  ExitStatus,
295  Thread == PsGetCurrentThread()
296  );
297  }
298  else if (KphDynNtVersion == PHNT_WIN8)
299  {
300  NTSTATUS status;
301  ULONG directTerminate;
302 
303  dprintf("Calling 8-style PspTerminateThreadByPointer\n");
304  directTerminate = Thread == PsGetCurrentThread();
305 
306 #ifdef _X86_
307 
308  // PspTerminateThreadByPointer on 8 has its first argument
309  // in edi.
310  __asm
311  {
312  push [directTerminate]
313  push [ExitStatus]
314  mov edi, [Thread]
315  call [PspTerminateThreadByPointer_I]
316  mov [status], eax
317  }
318 
319 #else
320 
321  status = ((_PspTerminateThreadByPointer52)PspTerminateThreadByPointer_I)(
322  Thread,
323  ExitStatus,
324  Thread == PsGetCurrentThread()
325  );
326 
327 #endif
328 
329  return status;
330  }
331  else if (KphDynNtVersion == PHNT_WINBLUE)
332  {
333  dprintf("Calling 8.1-style PspTerminateThreadByPointer\n");
334  return ((_PspTerminateThreadByPointer63)PspTerminateThreadByPointer_I)(
335  Thread,
336  ExitStatus,
337  Thread == PsGetCurrentThread()
338  );
339  }
340  else
341  {
342  return STATUS_NOT_SUPPORTED;
343  }
344 }
345 
355  __in HANDLE ThreadHandle,
356  __in NTSTATUS ExitStatus,
357  __in KPROCESSOR_MODE AccessMode
358  )
359 {
360  NTSTATUS status;
361  PETHREAD thread;
362 
363  PAGED_CODE();
364 
365  status = ObReferenceObjectByHandle(
366  ThreadHandle,
367  0,
368  *PsThreadType,
369  AccessMode,
370  &thread,
371  NULL
372  );
373 
374  if (!NT_SUCCESS(status))
375  return status;
376 
377  if (thread != PsGetCurrentThread())
378  {
379  status = KphTerminateThreadByPointerInternal(thread, ExitStatus);
380  }
381  else
382  {
383  status = STATUS_CANT_TERMINATE_SELF;
384  }
385 
386  ObDereferenceObject(thread);
387 
388  return status;
389 }
390 
404  __in HANDLE ThreadHandle,
405  __in NTSTATUS ExitStatus,
406  __in KPROCESSOR_MODE AccessMode
407  )
408 {
409  NTSTATUS status;
410  PETHREAD thread;
411 
412  PAGED_CODE();
413 
414  status = ObReferenceObjectByHandle(
415  ThreadHandle,
416  0,
417  *PsThreadType,
418  AccessMode,
419  &thread,
420  NULL
421  );
422 
423  if (!NT_SUCCESS(status))
424  return status;
425 
426  if (thread != PsGetCurrentThread())
427  {
428  EXIT_THREAD_CONTEXT context;
429 
430  // Initialize the context structure.
431  context.ExitStatus = ExitStatus;
432  KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE);
433 
435  &context.Apc,
436  (PKTHREAD)thread,
439  NULL,
440  NULL,
441  KernelMode,
442  NULL
443  );
444 
445  // Queue the APC.
446  if (KeInsertQueueApc(&context.Apc, &context, NULL, 2))
447  {
448  // Wait for the APC procedure to finish retrieving information.
449  status = KeWaitForSingleObject(
450  &context.CompletedEvent,
451  Executive,
452  KernelMode,
453  FALSE,
454  NULL
455  );
456  }
457  else
458  {
459  status = STATUS_UNSUCCESSFUL;
460  }
461  }
462  else
463  {
464  status = STATUS_CANT_TERMINATE_SELF;
465  }
466 
467  ObDereferenceObject(thread);
468 
469  return status;
470 }
471 
473  __in PRKAPC Apc,
474  __inout PKNORMAL_ROUTINE *NormalRoutine,
475  __inout PVOID *NormalContext,
476  __inout PVOID *SystemArgument1,
477  __inout PVOID *SystemArgument2
478  )
479 {
480  PEXIT_THREAD_CONTEXT context = *SystemArgument1;
481  NTSTATUS exitStatus;
482 
483  PAGED_CODE();
484 
485  exitStatus = context->ExitStatus;
486  // That's the best we can do. Once we exit the current thread we can't
487  // signal the event, so just signal it now.
488  KeSetEvent(&context->CompletedEvent, 0, FALSE);
489  // Exit the thread.
490  KphTerminateThreadByPointerInternal(PsGetCurrentThread(), exitStatus);
491 }
492 
502  __in HANDLE ThreadHandle,
503  __inout PCONTEXT ThreadContext,
504  __in KPROCESSOR_MODE AccessMode
505  )
506 {
507  NTSTATUS status;
508  PETHREAD thread;
509 
510  PAGED_CODE();
511 
512  status = ObReferenceObjectByHandle(
513  ThreadHandle,
514  0,
515  *PsThreadType,
516  AccessMode,
517  &thread,
518  NULL
519  );
520 
521  if (!NT_SUCCESS(status))
522  return status;
523 
524  status = PsGetContextThread(thread, ThreadContext, AccessMode);
525  ObDereferenceObject(thread);
526 
527  return status;
528 }
529 
538  __in HANDLE ThreadHandle,
539  __in PCONTEXT ThreadContext,
540  __in KPROCESSOR_MODE AccessMode
541  )
542 {
543  NTSTATUS status;
544  PETHREAD thread;
545 
546  PAGED_CODE();
547 
548  status = ObReferenceObjectByHandle(
549  ThreadHandle,
550  0,
551  *PsThreadType,
552  AccessMode,
553  &thread,
554  NULL
555  );
556 
557  if (!NT_SUCCESS(status))
558  return status;
559 
560  status = PsSetContextThread(thread, ThreadContext, AccessMode);
561  ObDereferenceObject(thread);
562 
563  return status;
564 }
565 
583  __in ULONG FramesToSkip,
584  __in ULONG FramesToCapture,
585  __in_opt ULONG Flags,
586  __out_ecount(FramesToCapture) PVOID *BackTrace,
587  __out_opt PULONG BackTraceHash
588  )
589 {
590  PVOID backTrace[MAX_STACK_DEPTH];
591  ULONG framesFound;
592  ULONG hash;
593  ULONG i;
594 
595  // Skip the current frame (for this function).
596  FramesToSkip++;
597 
598  // Ensure that we won't overrun the buffer.
599  if (FramesToCapture + FramesToSkip > MAX_STACK_DEPTH)
600  return 0;
601  // Validate the flags.
602  if ((Flags & RTL_WALK_VALID_FLAGS) != Flags)
603  return 0;
604 
605  // Walk the stack.
606  framesFound = RtlWalkFrameChain(
607  backTrace,
608  FramesToCapture + FramesToSkip,
609  Flags
610  );
611  // Return nothing if we found fewer frames than we wanted to skip.
612  if (framesFound <= FramesToSkip)
613  return 0;
614 
615  // Copy over the stack trace.
616  // At the same time we calculate the stack trace hash by
617  // summing the addresses.
618  for (i = 0, hash = 0; i < FramesToCapture; i++)
619  {
620  if (FramesToSkip + i >= framesFound)
621  break;
622 
623  BackTrace[i] = backTrace[FramesToSkip + i];
624  hash += PtrToUlong(BackTrace[i]);
625  }
626 
627  if (BackTraceHash)
628  *BackTraceHash = hash;
629 
630  return i;
631 }
632 
651  __in PETHREAD Thread,
652  __in ULONG FramesToSkip,
653  __in ULONG FramesToCapture,
654  __out_ecount(FramesToCapture) PVOID *BackTrace,
655  __out_opt PULONG CapturedFrames,
656  __out_opt PULONG BackTraceHash,
657  __in KPROCESSOR_MODE AccessMode
658  )
659 {
660  NTSTATUS status = STATUS_SUCCESS;
662  ULONG backTraceSize;
663  PVOID *backTrace;
664 
665  PAGED_CODE();
666 
667  // Make sure the caller didn't request too many frames.
668  // This also restricts the amount of memory we will try to
669  // allocate later.
670  if (FramesToCapture > MAX_STACK_DEPTH)
671  return STATUS_INVALID_PARAMETER_3;
672 
673  backTraceSize = FramesToCapture * sizeof(PVOID);
674 
675  if (AccessMode != KernelMode)
676  {
677  __try
678  {
679  ProbeForWrite(BackTrace, backTraceSize, sizeof(PVOID));
680 
681  if (CapturedFrames)
682  ProbeForWrite(CapturedFrames, sizeof(ULONG), sizeof(ULONG));
683  if (BackTraceHash)
684  ProbeForWrite(BackTraceHash, sizeof(ULONG), sizeof(ULONG));
685  }
686  __except (EXCEPTION_EXECUTE_HANDLER)
687  {
688  return GetExceptionCode();
689  }
690  }
691 
692  // If the caller doesn't want to capture anything, return immediately.
693  if (backTraceSize == 0)
694  {
695  if (AccessMode != KernelMode)
696  {
697  __try
698  {
699  if (CapturedFrames)
700  *CapturedFrames = 0;
701  if (BackTraceHash)
702  *BackTraceHash = 0;
703  }
704  __except (EXCEPTION_EXECUTE_HANDLER)
705  {
706  status = GetExceptionCode();
707  }
708  }
709  else
710  {
711  if (CapturedFrames)
712  *CapturedFrames = 0;
713  if (BackTraceHash)
714  *BackTraceHash = 0;
715  }
716 
717  return status;
718  }
719 
720  // Allocate storage for the stack trace.
721  backTrace = ExAllocatePoolWithTag(NonPagedPool, backTraceSize, 'bhpK');
722 
723  if (!backTrace)
724  return STATUS_INSUFFICIENT_RESOURCES;
725 
726  // Initialize the context structure.
727  context.FramesToSkip = FramesToSkip;
728  context.FramesToCapture = FramesToCapture;
729  context.BackTrace = backTrace;
730 
731  // Check if we're trying to get a stack trace of the current thread.
732  // If so, we don't need to insert an APC.
733  if (Thread == PsGetCurrentThread())
734  {
735  PCAPTURE_BACKTRACE_THREAD_CONTEXT contextPtr = &context;
736  PVOID dummy = NULL;
737  KIRQL oldIrql;
738 
739  // Raise the IRQL to APC_LEVEL to simulate an APC environment,
740  // and call the APC routine directly.
741 
742  context.Local = TRUE;
743  KeRaiseIrql(APC_LEVEL, &oldIrql);
745  &context.Apc,
746  NULL,
747  NULL,
748  &contextPtr,
749  &dummy
750  );
751  KeLowerIrql(oldIrql);
752  }
753  else
754  {
755  context.Local = FALSE;
756  KeInitializeEvent(&context.CompletedEvent, NotificationEvent, FALSE);
758  &context.Apc,
759  (PKTHREAD)Thread,
762  NULL,
763  NULL,
764  KernelMode,
765  NULL
766  );
767 
768  if (KeInsertQueueApc(&context.Apc, &context, NULL, 2))
769  {
770  // Wait for the APC to complete.
771  status = KeWaitForSingleObject(
772  &context.CompletedEvent,
773  Executive,
774  KernelMode,
775  FALSE,
776  NULL
777  );
778  }
779  else
780  {
781  status = STATUS_UNSUCCESSFUL;
782  }
783  }
784 
785  if (NT_SUCCESS(status))
786  {
787  ASSERT(context.CapturedFrames <= FramesToCapture);
788 
789  if (AccessMode != KernelMode)
790  {
791  __try
792  {
793  memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID));
794 
795  if (CapturedFrames)
796  *CapturedFrames = context.CapturedFrames;
797  if (BackTraceHash)
798  *BackTraceHash = context.BackTraceHash;
799  }
800  __except (EXCEPTION_EXECUTE_HANDLER)
801  {
802  status = GetExceptionCode();
803  }
804  }
805  else
806  {
807  memcpy(BackTrace, backTrace, context.CapturedFrames * sizeof(PVOID));
808 
809  if (CapturedFrames)
810  *CapturedFrames = context.CapturedFrames;
811  if (BackTraceHash)
812  *BackTraceHash = context.BackTraceHash;
813  }
814  }
815 
816  ExFreePoolWithTag(backTrace, 'bhpK');
817 
818  return status;
819 }
820 
822  __in PRKAPC Apc,
823  __inout PKNORMAL_ROUTINE *NormalRoutine,
824  __inout PVOID *NormalContext,
825  __inout PVOID *SystemArgument1,
826  __inout PVOID *SystemArgument2
827  )
828 {
829  PCAPTURE_BACKTRACE_THREAD_CONTEXT context = *SystemArgument1;
830 
831  PAGED_CODE();
832 
833  context->CapturedFrames = KphCaptureStackBackTrace(
834  context->FramesToSkip,
835  context->FramesToCapture,
836  0,
837  context->BackTrace,
838  &context->BackTraceHash
839  );
840 
841  if (!context->Local)
842  {
843  // Notify the originating thread that we have completed.
844  KeSetEvent(&context->CompletedEvent, 0, FALSE);
845  }
846 }
847 
867  __in HANDLE ThreadHandle,
868  __in ULONG FramesToSkip,
869  __in ULONG FramesToCapture,
870  __out_ecount(FramesToCapture) PVOID *BackTrace,
871  __out_opt PULONG CapturedFrames,
872  __out_opt PULONG BackTraceHash,
873  __in KPROCESSOR_MODE AccessMode
874  )
875 {
876  NTSTATUS status = STATUS_SUCCESS;
877  PETHREAD thread;
878 
879  PAGED_CODE();
880 
881  status = ObReferenceObjectByHandle(
882  ThreadHandle,
883  0,
884  *PsThreadType,
885  AccessMode,
886  &thread,
887  NULL
888  );
889 
890  if (!NT_SUCCESS(status))
891  return status;
892 
894  thread,
895  FramesToSkip,
896  FramesToCapture,
897  BackTrace,
898  CapturedFrames,
899  BackTraceHash,
900  AccessMode
901  );
902  ObDereferenceObject(thread);
903 
904  return status;
905 }
906 
920  __in HANDLE ThreadHandle,
921  __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
922  __out_bcount(ProcessInformationLength) PVOID ThreadInformation,
923  __in ULONG ThreadInformationLength,
924  __out_opt PULONG ReturnLength,
925  __in KPROCESSOR_MODE AccessMode
926  )
927 {
928  NTSTATUS status;
929  PETHREAD thread;
930  ULONG returnLength;
931 
932  PAGED_CODE();
933 
934  if (AccessMode != KernelMode)
935  {
936  __try
937  {
938  ProbeForWrite(ThreadInformation, ThreadInformationLength, sizeof(ULONG));
939 
940  if (ReturnLength)
941  ProbeForWrite(ReturnLength, sizeof(ULONG), sizeof(ULONG));
942  }
943  __except (EXCEPTION_EXECUTE_HANDLER)
944  {
945  return GetExceptionCode();
946  }
947  }
948 
949  status = ObReferenceObjectByHandle(
950  ThreadHandle,
951  0,
952  *PsThreadType,
953  AccessMode,
954  &thread,
955  NULL
956  );
957 
958  if (!NT_SUCCESS(status))
959  return status;
960 
961  switch (ThreadInformationClass)
962  {
964  {
965  PVOID win32Thread;
966 
967  win32Thread = PsGetThreadWin32Thread(thread);
968 
969  if (ThreadInformationLength == sizeof(PVOID))
970  {
971  __try
972  {
973  *(PVOID *)ThreadInformation = win32Thread;
974  }
975  __except (EXCEPTION_EXECUTE_HANDLER)
976  {
977  status = GetExceptionCode();
978  }
979  }
980  else
981  {
982  status = STATUS_INFO_LENGTH_MISMATCH;
983  }
984 
985  returnLength = sizeof(PVOID);
986  }
987  break;
988  case KphThreadIoPriority:
989  {
990  HANDLE newThreadHandle;
991  ULONG ioPriority;
992 
993  if (NT_SUCCESS(status = ObOpenObjectByPointer(
994  thread,
996  NULL,
998  *PsThreadType,
999  KernelMode,
1000  &newThreadHandle
1001  )))
1002  {
1003  if (NT_SUCCESS(status = ZwQueryInformationThread(
1004  newThreadHandle,
1005  ThreadIoPriority,
1006  &ioPriority,
1007  sizeof(ULONG),
1008  NULL
1009  )))
1010  {
1011  if (ThreadInformationLength == sizeof(ULONG))
1012  {
1013  __try
1014  {
1015  *(PULONG)ThreadInformation = ioPriority;
1016  }
1017  __except (EXCEPTION_EXECUTE_HANDLER)
1018  {
1019  status = GetExceptionCode();
1020  }
1021  }
1022  else
1023  {
1024  status = STATUS_INFO_LENGTH_MISMATCH;
1025  }
1026  }
1027 
1028  ZwClose(newThreadHandle);
1029  }
1030 
1031  returnLength = sizeof(ULONG);
1032  }
1033  break;
1034  default:
1035  status = STATUS_INVALID_INFO_CLASS;
1036  returnLength = 0;
1037  break;
1038  }
1039 
1040  ObDereferenceObject(thread);
1041 
1042  if (ReturnLength)
1043  {
1044  if (AccessMode != KernelMode)
1045  {
1046  __try
1047  {
1048  *ReturnLength = returnLength;
1049  }
1050  __except (EXCEPTION_EXECUTE_HANDLER)
1051  {
1052  NOTHING;
1053  }
1054  }
1055  else
1056  {
1057  *ReturnLength = returnLength;
1058  }
1059  }
1060 
1061  return status;
1062 }
1063 
1075  __in HANDLE ThreadHandle,
1076  __in KPH_THREAD_INFORMATION_CLASS ThreadInformationClass,
1077  __in_bcount(ThreadInformationLength) PVOID ThreadInformation,
1078  __in ULONG ThreadInformationLength,
1079  __in KPROCESSOR_MODE AccessMode
1080  )
1081 {
1082  NTSTATUS status;
1083  PETHREAD thread;
1084 
1085  PAGED_CODE();
1086 
1087  if (AccessMode != KernelMode)
1088  {
1089  __try
1090  {
1091  ProbeForRead(ThreadInformation, ThreadInformationLength, sizeof(ULONG));
1092  }
1093  __except (EXCEPTION_EXECUTE_HANDLER)
1094  {
1095  return GetExceptionCode();
1096  }
1097  }
1098 
1099  status = ObReferenceObjectByHandle(
1100  ThreadHandle,
1101  0,
1102  *PsThreadType,
1103  AccessMode,
1104  &thread,
1105  NULL
1106  );
1107 
1108  if (!NT_SUCCESS(status))
1109  return status;
1110 
1111  switch (ThreadInformationClass)
1112  {
1114  {
1115  HANDLE tokenHandle = NULL;
1116  PACCESS_TOKEN token;
1117  HANDLE newTokenHandle;
1118 
1119  if (ThreadInformationLength == sizeof(HANDLE))
1120  {
1121  __try
1122  {
1123  tokenHandle = *(PHANDLE)ThreadInformation;
1124  }
1125  __except (EXCEPTION_EXECUTE_HANDLER)
1126  {
1127  status = GetExceptionCode();
1128  }
1129  }
1130  else
1131  {
1132  status = STATUS_INFO_LENGTH_MISMATCH;
1133  }
1134 
1135  if (NT_SUCCESS(status))
1136  {
1137  if (NT_SUCCESS(status = ObReferenceObjectByHandle(
1138  tokenHandle,
1139  TOKEN_IMPERSONATE,
1140  *SeTokenObjectType,
1141  AccessMode,
1142  &token,
1143  NULL
1144  )))
1145  {
1146  if (NT_SUCCESS(status = ObOpenObjectByPointer(
1147  token,
1149  NULL,
1150  TOKEN_IMPERSONATE,
1151  *SeTokenObjectType,
1152  KernelMode,
1153  &newTokenHandle
1154  )))
1155  {
1156  status = PsAssignImpersonationToken(thread, newTokenHandle);
1157  ZwClose(newTokenHandle);
1158  }
1159 
1160  ObDereferenceObject(token);
1161  }
1162  }
1163  }
1164  break;
1165  case KphThreadIoPriority:
1166  {
1167  ULONG ioPriority;
1168  HANDLE newThreadHandle;
1169 
1170  if (ThreadInformationLength == sizeof(ULONG))
1171  {
1172  __try
1173  {
1174  ioPriority = *(PULONG)ThreadInformation;
1175  }
1176  __except (EXCEPTION_EXECUTE_HANDLER)
1177  {
1178  status = GetExceptionCode();
1179  }
1180  }
1181  else
1182  {
1183  status = STATUS_INFO_LENGTH_MISMATCH;
1184  }
1185 
1186  if (NT_SUCCESS(status))
1187  {
1188  if (NT_SUCCESS(status = ObOpenObjectByPointer(
1189  thread,
1191  NULL,
1192  THREAD_SET_INFORMATION,
1193  *PsThreadType,
1194  KernelMode,
1195  &newThreadHandle
1196  )))
1197  {
1198  status = ZwSetInformationThread(
1199  newThreadHandle,
1200  ThreadIoPriority,
1201  &ioPriority,
1202  sizeof(ULONG)
1203  );
1204  ZwClose(newThreadHandle);
1205  }
1206  }
1207  }
1208  break;
1209  default:
1210  status = STATUS_INVALID_INFO_CLASS;
1211  break;
1212  }
1213 
1214  ObDereferenceObject(thread);
1215 
1216  return status;
1217 }