Process Hacker
hndlinfo.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * handle information
4  *
5  * Copyright (C) 2010-2015 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <ph.h>
24 #include <kphuser.h>
25 
26 #define PH_QUERY_HACK_MAX_THREADS 20
27 
28 typedef struct _PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT
29 {
30  SLIST_ENTRY ListEntry;
31 
33  PVOID Context;
34 
35  HANDLE StartEventHandle;
36  HANDLE CompletedEventHandle;
37  HANDLE ThreadHandle;
39 
41 {
47 
48 typedef struct _PHP_QUERY_OBJECT_COMMON_CONTEXT
49 {
51  NTSTATUS Status;
52 
53  union
54  {
55  struct
56  {
57  HANDLE Handle;
58  OBJECT_INFORMATION_CLASS ObjectInformationClass;
59  PVOID ObjectInformation;
60  ULONG ObjectInformationLength;
61  PULONG ReturnLength;
62  } NtQueryObject;
63  struct
64  {
65  HANDLE Handle;
66  SECURITY_INFORMATION SecurityInformation;
67  PSECURITY_DESCRIPTOR SecurityDescriptor;
68  ULONG Length;
69  PULONG LengthNeeded;
70  } NtQuerySecurityObject;
71  struct
72  {
73  HANDLE Handle;
74  SECURITY_INFORMATION SecurityInformation;
75  PSECURITY_DESCRIPTOR SecurityDescriptor;
76  } NtSetSecurityObject;
77  struct
78  {
79  HANDLE SourceProcessHandle;
80  HANDLE SourceHandle;
81  HANDLE TargetProcessHandle;
82  PHANDLE TargetHandle;
83  ACCESS_MASK DesiredAccess;
84  ULONG HandleAttributes;
85  ULONG Options;
87  } u;
89 
91  _In_opt_ PLARGE_INTEGER Timeout
92  );
93 
95  _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext
96  );
97 
98 NTSTATUS PhpCallWithTimeout(
99  _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext,
100  _In_ PUSER_THREAD_START_ROUTINE Routine,
101  _In_opt_ PVOID Context,
102  _In_ PLARGE_INTEGER Timeout
103  );
104 
106  _In_ PVOID Parameter
107  );
108 
109 static PPH_STRING PhObjectTypeNames[MAX_OBJECT_TYPE_NUMBER] = { 0 };
110 static PPH_GET_CLIENT_ID_NAME PhHandleGetClientIdName = PhStdGetClientIdName;
111 
112 static SLIST_HEADER PhpCallWithTimeoutThreadListHead;
113 static PH_QUEUED_LOCK PhpCallWithTimeoutThreadReleaseEvent = PH_QUEUED_LOCK_INIT;
114 
116  _In_ PPH_GET_CLIENT_ID_NAME GetClientIdName
117  )
118 {
120  (PVOID *)&PhHandleGetClientIdName,
121  GetClientIdName
122  );
123 }
124 
126  _In_ HANDLE ProcessHandle,
127  _In_ HANDLE Handle,
128  _Out_ POBJECT_BASIC_INFORMATION BasicInformation
129  )
130 {
131  NTSTATUS status;
132 
133  if (KphIsConnected())
134  {
135  status = KphQueryInformationObject(
136  ProcessHandle,
137  Handle,
139  BasicInformation,
140  sizeof(OBJECT_BASIC_INFORMATION),
141  NULL
142  );
143 
144  if (NT_SUCCESS(status))
145  {
146  // The object was referenced in KProcessHacker, so
147  // we need to subtract 1 from the pointer count.
148  BasicInformation->PointerCount -= 1;
149  }
150  }
151  else
152  {
153  status = NtQueryObject(
154  Handle,
155  ObjectBasicInformation,
156  BasicInformation,
157  sizeof(OBJECT_BASIC_INFORMATION),
158  NULL
159  );
160 
161  if (NT_SUCCESS(status))
162  {
163  // The object was referenced in NtQueryObject and
164  // a handle was opened to the object. We need to
165  // subtract 1 from the pointer count, then subtract
166  // 1 from both counts.
167  BasicInformation->HandleCount -= 1;
168  BasicInformation->PointerCount -= 2;
169  }
170  }
171 
172  return status;
173 }
174 
176  _In_ HANDLE ProcessHandle,
177  _In_ HANDLE Handle,
178  _In_ ULONG ObjectTypeNumber,
179  _Out_ PPH_STRING *TypeName
180  )
181 {
182  NTSTATUS status = STATUS_SUCCESS;
183  PPH_STRING typeName = NULL;
184 
185  // If the cache contains the object type name, use it. Otherwise,
186  // query the type name.
187 
188  if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER)
189  typeName = PhObjectTypeNames[ObjectTypeNumber];
190 
191  if (typeName)
192  {
193  PhReferenceObject(typeName);
194  }
195  else
196  {
198  ULONG returnLength = 0;
199  PPH_STRING oldTypeName;
200 
201  // Get the needed buffer size.
202  if (KphIsConnected())
203  {
204  status = KphQueryInformationObject(
205  ProcessHandle,
206  Handle,
208  NULL,
209  0,
210  &returnLength
211  );
212  }
213  else
214  {
215  status = NtQueryObject(
216  Handle,
217  ObjectTypeInformation,
218  NULL,
219  0,
220  &returnLength
221  );
222  }
223 
224  if (returnLength == 0)
225  return status;
226 
227  buffer = PhAllocate(returnLength);
228 
229  if (KphIsConnected())
230  {
231  status = KphQueryInformationObject(
232  ProcessHandle,
233  Handle,
235  buffer,
236  returnLength,
237  &returnLength
238  );
239  }
240  else
241  {
242  status = NtQueryObject(
243  Handle,
244  ObjectTypeInformation,
245  buffer,
246  returnLength,
247  &returnLength
248  );
249  }
250 
251  if (!NT_SUCCESS(status))
252  {
253  PhFree(buffer);
254  return status;
255  }
256 
257  // Create a copy of the type name.
258  typeName = PhCreateStringFromUnicodeString(&buffer->TypeName);
259 
260  if (ObjectTypeNumber != -1 && ObjectTypeNumber < MAX_OBJECT_TYPE_NUMBER)
261  {
262  // Try to store the type name in the cache.
264  &PhObjectTypeNames[ObjectTypeNumber],
265  typeName,
266  NULL
267  );
268 
269  // Add a reference if we stored the type name
270  // successfully.
271  if (!oldTypeName)
272  PhReferenceObject(typeName);
273  }
274 
275  PhFree(buffer);
276  }
277 
278  // At this point typeName should contain a type name
279  // with one additional reference.
280 
281  *TypeName = typeName;
282 
283  return status;
284 }
285 
287  _In_ HANDLE ProcessHandle,
288  _In_ HANDLE Handle,
289  _In_ BOOLEAN WithTimeout,
290  _Out_ PPH_STRING *ObjectName
291  )
292 {
293  NTSTATUS status;
294  POBJECT_NAME_INFORMATION buffer;
295  ULONG bufferSize;
296  ULONG attempts = 8;
297 
298  bufferSize = 0x200;
299  buffer = PhAllocate(bufferSize);
300 
301  // A loop is needed because the I/O subsystem likes to give us the wrong return lengths...
302  do
303  {
304  if (KphIsConnected())
305  {
306  status = KphQueryInformationObject(
307  ProcessHandle,
308  Handle,
310  buffer,
311  bufferSize,
312  &bufferSize
313  );
314  }
315  else
316  {
317  if (WithTimeout)
318  {
320  Handle,
322  buffer,
323  bufferSize,
324  &bufferSize
325  );
326  }
327  else
328  {
329  status = NtQueryObject(
330  Handle,
332  buffer,
333  bufferSize,
334  &bufferSize
335  );
336  }
337  }
338 
339  if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH ||
340  status == STATUS_BUFFER_TOO_SMALL)
341  {
342  PhFree(buffer);
343  buffer = PhAllocate(bufferSize);
344  }
345  else
346  {
347  break;
348  }
349  } while (--attempts);
350 
351  if (NT_SUCCESS(status))
352  {
353  *ObjectName = PhCreateStringFromUnicodeString(&buffer->Name);
354  }
355 
356  PhFree(buffer);
357 
358  return status;
359 }
360 
362  _In_ PPH_STRING Name
363  )
364 {
365  static PH_STRINGREF hklmPrefix = PH_STRINGREF_INIT(L"\\Registry\\Machine");
366  static PH_STRINGREF hkcrPrefix = PH_STRINGREF_INIT(L"\\Registry\\Machine\\Software\\Classes");
367  static PH_STRINGREF hkuPrefix = PH_STRINGREF_INIT(L"\\Registry\\User");
368  static PPH_STRING hkcuPrefix;
369  static PPH_STRING hkcucrPrefix;
370 
371  static PH_STRINGREF hklmString = PH_STRINGREF_INIT(L"HKLM");
372  static PH_STRINGREF hkcrString = PH_STRINGREF_INIT(L"HKCR");
373  static PH_STRINGREF hkuString = PH_STRINGREF_INIT(L"HKU");
374  static PH_STRINGREF hkcuString = PH_STRINGREF_INIT(L"HKCU");
375  static PH_STRINGREF hkcucrString = PH_STRINGREF_INIT(L"HKCU\\Software\\Classes");
376 
377  static PH_INITONCE initOnce = PH_INITONCE_INIT;
378 
379  PPH_STRING newName;
380  PH_STRINGREF name;
381 
382  if (PhBeginInitOnce(&initOnce))
383  {
384  PTOKEN_USER tokenUser;
385  PPH_STRING stringSid = NULL;
386 
388  {
391  &tokenUser
392  )))
393  {
394  stringSid = PhSidToStringSid(tokenUser->User.Sid);
395  PhFree(tokenUser);
396  }
397  }
398 
399  if (stringSid)
400  {
401  static PH_STRINGREF registryUserPrefix = PH_STRINGREF_INIT(L"\\Registry\\User\\");
402  static PH_STRINGREF classesString = PH_STRINGREF_INIT(L"_Classes");
403 
404  hkcuPrefix = PhConcatStringRef2(&registryUserPrefix, &stringSid->sr);
405  hkcucrPrefix = PhConcatStringRef2(&hkcuPrefix->sr, &classesString);
406 
407  PhDereferenceObject(stringSid);
408  }
409  else
410  {
411  hkcuPrefix = PhCreateString(L"..."); // some random string that won't ever get matched
412  hkcucrPrefix = PhCreateString(L"...");
413  }
414 
415  PhEndInitOnce(&initOnce);
416  }
417 
418  name = Name->sr;
419 
420  if (PhStartsWithStringRef(&name, &hkcrPrefix, TRUE))
421  {
422  PhSkipStringRef(&name, hkcrPrefix.Length);
423  newName = PhConcatStringRef2(&hkcrString, &name);
424  }
425  else if (PhStartsWithStringRef(&name, &hklmPrefix, TRUE))
426  {
427  PhSkipStringRef(&name, hklmPrefix.Length);
428  newName = PhConcatStringRef2(&hklmString, &name);
429  }
430  else if (PhStartsWithStringRef(&name, &hkcucrPrefix->sr, TRUE))
431  {
432  PhSkipStringRef(&name, hkcucrPrefix->Length);
433  newName = PhConcatStringRef2(&hkcucrString, &name);
434  }
435  else if (PhStartsWithStringRef(&name, &hkcuPrefix->sr, TRUE))
436  {
437  PhSkipStringRef(&name, hkcuPrefix->Length);
438  newName = PhConcatStringRef2(&hkcuString, &name);
439  }
440  else if (PhStartsWithStringRef(&name, &hkuPrefix, TRUE))
441  {
442  PhSkipStringRef(&name, hkuPrefix.Length);
443  newName = PhConcatStringRef2(&hkuString, &name);
444  }
445  else
446  {
447  PhSetReference(&newName, Name);
448  }
449 
450  return newName;
451 }
452 
454  _In_ HANDLE SectionHandle,
455  _Out_ PPH_STRING *FileName
456  )
457 {
458  NTSTATUS status;
459  SIZE_T viewSize;
460  PVOID viewBase;
461 
462  viewSize = 1;
463  viewBase = NULL;
464 
465  status = NtMapViewOfSection(
466  SectionHandle,
467  NtCurrentProcess(),
468  &viewBase,
469  0,
470  0,
471  NULL,
472  &viewSize,
473  ViewShare,
474  0,
475  PAGE_READONLY
476  );
477 
478  if (!NT_SUCCESS(status))
479  return status;
480 
481  status = PhGetProcessMappedFileName(NtCurrentProcess(), viewBase, FileName);
482  NtUnmapViewOfSection(NtCurrentProcess(), viewBase);
483 
484  return status;
485 }
486 
488  _In_ PCLIENT_ID ClientId
489  )
490 {
491  static PH_QUEUED_LOCK cachedProcessesLock = PH_QUEUED_LOCK_INIT;
492  static PVOID processes = NULL;
493  static ULONG lastProcessesTickCount = 0;
494 
495  PPH_STRING name;
496  ULONG tickCount;
497  PSYSTEM_PROCESS_INFORMATION processInfo;
498 
499  // Get a new process list only if 2 seconds have passed
500  // since the last update.
501 
502  tickCount = GetTickCount();
503 
504  if (tickCount - lastProcessesTickCount >= 2000)
505  {
506  PhAcquireQueuedLockExclusive(&cachedProcessesLock);
507 
508  // Re-check the tick count.
509  if (tickCount - lastProcessesTickCount >= 2000)
510  {
511  if (processes)
512  {
513  PhFree(processes);
514  processes = NULL;
515  }
516 
517  if (!NT_SUCCESS(PhEnumProcesses(&processes)))
518  {
519  PhReleaseQueuedLockExclusive(&cachedProcessesLock);
520  return PhCreateString(L"(Error querying processes)");
521  }
522 
523  lastProcessesTickCount = tickCount;
524  }
525 
526  PhReleaseQueuedLockExclusive(&cachedProcessesLock);
527  }
528 
529  // Get a lock on the process list and get a name for the client ID.
530 
531  PhAcquireQueuedLockShared(&cachedProcessesLock);
532 
533  if (!processes)
534  {
535  PhReleaseQueuedLockShared(&cachedProcessesLock);
536  return NULL;
537  }
538 
539  processInfo = PhFindProcessInformation(processes, ClientId->UniqueProcess);
540 
541  if (ClientId->UniqueThread)
542  {
543  if (processInfo)
544  {
545  name = PhFormatString(
546  L"%.*s (%u): %u",
547  processInfo->ImageName.Length / 2,
548  processInfo->ImageName.Buffer,
549  (ULONG)ClientId->UniqueProcess,
550  (ULONG)ClientId->UniqueThread
551  );
552  }
553  else
554  {
555  name = PhFormatString(L"Non-existent process (%u): %u",
556  (ULONG)ClientId->UniqueProcess, (ULONG)ClientId->UniqueThread);
557  }
558  }
559  else
560  {
561  if (processInfo)
562  {
563  name = PhFormatString(
564  L"%.*s (%u)",
565  processInfo->ImageName.Length / 2,
566  processInfo->ImageName.Buffer,
567  (ULONG)ClientId->UniqueProcess
568  );
569  }
570  else
571  {
572  name = PhFormatString(L"Non-existent process (%u)", (ULONG)ClientId->UniqueProcess);
573  }
574  }
575 
576  PhReleaseQueuedLockShared(&cachedProcessesLock);
577 
578  return name;
579 }
580 
582  _In_ HANDLE ProcessHandle,
583  _In_ HANDLE Handle,
584  _In_ PPH_STRING ObjectName,
585  _In_ PPH_STRING TypeName,
586  _Out_ PPH_STRING *BestObjectName
587  )
588 {
589  NTSTATUS status;
590  PPH_STRING bestObjectName = NULL;
591  PPH_GET_CLIENT_ID_NAME handleGetClientIdName = PhHandleGetClientIdName;
592 
593  if (PhEqualString2(TypeName, L"EtwRegistration", TRUE))
594  {
595  if (KphIsConnected())
596  {
597  ETWREG_BASIC_INFORMATION basicInfo;
598 
599  status = KphQueryInformationObject(
600  ProcessHandle,
601  Handle,
603  &basicInfo,
604  sizeof(ETWREG_BASIC_INFORMATION),
605  NULL
606  );
607 
608  if (NT_SUCCESS(status))
609  {
610  static PH_STRINGREF publishersKeyName = PH_STRINGREF_INIT(L"Software\\Microsoft\\Windows\\CurrentVersion\\WINEVT\\Publishers\\");
611 
612  PPH_STRING guidString;
613  PPH_STRING keyName;
614  HANDLE keyHandle;
615  PPH_STRING publisherName = NULL;
616 
617  guidString = PhFormatGuid(&basicInfo.Guid);
618 
619  // We should perform a lookup on the GUID to get the publisher name.
620 
621  keyName = PhConcatStringRef2(&publishersKeyName, &guidString->sr);
622 
623  if (NT_SUCCESS(PhOpenKey(
624  &keyHandle,
625  KEY_READ,
627  &keyName->sr,
628  0
629  )))
630  {
631  publisherName = PhQueryRegistryString(keyHandle, NULL);
632 
633  if (publisherName && publisherName->Length == 0)
634  {
635  PhDereferenceObject(publisherName);
636  publisherName = NULL;
637  }
638 
639  NtClose(keyHandle);
640  }
641 
642  PhDereferenceObject(keyName);
643 
644  if (publisherName)
645  {
646  bestObjectName = publisherName;
647  PhDereferenceObject(guidString);
648  }
649  else
650  {
651  bestObjectName = guidString;
652  }
653  }
654  }
655  }
656  else if (PhEqualString2(TypeName, L"File", TRUE))
657  {
658  // Convert the file name to a DOS file name.
659  bestObjectName = PhResolveDevicePrefix(ObjectName);
660 
661  if (!bestObjectName)
662  {
663  // The file doesn't have a DOS name.
664  PhSetReference(&bestObjectName, ObjectName);
665  }
666 
667  if (PhIsNullOrEmptyString(bestObjectName) && KphIsConnected())
668  {
669  KPH_FILE_OBJECT_DRIVER fileObjectDriver;
670  PPH_STRING driverName;
671 
672  status = KphQueryInformationObject(
673  ProcessHandle,
674  Handle,
676  &fileObjectDriver,
677  sizeof(KPH_FILE_OBJECT_DRIVER),
678  NULL
679  );
680 
681  if (NT_SUCCESS(status) && fileObjectDriver.DriverHandle)
682  {
683  if (NT_SUCCESS(PhGetDriverName(fileObjectDriver.DriverHandle, &driverName)))
684  {
685  static PH_STRINGREF prefix = PH_STRINGREF_INIT(L"Unnamed file: ");
686 
687  PhMoveReference(&bestObjectName, PhConcatStringRef2(&prefix, &driverName->sr));
688  PhDereferenceObject(driverName);
689  }
690 
691  NtClose(fileObjectDriver.DriverHandle);
692  }
693  }
694  }
695  else if (PhEqualString2(TypeName, L"Job", TRUE))
696  {
697  HANDLE dupHandle;
698  PJOBOBJECT_BASIC_PROCESS_ID_LIST processIdList;
699 
700  status = NtDuplicateObject(
701  ProcessHandle,
702  Handle,
703  NtCurrentProcess(),
704  &dupHandle,
706  0,
707  0
708  );
709 
710  if (!NT_SUCCESS(status))
711  goto CleanupExit;
712 
713  if (handleGetClientIdName && NT_SUCCESS(PhGetJobProcessIdList(dupHandle, &processIdList)))
714  {
716  ULONG i;
717  CLIENT_ID clientId;
718  PPH_STRING name;
719 
720  PhInitializeStringBuilder(&sb, 40);
721  clientId.UniqueThread = NULL;
722 
723  for (i = 0; i < processIdList->NumberOfProcessIdsInList; i++)
724  {
725  clientId.UniqueProcess = (HANDLE)processIdList->ProcessIdList[i];
726  name = handleGetClientIdName(&clientId);
727 
728  if (name)
729  {
730  PhAppendStringBuilder(&sb, &name->sr);
731  PhAppendStringBuilder2(&sb, L"; ");
732  PhDereferenceObject(name);
733  }
734  }
735 
736  PhFree(processIdList);
737 
738  if (sb.String->Length != 0)
739  PhRemoveEndStringBuilder(&sb, 2);
740 
741  if (sb.String->Length == 0)
742  PhAppendStringBuilder2(&sb, L"(No processes)");
743 
744  bestObjectName = PhFinalStringBuilderString(&sb);
745  }
746 
747  NtClose(dupHandle);
748  }
749  else if (PhEqualString2(TypeName, L"Key", TRUE))
750  {
751  bestObjectName = PhFormatNativeKeyName(ObjectName);
752  }
753  else if (PhEqualString2(TypeName, L"Process", TRUE))
754  {
755  CLIENT_ID clientId;
756 
757  clientId.UniqueThread = NULL;
758 
759  if (KphIsConnected())
760  {
761  PROCESS_BASIC_INFORMATION basicInfo;
762 
763  status = KphQueryInformationObject(
764  ProcessHandle,
765  Handle,
767  &basicInfo,
768  sizeof(PROCESS_BASIC_INFORMATION),
769  NULL
770  );
771 
772  if (!NT_SUCCESS(status))
773  goto CleanupExit;
774 
775  clientId.UniqueProcess = basicInfo.UniqueProcessId;
776  }
777  else
778  {
779  HANDLE dupHandle;
780  PROCESS_BASIC_INFORMATION basicInfo;
781 
782  status = NtDuplicateObject(
783  ProcessHandle,
784  Handle,
785  NtCurrentProcess(),
786  &dupHandle,
788  0,
789  0
790  );
791 
792  if (!NT_SUCCESS(status))
793  goto CleanupExit;
794 
795  status = PhGetProcessBasicInformation(dupHandle, &basicInfo);
796  NtClose(dupHandle);
797 
798  if (!NT_SUCCESS(status))
799  goto CleanupExit;
800 
801  clientId.UniqueProcess = basicInfo.UniqueProcessId;
802  }
803 
804  if (handleGetClientIdName)
805  bestObjectName = handleGetClientIdName(&clientId);
806  }
807  else if (PhEqualString2(TypeName, L"Section", TRUE))
808  {
809  HANDLE dupHandle;
810  PPH_STRING fileName;
811 
812  if (!PhIsNullOrEmptyString(ObjectName))
813  goto CleanupExit;
814 
815  status = NtDuplicateObject(
816  ProcessHandle,
817  Handle,
818  NtCurrentProcess(),
819  &dupHandle,
820  SECTION_QUERY | SECTION_MAP_READ,
821  0,
822  0
823  );
824 
825  if (!NT_SUCCESS(status))
826  goto CleanupExit;
827 
828  status = PhGetSectionFileName(dupHandle, &fileName);
829 
830  if (NT_SUCCESS(status))
831  {
832  bestObjectName = PhResolveDevicePrefix(fileName);
833  PhDereferenceObject(fileName);
834  }
835  else
836  {
837  SECTION_BASIC_INFORMATION basicInfo;
838 
839  if (NT_SUCCESS(PhGetSectionBasicInformation(dupHandle, &basicInfo)))
840  {
841  PH_FORMAT format[4];
842  PWSTR sectionType = L"Unknown";
843 
844  if (basicInfo.AllocationAttributes & SEC_COMMIT)
845  sectionType = L"Commit";
846  else if (basicInfo.AllocationAttributes & SEC_FILE)
847  sectionType = L"File";
848  else if (basicInfo.AllocationAttributes & SEC_IMAGE)
849  sectionType = L"Image";
850  else if (basicInfo.AllocationAttributes & SEC_RESERVE)
851  sectionType = L"Reserve";
852 
853  PhInitFormatS(&format[0], sectionType);
854  PhInitFormatS(&format[1], L" (");
855  PhInitFormatSize(&format[2], basicInfo.MaximumSize.QuadPart);
856  PhInitFormatC(&format[3], ')');
857  bestObjectName = PhFormat(format, 4, 20);
858  }
859  }
860 
861  NtClose(dupHandle);
862  }
863  else if (PhEqualString2(TypeName, L"Thread", TRUE))
864  {
865  CLIENT_ID clientId;
866 
867  if (KphIsConnected())
868  {
869  THREAD_BASIC_INFORMATION basicInfo;
870 
871  status = KphQueryInformationObject(
872  ProcessHandle,
873  Handle,
875  &basicInfo,
876  sizeof(THREAD_BASIC_INFORMATION),
877  NULL
878  );
879 
880  if (!NT_SUCCESS(status))
881  goto CleanupExit;
882 
883  clientId = basicInfo.ClientId;
884  }
885  else
886  {
887  HANDLE dupHandle;
888  THREAD_BASIC_INFORMATION basicInfo;
889 
890  status = NtDuplicateObject(
891  ProcessHandle,
892  Handle,
893  NtCurrentProcess(),
894  &dupHandle,
896  0,
897  0
898  );
899 
900  if (!NT_SUCCESS(status))
901  goto CleanupExit;
902 
903  status = PhGetThreadBasicInformation(dupHandle, &basicInfo);
904  NtClose(dupHandle);
905 
906  if (!NT_SUCCESS(status))
907  goto CleanupExit;
908 
909  clientId = basicInfo.ClientId;
910  }
911 
912  if (handleGetClientIdName)
913  bestObjectName = handleGetClientIdName(&clientId);
914  }
915  else if (PhEqualString2(TypeName, L"TmEn", TRUE))
916  {
917  HANDLE dupHandle;
918  ENLISTMENT_BASIC_INFORMATION basicInfo;
919 
920  status = NtDuplicateObject(
921  ProcessHandle,
922  Handle,
923  NtCurrentProcess(),
924  &dupHandle,
925  ENLISTMENT_QUERY_INFORMATION,
926  0,
927  0
928  );
929 
930  if (!NT_SUCCESS(status))
931  goto CleanupExit;
932 
933  status = PhGetEnlistmentBasicInformation(dupHandle, &basicInfo);
934  NtClose(dupHandle);
935 
936  if (NT_SUCCESS(status))
937  {
938  bestObjectName = PhFormatGuid(&basicInfo.EnlistmentId);
939  }
940  }
941  else if (PhEqualString2(TypeName, L"TmRm", TRUE))
942  {
943  HANDLE dupHandle;
944  GUID guid;
945  PPH_STRING description;
946 
947  status = NtDuplicateObject(
948  ProcessHandle,
949  Handle,
950  NtCurrentProcess(),
951  &dupHandle,
952  RESOURCEMANAGER_QUERY_INFORMATION,
953  0,
954  0
955  );
956 
957  if (!NT_SUCCESS(status))
958  goto CleanupExit;
959 
961  dupHandle,
962  &guid,
963  &description
964  );
965  NtClose(dupHandle);
966 
967  if (NT_SUCCESS(status))
968  {
969  if (!PhIsNullOrEmptyString(description))
970  {
971  bestObjectName = description;
972  }
973  else
974  {
975  bestObjectName = PhFormatGuid(&guid);
976 
977  if (description)
978  PhDereferenceObject(description);
979  }
980  }
981  }
982  else if (PhEqualString2(TypeName, L"TmTm", TRUE))
983  {
984  HANDLE dupHandle;
985  PPH_STRING logFileName = NULL;
986  TRANSACTIONMANAGER_BASIC_INFORMATION basicInfo;
987 
988  status = NtDuplicateObject(
989  ProcessHandle,
990  Handle,
991  NtCurrentProcess(),
992  &dupHandle,
993  TRANSACTIONMANAGER_QUERY_INFORMATION,
994  0,
995  0
996  );
997 
998  if (!NT_SUCCESS(status))
999  goto CleanupExit;
1000 
1002  dupHandle,
1003  &logFileName
1004  );
1005 
1006  if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(logFileName))
1007  {
1008  bestObjectName = PhGetFileName(logFileName);
1009  PhDereferenceObject(logFileName);
1010  }
1011  else
1012  {
1013  if (logFileName)
1014  PhDereferenceObject(logFileName);
1015 
1017  dupHandle,
1018  &basicInfo
1019  );
1020 
1021  if (NT_SUCCESS(status))
1022  {
1023  bestObjectName = PhFormatGuid(&basicInfo.TmIdentity);
1024  }
1025  }
1026 
1027  NtClose(dupHandle);
1028  }
1029  else if (PhEqualString2(TypeName, L"TmTx", TRUE))
1030  {
1031  HANDLE dupHandle;
1032  PPH_STRING description = NULL;
1033  TRANSACTION_BASIC_INFORMATION basicInfo;
1034 
1035  status = NtDuplicateObject(
1036  ProcessHandle,
1037  Handle,
1038  NtCurrentProcess(),
1039  &dupHandle,
1040  TRANSACTION_QUERY_INFORMATION,
1041  0,
1042  0
1043  );
1044 
1045  if (!NT_SUCCESS(status))
1046  goto CleanupExit;
1047 
1049  dupHandle,
1050  NULL,
1051  NULL,
1052  &description
1053  );
1054 
1055  if (NT_SUCCESS(status) && !PhIsNullOrEmptyString(description))
1056  {
1057  bestObjectName = description;
1058  }
1059  else
1060  {
1061  if (description)
1062  PhDereferenceObject(description);
1063 
1065  dupHandle,
1066  &basicInfo
1067  );
1068 
1069  if (NT_SUCCESS(status))
1070  {
1071  bestObjectName = PhFormatGuid(&basicInfo.TransactionId);
1072  }
1073  }
1074 
1075  NtClose(dupHandle);
1076  }
1077  else if (PhEqualString2(TypeName, L"Token", TRUE))
1078  {
1079  HANDLE dupHandle;
1080  PTOKEN_USER tokenUser = NULL;
1081  TOKEN_STATISTICS statistics = { 0 };
1082 
1083  status = NtDuplicateObject(
1084  ProcessHandle,
1085  Handle,
1086  NtCurrentProcess(),
1087  &dupHandle,
1088  TOKEN_QUERY,
1089  0,
1090  0
1091  );
1092 
1093  if (!NT_SUCCESS(status))
1094  goto CleanupExit;
1095 
1096  status = PhGetTokenUser(dupHandle, &tokenUser);
1097  PhGetTokenStatistics(dupHandle, &statistics);
1098 
1099  if (NT_SUCCESS(status))
1100  {
1101  PPH_STRING fullName;
1102 
1103  fullName = PhGetSidFullName(tokenUser->User.Sid, TRUE, NULL);
1104 
1105  if (fullName)
1106  {
1107  PH_FORMAT format[4];
1108 
1109  PhInitFormatSR(&format[0], fullName->sr);
1110  PhInitFormatS(&format[1], L": 0x");
1111  PhInitFormatX(&format[2], statistics.AuthenticationId.LowPart);
1112  PhInitFormatS(&format[3], statistics.TokenType == TokenPrimary ? L" (Primary)" : L" (Impersonation)");
1113 
1114  bestObjectName = PhFormat(format, 4, fullName->Length + 8 + 16 + 16);
1115  PhDereferenceObject(fullName);
1116  }
1117 
1118  PhFree(tokenUser);
1119  }
1120 
1121  NtClose(dupHandle);
1122  }
1123 
1124 CleanupExit:
1125 
1126  if (!bestObjectName)
1127  PhSetReference(&bestObjectName, ObjectName);
1128 
1129  *BestObjectName = bestObjectName;
1130 
1131  return STATUS_SUCCESS;
1132 }
1133 
1156  _In_ HANDLE ProcessHandle,
1157  _In_ HANDLE Handle,
1158  _In_ ULONG ObjectTypeNumber,
1159  _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,
1160  _Out_opt_ PPH_STRING *TypeName,
1161  _Out_opt_ PPH_STRING *ObjectName,
1162  _Out_opt_ PPH_STRING *BestObjectName
1163  )
1164 {
1165  NTSTATUS status;
1166  NTSTATUS subStatus;
1167 
1168  status = PhGetHandleInformationEx(
1169  ProcessHandle,
1170  Handle,
1171  ObjectTypeNumber,
1172  0,
1173  &subStatus,
1174  BasicInformation,
1175  TypeName,
1176  ObjectName,
1177  BestObjectName,
1178  NULL
1179  );
1180 
1181  if (!NT_SUCCESS(status))
1182  return status;
1183 
1184  // Fail if any component failed, for compatibility reasons.
1185  if (!NT_SUCCESS(subStatus))
1186  {
1187  if (TypeName)
1188  PhClearReference(TypeName);
1189  if (ObjectName)
1190  PhClearReference(ObjectName);
1191  if (BestObjectName)
1192  PhClearReference(BestObjectName);
1193 
1194  return subStatus;
1195  }
1196 
1197  return status;
1198 }
1199 
1233  _In_ HANDLE ProcessHandle,
1234  _In_ HANDLE Handle,
1235  _In_ ULONG ObjectTypeNumber,
1236  _Reserved_ ULONG Flags,
1237  _Out_opt_ PNTSTATUS SubStatus,
1238  _Out_opt_ POBJECT_BASIC_INFORMATION BasicInformation,
1239  _Out_opt_ PPH_STRING *TypeName,
1240  _Out_opt_ PPH_STRING *ObjectName,
1241  _Out_opt_ PPH_STRING *BestObjectName,
1242  _Reserved_ PVOID *ExtraInformation
1243  )
1244 {
1245  NTSTATUS status = STATUS_SUCCESS;
1246  NTSTATUS subStatus = STATUS_SUCCESS;
1247  HANDLE dupHandle = NULL;
1248  PPH_STRING typeName = NULL;
1249  PPH_STRING objectName = NULL;
1250  PPH_STRING bestObjectName = NULL;
1251 
1252  if (Handle == NULL || Handle == NtCurrentProcess() || Handle == NtCurrentThread())
1253  return STATUS_INVALID_HANDLE;
1254  if (ObjectTypeNumber != -1 && ObjectTypeNumber >= MAX_OBJECT_TYPE_NUMBER)
1255  return STATUS_INVALID_PARAMETER_3;
1256 
1257  // Duplicate the handle if we're not using KPH.
1258  if (!KphIsConnected())
1259  {
1260  // However, we obviously don't need to duplicate it
1261  // if the handle is in the current process.
1262  if (ProcessHandle != NtCurrentProcess())
1263  {
1264  status = NtDuplicateObject(
1265  ProcessHandle,
1266  Handle,
1267  NtCurrentProcess(),
1268  &dupHandle,
1269  0,
1270  0,
1271  0
1272  );
1273 
1274  if (!NT_SUCCESS(status))
1275  return status;
1276  }
1277  else
1278  {
1279  dupHandle = Handle;
1280  }
1281  }
1282 
1283  // Get basic information.
1284  if (BasicInformation)
1285  {
1287  ProcessHandle,
1288  KphIsConnected() ? Handle : dupHandle,
1289  BasicInformation
1290  );
1291 
1292  if (!NT_SUCCESS(status))
1293  goto CleanupExit;
1294  }
1295 
1296  // Exit early if we don't need to get any other information.
1297  if (!TypeName && !ObjectName && !BestObjectName)
1298  goto CleanupExit;
1299 
1300  // Get the type name.
1301  status = PhpGetObjectTypeName(
1302  ProcessHandle,
1303  KphIsConnected() ? Handle : dupHandle,
1304  ObjectTypeNumber,
1305  &typeName
1306  );
1307 
1308  if (!NT_SUCCESS(status))
1309  goto CleanupExit;
1310 
1311  // Exit early if we don't need to get the object name.
1312  if (!ObjectName && !BestObjectName)
1313  goto CleanupExit;
1314 
1315  // Get the object name.
1316  // If we're dealing with a file handle we must take special precautions so we don't hang.
1317  if (PhEqualString2(typeName, L"File", TRUE) && !KphIsConnected())
1318  {
1319 #define QUERY_NORMALLY 0
1320 #define QUERY_WITH_TIMEOUT 1
1321 #define QUERY_FAIL 2
1322 
1323  ULONG hackLevel = QUERY_WITH_TIMEOUT;
1324 
1325  // We can't use the timeout method on XP because hanging threads can't even be terminated!
1326  if (WindowsVersion <= WINDOWS_XP)
1327  hackLevel = QUERY_FAIL;
1328 
1329  if (hackLevel == QUERY_NORMALLY || hackLevel == QUERY_WITH_TIMEOUT)
1330  {
1331  status = PhpGetObjectName(
1332  ProcessHandle,
1333  KphIsConnected() ? Handle : dupHandle,
1334  hackLevel == QUERY_WITH_TIMEOUT,
1335  &objectName
1336  );
1337  }
1338  else
1339  {
1340  // Pretend the file object has no name.
1341  objectName = PhReferenceEmptyString();
1342  status = STATUS_SUCCESS;
1343  }
1344  }
1345  else
1346  {
1347  // Query the object normally.
1348  status = PhpGetObjectName(
1349  ProcessHandle,
1350  KphIsConnected() ? Handle : dupHandle,
1351  FALSE,
1352  &objectName
1353  );
1354  }
1355 
1356  if (!NT_SUCCESS(status))
1357  {
1358  if (PhEqualString2(typeName, L"File", TRUE) && KphIsConnected())
1359  {
1360  // PhpGetBestObjectName can provide us with a name.
1361  objectName = PhReferenceEmptyString();
1362  status = STATUS_SUCCESS;
1363  }
1364  else
1365  {
1366  subStatus = status;
1367  status = STATUS_SUCCESS;
1368  goto CleanupExit;
1369  }
1370  }
1371 
1372  // Exit early if we don't need to get the best object name.
1373  if (!BestObjectName)
1374  goto CleanupExit;
1375 
1376  status = PhpGetBestObjectName(
1377  ProcessHandle,
1378  Handle,
1379  objectName,
1380  typeName,
1381  &bestObjectName
1382  );
1383 
1384  if (!NT_SUCCESS(status))
1385  {
1386  subStatus = status;
1387  status = STATUS_SUCCESS;
1388  goto CleanupExit;
1389  }
1390 
1391 CleanupExit:
1392 
1393  if (NT_SUCCESS(status))
1394  {
1395  if (SubStatus)
1396  *SubStatus = subStatus;
1397  if (TypeName)
1398  PhSetReference(TypeName, typeName);
1399  if (ObjectName)
1400  PhSetReference(ObjectName, objectName);
1401  if (BestObjectName)
1402  PhSetReference(BestObjectName, bestObjectName);
1403  }
1404 
1405  if (dupHandle && ProcessHandle != NtCurrentProcess())
1406  NtClose(dupHandle);
1407 
1408  PhClearReference(&typeName);
1409  PhClearReference(&objectName);
1410  PhClearReference(&bestObjectName);
1411 
1412  return status;
1413 }
1414 
1416  _Out_ POBJECT_TYPES_INFORMATION *ObjectTypes
1417  )
1418 {
1419  NTSTATUS status;
1420  PVOID buffer;
1421  ULONG bufferSize;
1422 
1423  bufferSize = 0x1000;
1424  buffer = PhAllocate(bufferSize);
1425 
1426  while ((status = NtQueryObject(
1427  NULL,
1429  buffer,
1430  bufferSize,
1431  NULL
1432  )) == STATUS_INFO_LENGTH_MISMATCH)
1433  {
1434  PhFree(buffer);
1435  bufferSize *= 2;
1436 
1437  // Fail if we're resizing the buffer to something very large.
1438  if (bufferSize > PH_LARGE_BUFFER_SIZE)
1439  return STATUS_INSUFFICIENT_RESOURCES;
1440 
1441  buffer = PhAllocate(bufferSize);
1442  }
1443 
1444  if (!NT_SUCCESS(status))
1445  {
1446  PhFree(buffer);
1447  return status;
1448  }
1449 
1450  *ObjectTypes = (POBJECT_TYPES_INFORMATION)buffer;
1451 
1452  return status;
1453 }
1454 
1456  _In_ PUNICODE_STRING TypeName
1457  )
1458 {
1459  POBJECT_TYPES_INFORMATION objectTypes;
1460  POBJECT_TYPE_INFORMATION objectType;
1461  ULONG i;
1462 
1463  if (NT_SUCCESS(PhEnumObjectTypes(&objectTypes)))
1464  {
1465  objectType = PH_FIRST_OBJECT_TYPE(objectTypes);
1466 
1467  for (i = 0; i < objectTypes->NumberOfTypes; i++)
1468  {
1469  if (RtlEqualUnicodeString(&objectType->TypeName, TypeName, TRUE))
1470  {
1471  if (WindowsVersion >= WINDOWS_8_1)
1472  return objectType->TypeIndex;
1473  else if (WindowsVersion >= WINDOWS_7)
1474  return i + 2;
1475  else
1476  return i + 1;
1477  }
1478 
1479  objectType = PH_NEXT_OBJECT_TYPE(objectType);
1480  }
1481 
1482  PhFree(objectTypes);
1483  }
1484 
1485  return -1;
1486 }
1487 
1489  _In_opt_ PLARGE_INTEGER Timeout
1490  )
1491 {
1492  static PH_INITONCE initOnce = PH_INITONCE_INIT;
1493 
1495  PSLIST_ENTRY listEntry;
1496  PH_QUEUED_WAIT_BLOCK waitBlock;
1497 
1498  if (PhBeginInitOnce(&initOnce))
1499  {
1500  ULONG i;
1501 
1502  for (i = 0; i < PH_QUERY_HACK_MAX_THREADS; i++)
1503  {
1504  threadContext = PhAllocate(sizeof(PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT));
1505  memset(threadContext, 0, sizeof(PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT));
1506  RtlInterlockedPushEntrySList(&PhpCallWithTimeoutThreadListHead, &threadContext->ListEntry);
1507  }
1508 
1509  PhEndInitOnce(&initOnce);
1510  }
1511 
1512  while (TRUE)
1513  {
1514  if (listEntry = RtlInterlockedPopEntrySList(&PhpCallWithTimeoutThreadListHead))
1515  break;
1516 
1517  if (!Timeout || Timeout->QuadPart != 0)
1518  {
1519  PhQueueWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock);
1520 
1521  if (listEntry = RtlInterlockedPopEntrySList(&PhpCallWithTimeoutThreadListHead))
1522  {
1523  // A new entry has just become available; cancel the wait.
1524  PhSetWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock);
1525  break;
1526  }
1527  else
1528  {
1529  PhWaitForWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, &waitBlock, FALSE, Timeout);
1530  }
1531  }
1532  else
1533  {
1534  return NULL;
1535  }
1536  }
1537 
1538  return CONTAINING_RECORD(listEntry, PHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT, ListEntry);
1539 }
1540 
1542  _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext
1543  )
1544 {
1545  RtlInterlockedPushEntrySList(&PhpCallWithTimeoutThreadListHead, &ThreadContext->ListEntry);
1546  PhSetWakeEvent(&PhpCallWithTimeoutThreadReleaseEvent, NULL);
1547 }
1548 
1550  _Inout_ PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT ThreadContext,
1551  _In_ PUSER_THREAD_START_ROUTINE Routine,
1552  _In_opt_ PVOID Context,
1553  _In_ PLARGE_INTEGER Timeout
1554  )
1555 {
1556  NTSTATUS status;
1557 
1558  // Create objects if necessary.
1559 
1560  if (!ThreadContext->StartEventHandle)
1561  {
1562  if (!NT_SUCCESS(status = NtCreateEvent(&ThreadContext->StartEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)))
1563  return status;
1564  }
1565 
1566  if (!ThreadContext->CompletedEventHandle)
1567  {
1568  if (!NT_SUCCESS(status = NtCreateEvent(&ThreadContext->CompletedEventHandle, EVENT_ALL_ACCESS, NULL, SynchronizationEvent, FALSE)))
1569  return status;
1570  }
1571 
1572  // Create a query thread if we don't have one.
1573  if (!ThreadContext->ThreadHandle)
1574  {
1575  CLIENT_ID clientId;
1576 
1577  NtClearEvent(ThreadContext->StartEventHandle);
1578  NtClearEvent(ThreadContext->CompletedEventHandle);
1579 
1580  if (!NT_SUCCESS(status = RtlCreateUserThread(
1581  NtCurrentProcess(),
1582  NULL,
1583  FALSE,
1584  0,
1585  0,
1586  32 * 1024,
1588  ThreadContext,
1589  &ThreadContext->ThreadHandle,
1590  &clientId)))
1591  {
1592  return status;
1593  }
1594 
1595  // Wait for the thread to initialize.
1596  NtWaitForSingleObject(ThreadContext->CompletedEventHandle, FALSE, NULL);
1597  }
1598 
1599  ThreadContext->Routine = Routine;
1600  ThreadContext->Context = Context;
1601 
1602  NtSetEvent(ThreadContext->StartEventHandle, NULL);
1603  status = NtWaitForSingleObject(ThreadContext->CompletedEventHandle, FALSE, Timeout);
1604 
1605  ThreadContext->Routine = NULL;
1606  MemoryBarrier();
1607  ThreadContext->Context = NULL;
1608 
1609  if (status != STATUS_WAIT_0)
1610  {
1611  // The operation timed out, or there was an error. Kill the thread.
1612  // On Vista and above, the thread stack is freed automatically.
1613  NtTerminateThread(ThreadContext->ThreadHandle, STATUS_UNSUCCESSFUL);
1614  status = NtWaitForSingleObject(ThreadContext->ThreadHandle, FALSE, NULL);
1615  NtClose(ThreadContext->ThreadHandle);
1616  ThreadContext->ThreadHandle = NULL;
1617 
1618  status = STATUS_UNSUCCESSFUL;
1619  }
1620 
1621  return status;
1622 }
1623 
1625  _In_ PVOID Parameter
1626  )
1627 {
1628  PPHP_CALL_WITH_TIMEOUT_THREAD_CONTEXT threadContext = Parameter;
1629 
1630  NtSetEvent(threadContext->CompletedEventHandle, NULL);
1631 
1632  while (TRUE)
1633  {
1634  if (NtWaitForSingleObject(threadContext->StartEventHandle, FALSE, NULL) != STATUS_WAIT_0)
1635  continue;
1636 
1637  if (threadContext->Routine)
1638  threadContext->Routine(threadContext->Context);
1639 
1640  NtSetEvent(threadContext->CompletedEventHandle, NULL);
1641  }
1642 
1643  return STATUS_SUCCESS;
1644 }
1645 
1647  _In_ PUSER_THREAD_START_ROUTINE Routine,
1648  _In_opt_ PVOID Context,
1649  _In_opt_ PLARGE_INTEGER AcquireTimeout,
1650  _In_ PLARGE_INTEGER CallTimeout
1651  )
1652 {
1653  NTSTATUS status;
1655 
1656  if (threadContext = PhpAcquireCallWithTimeoutThread(AcquireTimeout))
1657  {
1658  status = PhpCallWithTimeout(threadContext, Routine, Context, CallTimeout);
1659  PhpReleaseCallWithTimeoutThread(threadContext);
1660  }
1661  else
1662  {
1663  status = STATUS_UNSUCCESSFUL;
1664  }
1665 
1666  return status;
1667 }
1668 
1670  _In_ PVOID Parameter
1671  )
1672 {
1673  PPHP_QUERY_OBJECT_COMMON_CONTEXT context = Parameter;
1674 
1675  switch (context->Work)
1676  {
1677  case NtQueryObjectWork:
1678  context->Status = NtQueryObject(
1679  context->u.NtQueryObject.Handle,
1680  context->u.NtQueryObject.ObjectInformationClass,
1681  context->u.NtQueryObject.ObjectInformation,
1682  context->u.NtQueryObject.ObjectInformationLength,
1683  context->u.NtQueryObject.ReturnLength
1684  );
1685  break;
1687  context->Status = NtQuerySecurityObject(
1688  context->u.NtQuerySecurityObject.Handle,
1689  context->u.NtQuerySecurityObject.SecurityInformation,
1690  context->u.NtQuerySecurityObject.SecurityDescriptor,
1691  context->u.NtQuerySecurityObject.Length,
1692  context->u.NtQuerySecurityObject.LengthNeeded
1693  );
1694  break;
1696  context->Status = NtSetSecurityObject(
1697  context->u.NtSetSecurityObject.Handle,
1698  context->u.NtSetSecurityObject.SecurityInformation,
1699  context->u.NtSetSecurityObject.SecurityDescriptor
1700  );
1701  break;
1703  context->Status = KphDuplicateObject(
1704  context->u.KphDuplicateObject.SourceProcessHandle,
1705  context->u.KphDuplicateObject.SourceHandle,
1706  context->u.KphDuplicateObject.TargetProcessHandle,
1707  context->u.KphDuplicateObject.TargetHandle,
1708  context->u.KphDuplicateObject.DesiredAccess,
1709  context->u.KphDuplicateObject.HandleAttributes,
1710  context->u.KphDuplicateObject.Options
1711  );
1712  break;
1713  default:
1714  context->Status = STATUS_INVALID_PARAMETER;
1715  break;
1716  }
1717 
1718  return STATUS_SUCCESS;
1719 }
1720 
1723  )
1724 {
1725  NTSTATUS status;
1726  LARGE_INTEGER timeout;
1727 
1728  timeout.QuadPart = -1 * PH_TIMEOUT_SEC;
1729  status = PhCallWithTimeout(PhpCommonQueryObjectRoutine, Context, NULL, &timeout);
1730 
1731  if (NT_SUCCESS(status))
1732  status = Context->Status;
1733 
1734  PhFree(Context);
1735 
1736  return status;
1737 }
1738 
1740  _In_ HANDLE Handle,
1741  _In_ OBJECT_INFORMATION_CLASS ObjectInformationClass,
1742  _Out_writes_bytes_opt_(ObjectInformationLength) PVOID ObjectInformation,
1743  _In_ ULONG ObjectInformationLength,
1744  _Out_opt_ PULONG ReturnLength
1745  )
1746 {
1748 
1749  context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));
1750  context->Work = NtQueryObjectWork;
1751  context->Status = STATUS_UNSUCCESSFUL;
1752  context->u.NtQueryObject.Handle = Handle;
1753  context->u.NtQueryObject.ObjectInformationClass = ObjectInformationClass;
1754  context->u.NtQueryObject.ObjectInformation = ObjectInformation;
1755  context->u.NtQueryObject.ObjectInformationLength = ObjectInformationLength;
1756  context->u.NtQueryObject.ReturnLength = ReturnLength;
1757 
1758  return PhpCommonQueryObjectWithTimeout(context);
1759 }
1760 
1762  _In_ HANDLE Handle,
1763  _In_ SECURITY_INFORMATION SecurityInformation,
1764  _Out_writes_bytes_opt_(Length) PSECURITY_DESCRIPTOR SecurityDescriptor,
1765  _In_ ULONG Length,
1766  _Out_ PULONG LengthNeeded
1767  )
1768 {
1770 
1771  context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));
1772  context->Work = NtQuerySecurityObjectWork;
1773  context->Status = STATUS_UNSUCCESSFUL;
1774  context->u.NtQuerySecurityObject.Handle = Handle;
1775  context->u.NtQuerySecurityObject.SecurityInformation = SecurityInformation;
1776  context->u.NtQuerySecurityObject.SecurityDescriptor = SecurityDescriptor;
1777  context->u.NtQuerySecurityObject.Length = Length;
1778  context->u.NtQuerySecurityObject.LengthNeeded = LengthNeeded;
1779 
1780  return PhpCommonQueryObjectWithTimeout(context);
1781 }
1782 
1784  _In_ HANDLE Handle,
1785  _In_ SECURITY_INFORMATION SecurityInformation,
1786  _In_ PSECURITY_DESCRIPTOR SecurityDescriptor
1787  )
1788 {
1790 
1791  context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));
1792  context->Work = NtSetSecurityObjectWork;
1793  context->Status = STATUS_UNSUCCESSFUL;
1794  context->u.NtSetSecurityObject.Handle = Handle;
1795  context->u.NtSetSecurityObject.SecurityInformation = SecurityInformation;
1796  context->u.NtSetSecurityObject.SecurityDescriptor = SecurityDescriptor;
1797 
1798  return PhpCommonQueryObjectWithTimeout(context);
1799 }
1800 
1802  _In_ HANDLE SourceProcessHandle,
1803  _In_ HANDLE SourceHandle,
1804  _In_opt_ HANDLE TargetProcessHandle,
1805  _Out_opt_ PHANDLE TargetHandle,
1806  _In_ ACCESS_MASK DesiredAccess,
1807  _In_ ULONG HandleAttributes,
1808  _In_ ULONG Options
1809  )
1810 {
1812 
1813  context = PhAllocate(sizeof(PHP_QUERY_OBJECT_COMMON_CONTEXT));
1814  context->Work = KphDuplicateObjectWork;
1815  context->Status = STATUS_UNSUCCESSFUL;
1816  context->u.KphDuplicateObject.SourceProcessHandle = SourceProcessHandle;
1817  context->u.KphDuplicateObject.SourceHandle = SourceHandle;
1818  context->u.KphDuplicateObject.TargetProcessHandle = TargetProcessHandle;
1819  context->u.KphDuplicateObject.TargetHandle = TargetHandle;
1820  context->u.KphDuplicateObject.DesiredAccess = DesiredAccess;
1821  context->u.KphDuplicateObject.HandleAttributes = HandleAttributes;
1822  context->u.KphDuplicateObject.Options = Options;
1823 
1824  return PhpCommonQueryObjectWithTimeout(context);
1825 }