Process Hacker
native.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * native wrapper and support functions
4  *
5  * Copyright (C) 2009-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 #include <apiimport.h>
26 
27 #define PH_DEVICE_PREFIX_LENGTH 64
28 #define PH_DEVICE_MUP_PREFIX_MAX_COUNT 16
29 
30 typedef BOOLEAN (NTAPI *PPHP_ENUM_PROCESS_MODULES_CALLBACK)(
31  _In_ HANDLE ProcessHandle,
32  _In_ PLDR_DATA_TABLE_ENTRY Entry,
33  _In_ PVOID AddressOfEntry,
34  _In_opt_ PVOID Context1,
35  _In_opt_ PVOID Context2
36  );
37 
38 typedef BOOLEAN (NTAPI *PPHP_ENUM_PROCESS_MODULES32_CALLBACK)(
39  _In_ HANDLE ProcessHandle,
40  _In_ PLDR_DATA_TABLE_ENTRY32 Entry,
41  _In_ ULONG AddressOfEntry,
42  _In_opt_ PVOID Context1,
43  _In_opt_ PVOID Context2
44  );
45 
46 static PH_INITONCE PhDevicePrefixesInitOnce = PH_INITONCE_INIT;
47 
48 static UNICODE_STRING PhDevicePrefixes[26];
49 static PH_QUEUED_LOCK PhDevicePrefixesLock = PH_QUEUED_LOCK_INIT;
50 
51 static PPH_STRING PhDeviceMupPrefixes[PH_DEVICE_MUP_PREFIX_MAX_COUNT] = { 0 };
52 static ULONG PhDeviceMupPrefixesCount = 0;
53 static PH_QUEUED_LOCK PhDeviceMupPrefixesLock = PH_QUEUED_LOCK_INIT;
54 
55 static PH_INITONCE PhPredefineKeyInitOnce = PH_INITONCE_INIT;
56 static UNICODE_STRING PhPredefineKeyNames[PH_KEY_MAXIMUM_PREDEFINE] =
57 {
58  RTL_CONSTANT_STRING(L"\\Registry\\Machine"),
59  RTL_CONSTANT_STRING(L"\\Registry\\User"),
60  RTL_CONSTANT_STRING(L"\\Registry\\Machine\\Software\\Classes"),
61  { 0, 0, NULL }
62 };
63 static HANDLE PhPredefineKeyHandles[PH_KEY_MAXIMUM_PREDEFINE] = { 0 };
64 
72 NTSTATUS PhOpenProcess(
73  _Out_ PHANDLE ProcessHandle,
74  _In_ ACCESS_MASK DesiredAccess,
75  _In_ HANDLE ProcessId
76  )
77 {
78  OBJECT_ATTRIBUTES objectAttributes;
79  CLIENT_ID clientId;
80 
81  clientId.UniqueProcess = ProcessId;
82  clientId.UniqueThread = NULL;
83 
84  if (KphIsConnected())
85  {
86  return KphOpenProcess(
87  ProcessHandle,
88  DesiredAccess,
89  &clientId
90  );
91  }
92  else
93  {
94  InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);
95 
96  return NtOpenProcess(
97  ProcessHandle,
98  DesiredAccess,
99  &objectAttributes,
100  &clientId
101  );
102  }
103 }
104 
112 NTSTATUS PhOpenThread(
113  _Out_ PHANDLE ThreadHandle,
114  _In_ ACCESS_MASK DesiredAccess,
115  _In_ HANDLE ThreadId
116  )
117 {
118  OBJECT_ATTRIBUTES objectAttributes;
119  CLIENT_ID clientId;
120 
121  clientId.UniqueProcess = NULL;
122  clientId.UniqueThread = ThreadId;
123 
124  if (KphIsConnected())
125  {
126  return KphOpenThread(
127  ThreadHandle,
128  DesiredAccess,
129  &clientId
130  );
131  }
132  else
133  {
134  InitializeObjectAttributes(&objectAttributes, NULL, 0, NULL, NULL);
135 
136  return NtOpenThread(
137  ThreadHandle,
138  DesiredAccess,
139  &objectAttributes,
140  &clientId
141  );
142  }
143 }
144 
146  _Out_ PHANDLE ProcessHandle,
147  _In_ ACCESS_MASK DesiredAccess,
148  _In_ HANDLE ThreadHandle
149  )
150 {
151  if (KphIsConnected())
152  {
153  return KphOpenThreadProcess(
154  ThreadHandle,
155  DesiredAccess,
156  ProcessHandle
157  );
158  }
159  else
160  {
161  NTSTATUS status;
162  THREAD_BASIC_INFORMATION basicInfo;
163 
165  ThreadHandle,
166  &basicInfo
167  )))
168  return status;
169 
170  return PhOpenProcess(
171  ProcessHandle,
172  DesiredAccess,
173  basicInfo.ClientId.UniqueProcess
174  );
175  }
176 }
177 
186  _Out_ PHANDLE TokenHandle,
187  _In_ ACCESS_MASK DesiredAccess,
188  _In_ HANDLE ProcessHandle
189  )
190 {
191  if (KphIsConnected())
192  {
193  return KphOpenProcessToken(
194  ProcessHandle,
195  DesiredAccess,
196  TokenHandle
197  );
198  }
199  else
200  {
201  return NtOpenProcessToken(
202  ProcessHandle,
203  DesiredAccess,
204  TokenHandle
205  );
206  }
207 }
208 
219  _Out_ PHANDLE TokenHandle,
220  _In_ ACCESS_MASK DesiredAccess,
221  _In_ HANDLE ThreadHandle,
222  _In_ BOOLEAN OpenAsSelf
223  )
224 {
225  return NtOpenThreadToken(
226  ThreadHandle,
227  DesiredAccess,
228  OpenAsSelf,
229  TokenHandle
230  );
231 }
232 
234  _In_ HANDLE Handle,
235  _In_ SECURITY_INFORMATION SecurityInformation,
236  _Out_ PSECURITY_DESCRIPTOR *SecurityDescriptor
237  )
238 {
239  NTSTATUS status;
240  ULONG bufferSize;
241  PVOID buffer;
242 
243  bufferSize = 0x100;
244  buffer = PhAllocate(bufferSize);
245  // This is required (especially for File objects) because some drivers don't seem to handle QuerySecurity properly.
246  memset(buffer, 0, bufferSize);
247 
248  status = NtQuerySecurityObject(
249  Handle,
250  SecurityInformation,
251  buffer,
252  bufferSize,
253  &bufferSize
254  );
255 
256  if (status == STATUS_BUFFER_TOO_SMALL)
257  {
258  PhFree(buffer);
259  buffer = PhAllocate(bufferSize);
260  memset(buffer, 0, bufferSize);
261 
262  status = NtQuerySecurityObject(
263  Handle,
264  SecurityInformation,
265  buffer,
266  bufferSize,
267  &bufferSize
268  );
269  }
270 
271  if (!NT_SUCCESS(status))
272  {
273  PhFree(buffer);
274  return status;
275  }
276 
277  *SecurityDescriptor = (PSECURITY_DESCRIPTOR)buffer;
278 
279  return status;
280 }
281 
283  _In_ HANDLE Handle,
284  _In_ SECURITY_INFORMATION SecurityInformation,
285  _In_ PSECURITY_DESCRIPTOR SecurityDescriptor
286  )
287 {
288  return NtSetSecurityObject(
289  Handle,
290  SecurityInformation,
291  SecurityDescriptor
292  );
293 }
294 
304  _In_ HANDLE ProcessHandle,
305  _In_ NTSTATUS ExitStatus
306  )
307 {
308  NTSTATUS status;
309 
310  if (KphIsConnected())
311  {
312  status = KphTerminateProcess(
313  ProcessHandle,
314  ExitStatus
315  );
316 
317  if (status != STATUS_NOT_SUPPORTED)
318  return status;
319  }
320 
321  return NtTerminateProcess(
322  ProcessHandle,
323  ExitStatus
324  );
325 }
326 
334  _In_ HANDLE ProcessHandle
335  )
336 {
338  {
339  return KphSuspendProcess(ProcessHandle);
340  }
341  else
342  {
343  return NtSuspendProcess(ProcessHandle);
344  }
345 }
346 
354  _In_ HANDLE ProcessHandle
355  )
356 {
358  {
359  return KphResumeProcess(ProcessHandle);
360  }
361  else
362  {
363  return NtResumeProcess(ProcessHandle);
364  }
365 }
366 
376  _In_ HANDLE ThreadHandle,
377  _In_ NTSTATUS ExitStatus
378  )
379 {
380 #ifndef _WIN64
381  NTSTATUS status;
382 
383  if (KphIsConnected())
384  {
385  status = KphTerminateThread(
386  ThreadHandle,
387  ExitStatus
388  );
389 
390  if (status != STATUS_NOT_SUPPORTED)
391  return status;
392  }
393 #endif
394 
395  return NtTerminateThread(
396  ThreadHandle,
397  ExitStatus
398  );
399 }
400 
410  _In_ HANDLE ThreadHandle,
411  _Out_opt_ PULONG PreviousSuspendCount
412  )
413 {
414  return NtSuspendThread(ThreadHandle, PreviousSuspendCount);
415 }
416 
425 NTSTATUS PhResumeThread(
426  _In_ HANDLE ThreadHandle,
427  _Out_opt_ PULONG PreviousSuspendCount
428  )
429 {
430  return NtResumeThread(ThreadHandle, PreviousSuspendCount);
431 }
432 
442  _In_ HANDLE ThreadHandle,
443  _Inout_ PCONTEXT Context
444  )
445 {
446  if (KphIsConnected())
447  {
448  return KphGetContextThread(ThreadHandle, Context);
449  }
450  else
451  {
452  return NtGetContextThread(ThreadHandle, Context);
453  }
454 }
455 
464  _In_ HANDLE ThreadHandle,
465  _In_ PCONTEXT Context
466  )
467 {
468  if (KphIsConnected())
469  {
470  return KphSetContextThread(ThreadHandle, Context);
471  }
472  else
473  {
474  return NtSetContextThread(ThreadHandle, Context);
475  }
476 }
477 
490  _In_ HANDLE ProcessHandle,
491  _In_ PVOID BaseAddress,
492  _Out_writes_bytes_(BufferSize) PVOID Buffer,
493  _In_ SIZE_T BufferSize,
494  _Out_opt_ PSIZE_T NumberOfBytesRead
495  )
496 {
497  NTSTATUS status;
498 
499  // KphReadVirtualMemory is much slower than
500  // NtReadVirtualMemory, so we'll stick to
501  // the using the original system call whenever possible.
502 
503  status = NtReadVirtualMemory(
504  ProcessHandle,
505  BaseAddress,
506  Buffer,
507  BufferSize,
508  NumberOfBytesRead
509  );
510 
511  if (status == STATUS_ACCESS_DENIED && KphIsConnected())
512  {
513  status = KphReadVirtualMemory(
514  ProcessHandle,
515  BaseAddress,
516  Buffer,
517  BufferSize,
518  NumberOfBytesRead
519  );
520  }
521 
522  return status;
523 }
524 
537  _In_ HANDLE ProcessHandle,
538  _In_ PVOID BaseAddress,
539  _In_reads_bytes_(BufferSize) PVOID Buffer,
540  _In_ SIZE_T BufferSize,
541  _Out_opt_ PSIZE_T NumberOfBytesWritten
542  )
543 {
544  NTSTATUS status;
545 
546  status = NtWriteVirtualMemory(
547  ProcessHandle,
548  BaseAddress,
549  Buffer,
550  BufferSize,
551  NumberOfBytesWritten
552  );
553 
554  if (status == STATUS_ACCESS_DENIED && KphIsConnected())
555  {
556  status = KphWriteVirtualMemory(
557  ProcessHandle,
558  BaseAddress,
559  Buffer,
560  BufferSize,
561  NumberOfBytesWritten
562  );
563  }
564 
565  return status;
566 }
567 
580  _In_ HANDLE ProcessHandle,
581  _In_ PROCESSINFOCLASS ProcessInformationClass,
582  _Out_ PVOID *Buffer
583  )
584 {
585  NTSTATUS status;
586  PVOID buffer;
587  ULONG returnLength = 0;
588 
589  status = NtQueryInformationProcess(
590  ProcessHandle,
591  ProcessInformationClass,
592  NULL,
593  0,
594  &returnLength
595  );
596 
597  if (status != STATUS_BUFFER_OVERFLOW && status != STATUS_BUFFER_TOO_SMALL && status != STATUS_INFO_LENGTH_MISMATCH)
598  return status;
599 
600  buffer = PhAllocate(returnLength);
601  status = NtQueryInformationProcess(
602  ProcessHandle,
603  ProcessInformationClass,
604  buffer,
605  returnLength,
606  &returnLength
607  );
608 
609  if (NT_SUCCESS(status))
610  {
611  *Buffer = buffer;
612  }
613  else
614  {
615  PhFree(buffer);
616  }
617 
618  return status;
619 }
620 
631  _In_ HANDLE ProcessHandle,
632  _Out_ PPH_STRING *FileName
633  )
634 {
635  NTSTATUS status;
636  PUNICODE_STRING fileName;
637 
639  ProcessHandle,
640  ProcessImageFileName,
641  &fileName
642  );
643 
644  if (!NT_SUCCESS(status))
645  return status;
646 
647  *FileName = PhCreateStringFromUnicodeString(fileName);
648  PhFree(fileName);
649 
650  return status;
651 }
652 
666  _In_ HANDLE ProcessHandle,
667  _Out_ PPH_STRING *FileName
668  )
669 {
670  NTSTATUS status;
671  PUNICODE_STRING fileName;
672 
674  ProcessHandle,
675  ProcessImageFileNameWin32,
676  &fileName
677  );
678 
679  if (!NT_SUCCESS(status))
680  return status;
681 
682  *FileName = PhCreateStringFromUnicodeString(fileName);
683  PhFree(fileName);
684 
685  return status;
686 }
687 
703  _In_ HANDLE ProcessHandle,
704  _In_ PH_PEB_OFFSET Offset,
705  _Out_ PPH_STRING *String
706  )
707 {
708  NTSTATUS status;
709  PPH_STRING string;
710  ULONG offset;
711 
712 #define PEB_OFFSET_CASE(Enum, Field) \
713  case Enum: offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Field); break; \
714  case Enum | PhpoWow64: offset = FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, Field); break
715 
716  switch (Offset)
717  {
718  PEB_OFFSET_CASE(PhpoCurrentDirectory, CurrentDirectory);
719  PEB_OFFSET_CASE(PhpoDllPath, DllPath);
720  PEB_OFFSET_CASE(PhpoImagePathName, ImagePathName);
721  PEB_OFFSET_CASE(PhpoCommandLine, CommandLine);
722  PEB_OFFSET_CASE(PhpoWindowTitle, WindowTitle);
723  PEB_OFFSET_CASE(PhpoDesktopInfo, DesktopInfo);
724  PEB_OFFSET_CASE(PhpoShellInfo, ShellInfo);
725  PEB_OFFSET_CASE(PhpoRuntimeData, RuntimeData);
726  default:
727  return STATUS_INVALID_PARAMETER_2;
728  }
729 
730  if (!(Offset & PhpoWow64))
731  {
732  PROCESS_BASIC_INFORMATION basicInfo;
733  PVOID processParameters;
734  UNICODE_STRING unicodeString;
735 
736  // Get the PEB address.
737  if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo)))
738  return status;
739 
740  // Read the address of the process parameters.
741  if (!NT_SUCCESS(status = PhReadVirtualMemory(
742  ProcessHandle,
743  PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)),
744  &processParameters,
745  sizeof(PVOID),
746  NULL
747  )))
748  return status;
749 
750  // Read the string structure.
751  if (!NT_SUCCESS(status = PhReadVirtualMemory(
752  ProcessHandle,
753  PTR_ADD_OFFSET(processParameters, offset),
754  &unicodeString,
755  sizeof(UNICODE_STRING),
756  NULL
757  )))
758  return status;
759 
760  string = PhCreateStringEx(NULL, unicodeString.Length);
761 
762  // Read the string contents.
763  if (!NT_SUCCESS(status = PhReadVirtualMemory(
764  ProcessHandle,
765  unicodeString.Buffer,
766  string->Buffer,
767  string->Length,
768  NULL
769  )))
770  {
771  PhDereferenceObject(string);
772  return status;
773  }
774  }
775  else
776  {
777  PVOID peb32;
778  ULONG processParameters32;
779  UNICODE_STRING32 unicodeString32;
780 
781  if (!NT_SUCCESS(status = PhGetProcessPeb32(ProcessHandle, &peb32)))
782  return status;
783 
784  if (!NT_SUCCESS(status = PhReadVirtualMemory(
785  ProcessHandle,
786  PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)),
787  &processParameters32,
788  sizeof(ULONG),
789  NULL
790  )))
791  return status;
792 
793  if (!NT_SUCCESS(status = PhReadVirtualMemory(
794  ProcessHandle,
795  PTR_ADD_OFFSET(processParameters32, offset),
796  &unicodeString32,
797  sizeof(UNICODE_STRING32),
798  NULL
799  )))
800  return status;
801 
802  string = PhCreateStringEx(NULL, unicodeString32.Length);
803 
804  // Read the string contents.
805  if (!NT_SUCCESS(status = PhReadVirtualMemory(
806  ProcessHandle,
807  UlongToPtr(unicodeString32.Buffer),
808  string->Buffer,
809  string->Length,
810  NULL
811  )))
812  {
813  PhDereferenceObject(string);
814  return status;
815  }
816  }
817 
818  *String = string;
819 
820  return status;
821 }
822 
834  _In_ HANDLE ProcessHandle,
835  _Out_ PPH_STRING *CommandLine
836  )
837 {
838  NTSTATUS status;
839 
841  {
842  PUNICODE_STRING commandLine;
843 
845  ProcessHandle,
846  ProcessCommandLineInformation,
847  &commandLine
848  );
849 
850  if (NT_SUCCESS(status))
851  {
852  *CommandLine = PhCreateStringFromUnicodeString(commandLine);
853  PhFree(commandLine);
854 
855  return status;
856  }
857  }
858 
859  return PhGetProcessPebString(ProcessHandle, PhpoCommandLine, CommandLine);
860 }
861 
875  _In_ HANDLE ProcessHandle,
876  _Out_ PULONG WindowFlags,
877  _Out_ PPH_STRING *WindowTitle
878  )
879 {
880  NTSTATUS status;
881 #ifdef _WIN64
882  BOOLEAN isWow64 = FALSE;
883 #endif
884  ULONG windowFlags;
885 
886  if (WindowsVersion >= WINDOWS_7)
887  {
888  PPROCESS_WINDOW_INFORMATION windowInfo;
889 
891  ProcessHandle,
892  ProcessWindowInformation,
893  &windowInfo
894  );
895 
896  if (NT_SUCCESS(status))
897  {
898  *WindowFlags = windowInfo->WindowFlags;
899  *WindowTitle = PhCreateStringEx(windowInfo->WindowTitle, windowInfo->WindowTitleLength);
900  PhFree(windowInfo);
901 
902  return status;
903  }
904  }
905 
906 #ifdef _WIN64
907  PhGetProcessIsWow64(ProcessHandle, &isWow64);
908 
909  if (!isWow64)
910 #endif
911  {
912  PROCESS_BASIC_INFORMATION basicInfo;
913  PVOID processParameters;
914 
915  // Get the PEB address.
916  if (!NT_SUCCESS(status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo)))
917  return status;
918 
919  // Read the address of the process parameters.
920  if (!NT_SUCCESS(status = PhReadVirtualMemory(
921  ProcessHandle,
922  PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)),
923  &processParameters,
924  sizeof(PVOID),
925  NULL
926  )))
927  return status;
928 
929  // Read the window flags.
930  if (!NT_SUCCESS(status = PhReadVirtualMemory(
931  ProcessHandle,
932  PTR_ADD_OFFSET(processParameters, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, WindowFlags)),
933  &windowFlags,
934  sizeof(ULONG),
935  NULL
936  )))
937  return status;
938  }
939 #ifdef _WIN64
940  else
941  {
942  PVOID peb32;
943  ULONG processParameters32;
944 
945  if (!NT_SUCCESS(status = PhGetProcessPeb32(ProcessHandle, &peb32)))
946  return status;
947 
948  if (!NT_SUCCESS(status = PhReadVirtualMemory(
949  ProcessHandle,
950  PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)),
951  &processParameters32,
952  sizeof(ULONG),
953  NULL
954  )))
955  return status;
956 
957  if (!NT_SUCCESS(status = PhReadVirtualMemory(
958  ProcessHandle,
959  PTR_ADD_OFFSET(processParameters32, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, WindowFlags)),
960  &windowFlags,
961  sizeof(ULONG),
962  NULL
963  )))
964  return status;
965  }
966 #endif
967 
968 #ifdef _WIN64
969  status = PhGetProcessPebString(ProcessHandle, PhpoWindowTitle | (isWow64 ? PhpoWow64 : 0), WindowTitle);
970 #else
971  status = PhGetProcessPebString(ProcessHandle, PhpoWindowTitle, WindowTitle);
972 #endif
973 
974  if (NT_SUCCESS(status))
975  *WindowFlags = windowFlags;
976 
977  return status;
978 }
979 
992  _In_ HANDLE ProcessHandle,
993  _Out_ PBOOLEAN IsPosix
994  )
995 {
996  NTSTATUS status;
997  PROCESS_BASIC_INFORMATION basicInfo;
998  ULONG imageSubsystem;
999 
1000  status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo);
1001 
1002  if (!NT_SUCCESS(status))
1003  return status;
1004 
1005  // No PEB for processes like System.
1006  if (!basicInfo.PebBaseAddress)
1007  return STATUS_UNSUCCESSFUL;
1008 
1009  status = PhReadVirtualMemory(
1010  ProcessHandle,
1011  PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ImageSubsystem)),
1012  &imageSubsystem,
1013  sizeof(ULONG),
1014  NULL
1015  );
1016 
1017  if (NT_SUCCESS(status))
1018  {
1019  *IsPosix = imageSubsystem == IMAGE_SUBSYSTEM_POSIX_CUI;
1020  }
1021 
1022  return status;
1023 }
1024 
1034  _In_ HANDLE ProcessHandle,
1035  _Out_ PULONG ExecuteFlags
1036  )
1037 {
1038  if (KphIsConnected())
1039  {
1041  ProcessHandle,
1043  ExecuteFlags,
1044  sizeof(ULONG),
1045  NULL
1046  );
1047  }
1048  else
1049  {
1050  return NtQueryInformationProcess(
1051  ProcessHandle,
1052  ProcessExecuteFlags,
1053  ExecuteFlags,
1054  sizeof(ULONG),
1055  NULL
1056  );
1057  }
1058 }
1059 
1061  _In_ HANDLE ProcessHandle,
1062  _Out_ PULONG DepStatus
1063  )
1064 {
1065  NTSTATUS status;
1066  ULONG executeFlags;
1067  ULONG depStatus;
1068 
1069  if (!NT_SUCCESS(status = PhGetProcessExecuteFlags(
1070  ProcessHandle,
1071  &executeFlags
1072  )))
1073  return status;
1074 
1075  // Check if execution of data pages is enabled.
1076  if (executeFlags & MEM_EXECUTE_OPTION_ENABLE)
1077  depStatus = 0;
1078  else
1079  depStatus = PH_PROCESS_DEP_ENABLED;
1080 
1081  if (executeFlags & MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION)
1083  if (executeFlags & MEM_EXECUTE_OPTION_PERMANENT)
1084  depStatus |= PH_PROCESS_DEP_PERMANENT;
1085 
1086  *DepStatus = depStatus;
1087 
1088  return status;
1089 }
1090 
1110  _In_ HANDLE ProcessHandle,
1111  _Out_ PPH_STRING *CommandLine
1112  )
1113 {
1114  NTSTATUS status;
1115  PROCESS_BASIC_INFORMATION basicInfo;
1116  PVOID processParameters;
1117  UNICODE_STRING commandLine;
1118 
1119  status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo);
1120 
1121  if (!NT_SUCCESS(status))
1122  return status;
1123 
1124  if (!NT_SUCCESS(status = PhReadVirtualMemory(
1125  ProcessHandle,
1126  PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)),
1127  &processParameters,
1128  sizeof(PVOID),
1129  NULL
1130  )))
1131  return status;
1132 
1133  if (!NT_SUCCESS(status = PhReadVirtualMemory(
1134  ProcessHandle,
1135  PTR_ADD_OFFSET(processParameters, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, CommandLine)),
1136  &commandLine,
1137  sizeof(UNICODE_STRING),
1138  NULL
1139  )))
1140  return status;
1141 
1142  // See ProcessHandle.cs from PH 1.x for how POSIX command lines work.
1143  {
1144  PVOID pointer = NULL;
1145  PVOID firstPointer = NULL;
1146  PVOID lastPointer = NULL;
1147  BOOLEAN zeroReached = FALSE;
1148  ULONG i;
1149  ULONG commandLineChunkSize;
1150  PCHAR commandLineChunk;
1151 
1152  i = 0;
1153 
1154  // Read the first command line pointer + the first environment pointer.
1155 
1156  while (i < sizeof(PVOID) * 100) // reasonable limit
1157  {
1159  ProcessHandle,
1160  PTR_ADD_OFFSET(commandLine.Buffer, i),
1161  &pointer,
1162  sizeof(PVOID),
1163  NULL
1164  );
1165 
1166  if (pointer && !firstPointer)
1167  firstPointer = pointer;
1168  if (zeroReached)
1169  lastPointer = pointer;
1170 
1171  i += sizeof(PVOID);
1172 
1173  if (zeroReached)
1174  break;
1175  else if (!pointer)
1176  zeroReached = TRUE;
1177 
1178  pointer = NULL;
1179  }
1180 
1181  commandLineChunkSize = (ULONG)((PBYTE)lastPointer - (PBYTE)firstPointer);
1182 
1183  // Set a limit on how much we're going to read.
1184  if (commandLineChunkSize > 0x1000)
1185  return STATUS_UNSUCCESSFUL;
1186 
1187  commandLineChunk = PhAllocate(commandLineChunkSize);
1188 
1189  // Read the chunk.
1190  if (!NT_SUCCESS(status = PhReadVirtualMemory(
1191  ProcessHandle,
1192  firstPointer,
1193  commandLineChunk,
1194  commandLineChunkSize,
1195  NULL
1196  )))
1197  {
1198  PhFree(commandLineChunk);
1199  return status;
1200  }
1201 
1202  // Replace the nulls in the chunk with spaces.
1203  for (i = 0; i < commandLineChunkSize; i++)
1204  {
1205  if (commandLineChunk[i] == 0)
1206  {
1207  commandLineChunk[i] = ' ';
1208 
1209  // Trim the last null/space.
1210  if (i == commandLineChunkSize - 1)
1211  {
1212  commandLineChunkSize--;
1213  break;
1214  }
1215  }
1216  }
1217 
1218  *CommandLine = PhZeroExtendToUtf16Ex(commandLineChunk, commandLineChunkSize);
1219  PhFree(commandLineChunk);
1220 
1221  return status;
1222  }
1223 }
1224 
1241  _In_ HANDLE ProcessHandle,
1242  _In_ ULONG Flags,
1243  _Out_ PVOID *Environment,
1244  _Out_ PULONG EnvironmentLength
1245  )
1246 {
1247  NTSTATUS status;
1248  PVOID environmentRemote;
1249  MEMORY_BASIC_INFORMATION mbi;
1250  PVOID environment;
1251  ULONG environmentLength;
1252 
1253  if (!(Flags & PH_GET_PROCESS_ENVIRONMENT_WOW64))
1254  {
1255  PROCESS_BASIC_INFORMATION basicInfo;
1256  PVOID processParameters;
1257 
1258  status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo);
1259 
1260  if (!NT_SUCCESS(status))
1261  return status;
1262 
1263  if (!NT_SUCCESS(status = PhReadVirtualMemory(
1264  ProcessHandle,
1265  PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, ProcessParameters)),
1266  &processParameters,
1267  sizeof(PVOID),
1268  NULL
1269  )))
1270  return status;
1271 
1272  if (!NT_SUCCESS(status = PhReadVirtualMemory(
1273  ProcessHandle,
1274  PTR_ADD_OFFSET(processParameters, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS, Environment)),
1275  &environmentRemote,
1276  sizeof(PVOID),
1277  NULL
1278  )))
1279  return status;
1280  }
1281  else
1282  {
1283  PVOID peb32;
1284  ULONG processParameters32;
1285  ULONG environmentRemote32;
1286 
1287  status = PhGetProcessPeb32(ProcessHandle, &peb32);
1288 
1289  if (!NT_SUCCESS(status))
1290  return status;
1291 
1292  if (!NT_SUCCESS(status = PhReadVirtualMemory(
1293  ProcessHandle,
1294  PTR_ADD_OFFSET(peb32, FIELD_OFFSET(PEB32, ProcessParameters)),
1295  &processParameters32,
1296  sizeof(ULONG),
1297  NULL
1298  )))
1299  return status;
1300 
1301  if (!NT_SUCCESS(status = PhReadVirtualMemory(
1302  ProcessHandle,
1303  PTR_ADD_OFFSET(processParameters32, FIELD_OFFSET(RTL_USER_PROCESS_PARAMETERS32, Environment)),
1304  &environmentRemote32,
1305  sizeof(ULONG),
1306  NULL
1307  )))
1308  return status;
1309 
1310  environmentRemote = UlongToPtr(environmentRemote32);
1311  }
1312 
1313  if (!NT_SUCCESS(status = NtQueryVirtualMemory(
1314  ProcessHandle,
1315  environmentRemote,
1317  &mbi,
1318  sizeof(MEMORY_BASIC_INFORMATION),
1319  NULL
1320  )))
1321  return status;
1322 
1323  environmentLength = (ULONG)(mbi.RegionSize -
1324  ((ULONG_PTR)environmentRemote - (ULONG_PTR)mbi.BaseAddress));
1325 
1326  // Read in the entire region of memory.
1327 
1328  environment = PhAllocatePage(environmentLength, NULL);
1329 
1330  if (!environment)
1331  return STATUS_NO_MEMORY;
1332 
1333  if (!NT_SUCCESS(status = PhReadVirtualMemory(
1334  ProcessHandle,
1335  environmentRemote,
1336  environment,
1337  environmentLength,
1338  NULL
1339  )))
1340  {
1341  PhFreePage(environment);
1342  return status;
1343  }
1344 
1345  *Environment = environment;
1346 
1347  if (EnvironmentLength)
1348  *EnvironmentLength = environmentLength;
1349 
1350  return status;
1351 }
1352 
1354  _In_ PVOID Environment,
1355  _In_ ULONG EnvironmentLength,
1356  _Inout_ PULONG EnumerationKey,
1357  _Out_ PPH_ENVIRONMENT_VARIABLE Variable
1358  )
1359 {
1360  ULONG length;
1361  ULONG startIndex;
1362  PWCHAR name;
1363  ULONG nameLength;
1364  PWCHAR value;
1365  ULONG valueLength;
1366  PWCHAR currentChar;
1367  ULONG currentIndex;
1368 
1369  length = EnvironmentLength / sizeof(WCHAR);
1370 
1371  currentIndex = *EnumerationKey;
1372  currentChar = (PWCHAR)Environment + currentIndex;
1373  startIndex = currentIndex;
1374  name = currentChar;
1375 
1376  // Find the end of the name.
1377  while (TRUE)
1378  {
1379  if (currentIndex >= length)
1380  return FALSE;
1381  if (*currentChar == '=')
1382  break;
1383  if (*currentChar == 0)
1384  return FALSE; // no more variables
1385 
1386  currentIndex++;
1387  currentChar++;
1388  }
1389 
1390  nameLength = currentIndex - startIndex;
1391 
1392  currentIndex++;
1393  currentChar++;
1394  startIndex = currentIndex;
1395  value = currentChar;
1396 
1397  // Find the end of the value.
1398  while (TRUE)
1399  {
1400  if (currentIndex >= length)
1401  return FALSE;
1402  if (*currentChar == 0)
1403  break;
1404 
1405  currentIndex++;
1406  currentChar++;
1407  }
1408 
1409  valueLength = currentIndex - startIndex;
1410 
1411  currentIndex++;
1412  *EnumerationKey = currentIndex;
1413 
1414  Variable->Name.Buffer = name;
1415  Variable->Name.Length = nameLength * sizeof(WCHAR);
1416  Variable->Value.Buffer = value;
1417  Variable->Value.Length = valueLength * sizeof(WCHAR);
1418 
1419  return TRUE;
1420 }
1421 
1434  _In_ HANDLE ProcessHandle,
1435  _In_ PVOID BaseAddress,
1436  _Out_ PPH_STRING *FileName
1437  )
1438 {
1439  NTSTATUS status;
1440  PVOID buffer;
1441  SIZE_T bufferSize;
1442  SIZE_T returnLength;
1443  PUNICODE_STRING unicodeString;
1444 
1445  bufferSize = 0x100;
1446  buffer = PhAllocate(bufferSize);
1447 
1448  status = NtQueryVirtualMemory(
1449  ProcessHandle,
1450  BaseAddress,
1452  buffer,
1453  bufferSize,
1454  &returnLength
1455  );
1456 
1457  if (status == STATUS_BUFFER_OVERFLOW)
1458  {
1459  PhFree(buffer);
1460  bufferSize = returnLength;
1461  buffer = PhAllocate(bufferSize);
1462 
1463  status = NtQueryVirtualMemory(
1464  ProcessHandle,
1465  BaseAddress,
1467  buffer,
1468  bufferSize,
1469  &returnLength
1470  );
1471  }
1472 
1473  if (!NT_SUCCESS(status))
1474  {
1475  PhFree(buffer);
1476  return status;
1477  }
1478 
1479  unicodeString = (PUNICODE_STRING)buffer;
1480  *FileName = PhCreateStringEx(
1481  unicodeString->Buffer,
1482  unicodeString->Length
1483  );
1484  PhFree(buffer);
1485 
1486  return status;
1487 }
1488 
1499  _In_ HANDLE ProcessHandle,
1500  _Out_ PMEMORY_WORKING_SET_INFORMATION *WorkingSetInformation
1501  )
1502 {
1503  NTSTATUS status;
1504  PVOID buffer;
1505  SIZE_T bufferSize;
1506 
1507  bufferSize = 0x8000;
1508  buffer = PhAllocate(bufferSize);
1509 
1510  while ((status = NtQueryVirtualMemory(
1511  ProcessHandle,
1512  NULL,
1514  buffer,
1515  bufferSize,
1516  NULL
1517  )) == STATUS_INFO_LENGTH_MISMATCH)
1518  {
1519  PhFree(buffer);
1520  bufferSize *= 2;
1521 
1522  // Fail if we're resizing the buffer to something very large.
1523  if (bufferSize > PH_LARGE_BUFFER_SIZE)
1524  return STATUS_INSUFFICIENT_RESOURCES;
1525 
1526  buffer = PhAllocate(bufferSize);
1527  }
1528 
1529  if (!NT_SUCCESS(status))
1530  {
1531  PhFree(buffer);
1532  return status;
1533  }
1534 
1535  *WorkingSetInformation = (PMEMORY_WORKING_SET_INFORMATION)buffer;
1536 
1537  return status;
1538 }
1539 
1549  _In_ HANDLE ProcessHandle,
1550  _Out_ PPH_PROCESS_WS_COUNTERS WsCounters
1551  )
1552 {
1553  NTSTATUS status;
1555  PH_PROCESS_WS_COUNTERS wsCounters;
1556  ULONG_PTR i;
1557 
1559  ProcessHandle,
1560  &wsInfo
1561  )))
1562  return status;
1563 
1564  memset(&wsCounters, 0, sizeof(PH_PROCESS_WS_COUNTERS));
1565 
1566  for (i = 0; i < wsInfo->NumberOfEntries; i++)
1567  {
1568  wsCounters.NumberOfPages++;
1569 
1570  if (wsInfo->WorkingSetInfo[i].ShareCount > 1)
1571  wsCounters.NumberOfSharedPages++;
1572  if (wsInfo->WorkingSetInfo[i].ShareCount == 0)
1573  wsCounters.NumberOfPrivatePages++;
1574  if (wsInfo->WorkingSetInfo[i].Shared)
1575  wsCounters.NumberOfShareablePages++;
1576  }
1577 
1578  PhFree(wsInfo);
1579 
1580  *WsCounters = wsCounters;
1581 
1582  return status;
1583 }
1584 
1593  _In_ HANDLE ProcessHandle,
1594  _In_ ULONG IoPriority
1595  )
1596 {
1597  if (KphIsConnected())
1598  {
1599  return KphSetInformationProcess(
1600  ProcessHandle,
1602  &IoPriority,
1603  sizeof(ULONG)
1604  );
1605  }
1606  else
1607  {
1608  return NtSetInformationProcess(
1609  ProcessHandle,
1610  ProcessIoPriority,
1611  &IoPriority,
1612  sizeof(ULONG)
1613  );
1614  }
1615 }
1616 
1627  _In_ HANDLE ProcessHandle,
1628  _In_ ULONG ExecuteFlags
1629  )
1630 {
1631  return KphSetInformationProcess(
1632  ProcessHandle,
1634  &ExecuteFlags,
1635  sizeof(ULONG)
1636  );
1637 }
1638 
1640  _In_ HANDLE ProcessHandle,
1641  _In_ ULONG DepStatus
1642  )
1643 {
1644  ULONG executeFlags;
1645 
1646  if (DepStatus & PH_PROCESS_DEP_ENABLED)
1647  executeFlags = MEM_EXECUTE_OPTION_DISABLE;
1648  else
1649  executeFlags = MEM_EXECUTE_OPTION_ENABLE;
1650 
1653  if (DepStatus & PH_PROCESS_DEP_PERMANENT)
1654  executeFlags |= MEM_EXECUTE_OPTION_PERMANENT;
1655 
1656  return PhSetProcessExecuteFlags(ProcessHandle, executeFlags);
1657 }
1658 
1660  _In_ HANDLE ProcessHandle,
1661  _In_ ULONG DepStatus,
1662  _In_opt_ PLARGE_INTEGER Timeout
1663  )
1664 {
1665  NTSTATUS status;
1666  HANDLE threadHandle;
1667  PVOID setProcessDepPolicy;
1668  ULONG flags;
1669 
1670  setProcessDepPolicy = PhGetModuleProcAddress(L"kernel32.dll", "SetProcessDEPPolicy");
1671 
1672  if (!setProcessDepPolicy)
1673  return STATUS_NOT_SUPPORTED;
1674 
1675  flags = 0;
1676 
1677  if (DepStatus & PH_PROCESS_DEP_ENABLED)
1678  flags |= PROCESS_DEP_ENABLE;
1680  flags |= PROCESS_DEP_DISABLE_ATL_THUNK_EMULATION;
1681 
1683  {
1684  status = RtlCreateUserThread(
1685  ProcessHandle,
1686  NULL,
1687  FALSE,
1688  0,
1689  0,
1690  0,
1691  (PUSER_THREAD_START_ROUTINE)setProcessDepPolicy,
1692  (PVOID)flags,
1693  &threadHandle,
1694  NULL
1695  );
1696  }
1697  else
1698  {
1699  if (threadHandle = CreateRemoteThread(
1700  ProcessHandle,
1701  NULL,
1702  0,
1703  (PTHREAD_START_ROUTINE)setProcessDepPolicy,
1704  (PVOID)flags,
1705  0,
1706  NULL
1707  ))
1708  {
1709  status = STATUS_SUCCESS;
1710  }
1711  else
1712  {
1713  status = PhGetLastWin32ErrorAsNtStatus();
1714  }
1715  }
1716 
1717  if (!NT_SUCCESS(status))
1718  return status;
1719 
1720  // Wait for the thread to finish.
1721  status = NtWaitForSingleObject(threadHandle, FALSE, Timeout);
1722  NtClose(threadHandle);
1723 
1724  return status;
1725 }
1726 
1742  _In_ HANDLE ProcessHandle,
1743  _In_ PWSTR FileName,
1744  _In_opt_ PLARGE_INTEGER Timeout
1745  )
1746 {
1747 #ifdef _WIN64
1748  static PVOID loadLibraryW32 = NULL;
1749 #endif
1750 
1751  NTSTATUS status;
1752 #ifdef _WIN64
1753  BOOLEAN isWow64 = FALSE;
1754  BOOLEAN isModule32 = FALSE;
1755  PH_MAPPED_IMAGE mappedImage;
1756 #endif
1757  PVOID threadStart;
1758  PH_STRINGREF fileName;
1759  PVOID baseAddress = NULL;
1760  SIZE_T allocSize;
1761  HANDLE threadHandle;
1762 
1763 #ifdef _WIN64
1764  PhGetProcessIsWow64(ProcessHandle, &isWow64);
1765 
1766  if (isWow64)
1767  {
1768  if (!NT_SUCCESS(status = PhLoadMappedImage(FileName, NULL, TRUE, &mappedImage)))
1769  return status;
1770 
1771  isModule32 = mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC;
1772  PhUnloadMappedImage(&mappedImage);
1773  }
1774 
1775  if (!isModule32)
1776  {
1777 #endif
1778  threadStart = PhGetModuleProcAddress(L"kernel32.dll", "LoadLibraryW");
1779 #ifdef _WIN64
1780  }
1781  else
1782  {
1783  threadStart = loadLibraryW32;
1784 
1785  if (!threadStart)
1786  {
1787  PPH_STRING kernel32FileName;
1788 
1789  kernel32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\kernel32.dll");
1790  status = PhGetProcedureAddressRemote(
1791  ProcessHandle,
1792  kernel32FileName->Buffer,
1793  "LoadLibraryW",
1794  0,
1795  &loadLibraryW32,
1796  NULL
1797  );
1798  PhDereferenceObject(kernel32FileName);
1799 
1800  if (!NT_SUCCESS(status))
1801  return status;
1802 
1803  threadStart = loadLibraryW32;
1804  }
1805  }
1806 #endif
1807 
1808  PhInitializeStringRefLongHint(&fileName, FileName);
1809  allocSize = fileName.Length + sizeof(WCHAR);
1810 
1811  if (!NT_SUCCESS(status = NtAllocateVirtualMemory(
1812  ProcessHandle,
1813  &baseAddress,
1814  0,
1815  &allocSize,
1816  MEM_COMMIT,
1817  PAGE_READWRITE
1818  )))
1819  return status;
1820 
1821  if (!NT_SUCCESS(status = PhWriteVirtualMemory(
1822  ProcessHandle,
1823  baseAddress,
1824  fileName.Buffer,
1825  fileName.Length + sizeof(WCHAR),
1826  NULL
1827  )))
1828  goto FreeExit;
1829 
1830  // Vista seems to support native threads better than XP.
1832  {
1833  if (!NT_SUCCESS(status = RtlCreateUserThread(
1834  ProcessHandle,
1835  NULL,
1836  FALSE,
1837  0,
1838  0,
1839  0,
1840  (PUSER_THREAD_START_ROUTINE)threadStart,
1841  baseAddress,
1842  &threadHandle,
1843  NULL
1844  )))
1845  goto FreeExit;
1846  }
1847  else
1848  {
1849  if (!(threadHandle = CreateRemoteThread(
1850  ProcessHandle,
1851  NULL,
1852  0,
1853  (PTHREAD_START_ROUTINE)threadStart,
1854  baseAddress,
1855  0,
1856  NULL
1857  )))
1858  {
1859  status = PhGetLastWin32ErrorAsNtStatus();
1860  goto FreeExit;
1861  }
1862  }
1863 
1864  // Wait for the thread to finish.
1865  status = NtWaitForSingleObject(threadHandle, FALSE, Timeout);
1866  NtClose(threadHandle);
1867 
1868 FreeExit:
1869  // Size needs to be zero if we're freeing.
1870  allocSize = 0;
1872  ProcessHandle,
1873  &baseAddress,
1874  &allocSize,
1875  MEM_RELEASE
1876  );
1877 
1878  return status;
1879 }
1880 
1892  _In_ HANDLE ProcessHandle,
1893  _In_ PVOID BaseAddress,
1894  _In_opt_ PLARGE_INTEGER Timeout
1895  )
1896 {
1897 #ifdef _WIN64
1898  static PVOID ldrUnloadDll32 = NULL;
1899 #endif
1900 
1901  NTSTATUS status;
1902 #ifdef _WIN64
1903  BOOLEAN isWow64 = FALSE;
1904  BOOLEAN isModule32 = FALSE;
1905 #endif
1906  HANDLE threadHandle;
1907  THREAD_BASIC_INFORMATION basicInfo;
1908  PVOID threadStart;
1909 
1910 #ifdef _WIN64
1911  PhGetProcessIsWow64(ProcessHandle, &isWow64);
1912 #endif
1913 
1914  // No point trying to set the load count on Windows 8 and higher, because
1915  // NT now uses a DAG of loader nodes.
1916  if (WindowsVersion < WINDOWS_8)
1917  {
1918  status = PhSetProcessModuleLoadCount(
1919  ProcessHandle,
1920  BaseAddress,
1921  1
1922  );
1923 
1924 #ifdef _WIN64
1925  if (isWow64 && status == STATUS_DLL_NOT_FOUND)
1926  {
1927  // The DLL might be 32-bit.
1929  ProcessHandle,
1930  BaseAddress,
1931  1
1932  );
1933 
1934  if (NT_SUCCESS(status))
1935  isModule32 = TRUE;
1936  }
1937 #endif
1938 
1939  if (!NT_SUCCESS(status))
1940  return status;
1941  }
1942 
1943 #ifdef _WIN64
1944  if (!isModule32)
1945  {
1946 #endif
1947  threadStart = PhGetModuleProcAddress(L"ntdll.dll", "LdrUnloadDll");
1948 #ifdef _WIN64
1949  }
1950  else
1951  {
1952  threadStart = ldrUnloadDll32;
1953 
1954  if (!threadStart)
1955  {
1956  PPH_STRING ntdll32FileName;
1957 
1958  ntdll32FileName = PhConcatStrings2(USER_SHARED_DATA->NtSystemRoot, L"\\SysWow64\\ntdll.dll");
1959  status = PhGetProcedureAddressRemote(
1960  ProcessHandle,
1961  ntdll32FileName->Buffer,
1962  "LdrUnloadDll",
1963  0,
1964  &ldrUnloadDll32,
1965  NULL
1966  );
1967  PhDereferenceObject(ntdll32FileName);
1968 
1969  if (!NT_SUCCESS(status))
1970  return status;
1971 
1972  threadStart = ldrUnloadDll32;
1973  }
1974  }
1975 #endif
1976 
1978  {
1979  status = RtlCreateUserThread(
1980  ProcessHandle,
1981  NULL,
1982  FALSE,
1983  0,
1984  0,
1985  0,
1986  (PUSER_THREAD_START_ROUTINE)threadStart,
1987  BaseAddress,
1988  &threadHandle,
1989  NULL
1990  );
1991  }
1992  else
1993  {
1994  if (!(threadHandle = CreateRemoteThread(
1995  ProcessHandle,
1996  NULL,
1997  0,
1998  (PTHREAD_START_ROUTINE)threadStart,
1999  BaseAddress,
2000  0,
2001  NULL
2002  )))
2003  {
2004  status = PhGetLastWin32ErrorAsNtStatus();
2005  }
2006  }
2007 
2008  if (!NT_SUCCESS(status))
2009  return status;
2010 
2011  status = NtWaitForSingleObject(threadHandle, FALSE, Timeout);
2012 
2013  if (status == STATUS_WAIT_0)
2014  {
2015  status = PhGetThreadBasicInformation(threadHandle, &basicInfo);
2016 
2017  if (NT_SUCCESS(status))
2018  status = basicInfo.ExitStatus;
2019  }
2020 
2021  NtClose(threadHandle);
2022 
2023  return status;
2024 }
2025 
2034  _In_ HANDLE ThreadHandle,
2035  _In_ ULONG IoPriority
2036  )
2037 {
2038  if (KphIsConnected())
2039  {
2040  return KphSetInformationThread(
2041  ThreadHandle,
2043  &IoPriority,
2044  sizeof(ULONG)
2045  );
2046  }
2047  else
2048  {
2049  return NtSetInformationThread(
2050  ThreadHandle,
2051  ThreadIoPriority,
2052  &IoPriority,
2053  sizeof(ULONG)
2054  );
2055  }
2056 }
2057 
2059  _In_ HANDLE JobHandle,
2060  _Out_ PJOBOBJECT_BASIC_PROCESS_ID_LIST *ProcessIdList
2061  )
2062 {
2063  NTSTATUS status;
2064  PVOID buffer;
2065  ULONG bufferSize;
2066 
2067  bufferSize = 0x100;
2068  buffer = PhAllocate(bufferSize);
2069 
2070  status = NtQueryInformationJobObject(
2071  JobHandle,
2072  JobObjectBasicProcessIdList,
2073  buffer,
2074  bufferSize,
2075  &bufferSize
2076  );
2077 
2078  if (status == STATUS_BUFFER_OVERFLOW)
2079  {
2080  PhFree(buffer);
2081  buffer = PhAllocate(bufferSize);
2082 
2083  status = NtQueryInformationJobObject(
2084  JobHandle,
2085  JobObjectBasicProcessIdList,
2086  buffer,
2087  bufferSize,
2088  NULL
2089  );
2090  }
2091 
2092  if (!NT_SUCCESS(status))
2093  {
2094  PhFree(buffer);
2095  return status;
2096  }
2097 
2098  *ProcessIdList = (PJOBOBJECT_BASIC_PROCESS_ID_LIST)buffer;
2099 
2100  return status;
2101 }
2102 
2115  _In_ HANDLE TokenHandle,
2116  _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
2117  _Out_ PVOID *Buffer
2118  )
2119 {
2120  NTSTATUS status;
2121  PVOID buffer;
2122  ULONG returnLength = 0;
2123 
2125  TokenHandle,
2126  TokenInformationClass,
2127  NULL,
2128  0,
2129  &returnLength
2130  );
2131  buffer = PhAllocate(returnLength);
2132  status = NtQueryInformationToken(
2133  TokenHandle,
2134  TokenInformationClass,
2135  buffer,
2136  returnLength,
2137  &returnLength
2138  );
2139 
2140  if (NT_SUCCESS(status))
2141  {
2142  *Buffer = buffer;
2143  }
2144  else
2145  {
2146  PhFree(buffer);
2147  }
2148 
2149  return status;
2150 }
2151 
2164  _In_ HANDLE TokenHandle,
2165  _In_ TOKEN_INFORMATION_CLASS TokenInformationClass,
2166  _Out_ PVOID *Buffer
2167  )
2168 {
2170  TokenHandle,
2171  TokenInformationClass,
2172  Buffer
2173  );
2174 }
2175 
2187  _In_ HANDLE TokenHandle,
2188  _Out_ PTOKEN_USER *User
2189  )
2190 {
2192  TokenHandle,
2193  TokenUser,
2194  User
2195  );
2196 }
2197 
2209  _In_ HANDLE TokenHandle,
2210  _Out_ PTOKEN_OWNER *Owner
2211  )
2212 {
2214  TokenHandle,
2215  TokenOwner,
2216  Owner
2217  );
2218 }
2219 
2231  _In_ HANDLE TokenHandle,
2232  _Out_ PTOKEN_PRIMARY_GROUP *PrimaryGroup
2233  )
2234 {
2236  TokenHandle,
2237  TokenPrimaryGroup,
2238  PrimaryGroup
2239  );
2240 }
2241 
2253  _In_ HANDLE TokenHandle,
2254  _Out_ PTOKEN_GROUPS *Groups
2255  )
2256 {
2258  TokenHandle,
2259  TokenGroups,
2260  Groups
2261  );
2262 }
2263 
2275  _In_ HANDLE TokenHandle,
2276  _Out_ PTOKEN_PRIVILEGES *Privileges
2277  )
2278 {
2280  TokenHandle,
2281  TokenPrivileges,
2282  Privileges
2283  );
2284 }
2285 
2287  _In_ HANDLE TokenHandle,
2288  _In_ ULONG SessionId
2289  )
2290 {
2291  return NtSetInformationToken(
2292  TokenHandle,
2293  TokenSessionId,
2294  &SessionId,
2295  sizeof(ULONG)
2296  );
2297 }
2298 
2313  _In_ HANDLE TokenHandle,
2314  _In_opt_ PWSTR PrivilegeName,
2315  _In_opt_ PLUID PrivilegeLuid,
2316  _In_ ULONG Attributes
2317  )
2318 {
2319  NTSTATUS status;
2320  TOKEN_PRIVILEGES privileges;
2321 
2322  privileges.PrivilegeCount = 1;
2323  privileges.Privileges[0].Attributes = Attributes;
2324 
2325  if (PrivilegeLuid)
2326  {
2327  privileges.Privileges[0].Luid = *PrivilegeLuid;
2328  }
2329  else if (PrivilegeName)
2330  {
2331  PH_STRINGREF privilegeName;
2332 
2333  PhInitializeStringRef(&privilegeName, PrivilegeName);
2334 
2336  &privilegeName,
2337  &privileges.Privileges[0].Luid
2338  ))
2339  return FALSE;
2340  }
2341  else
2342  {
2343  return FALSE;
2344  }
2345 
2346  if (!NT_SUCCESS(status = NtAdjustPrivilegesToken(
2347  TokenHandle,
2348  FALSE,
2349  &privileges,
2350  0,
2351  NULL,
2352  NULL
2353  )))
2354  return FALSE;
2355 
2356  if (status == STATUS_NOT_ALL_ASSIGNED)
2357  return FALSE;
2358 
2359  return TRUE;
2360 }
2361 
2363  _In_ HANDLE TokenHandle,
2364  _In_ LONG Privilege,
2365  _In_ ULONG Attributes
2366  )
2367 {
2368  LUID privilegeLuid;
2369 
2370  privilegeLuid = RtlConvertLongToLuid(Privilege);
2371 
2372  return PhSetTokenPrivilege(TokenHandle, NULL, &privilegeLuid, Attributes);
2373 }
2374 
2384  _In_ HANDLE TokenHandle,
2385  _In_ BOOLEAN IsVirtualizationEnabled
2386  )
2387 {
2388  ULONG virtualizationEnabled;
2389 
2390  virtualizationEnabled = IsVirtualizationEnabled;
2391 
2392  return NtSetInformationToken(
2393  TokenHandle,
2394  TokenVirtualizationEnabled,
2395  &virtualizationEnabled,
2396  sizeof(ULONG)
2397  );
2398 }
2399 
2412  _In_ HANDLE TokenHandle,
2413  _Out_opt_ PMANDATORY_LEVEL IntegrityLevel,
2414  _Out_opt_ PWSTR *IntegrityString
2415  )
2416 {
2417  NTSTATUS status;
2418  PTOKEN_MANDATORY_LABEL mandatoryLabel;
2419  ULONG subAuthority;
2420  MANDATORY_LEVEL integrityLevel;
2421  PWSTR integrityString;
2422 
2423  status = PhpQueryTokenVariableSize(TokenHandle, TokenIntegrityLevel, &mandatoryLabel);
2424 
2425  if (!NT_SUCCESS(status))
2426  return status;
2427 
2428  subAuthority = *RtlSubAuthoritySid(mandatoryLabel->Label.Sid, 0);
2429  PhFree(mandatoryLabel);
2430 
2431  switch (subAuthority)
2432  {
2433  case SECURITY_MANDATORY_UNTRUSTED_RID:
2434  integrityLevel = MandatoryLevelUntrusted;
2435  integrityString = L"Untrusted";
2436  break;
2437  case SECURITY_MANDATORY_LOW_RID:
2438  integrityLevel = MandatoryLevelLow;
2439  integrityString = L"Low";
2440  break;
2441  case SECURITY_MANDATORY_MEDIUM_RID:
2442  integrityLevel = MandatoryLevelMedium;
2443  integrityString = L"Medium";
2444  break;
2445  case SECURITY_MANDATORY_HIGH_RID:
2446  integrityLevel = MandatoryLevelHigh;
2447  integrityString = L"High";
2448  break;
2449  case SECURITY_MANDATORY_SYSTEM_RID:
2450  integrityLevel = MandatoryLevelSystem;
2451  integrityString = L"System";
2452  break;
2453  case SECURITY_MANDATORY_PROTECTED_PROCESS_RID:
2454  integrityLevel = MandatoryLevelSecureProcess;
2455  integrityString = L"Protected";
2456  break;
2457  default:
2458  return STATUS_UNSUCCESSFUL;
2459  }
2460 
2461  if (IntegrityLevel)
2462  *IntegrityLevel = integrityLevel;
2463  if (IntegrityString)
2464  *IntegrityString = integrityString;
2465 
2466  return status;
2467 }
2468 
2470  _In_ HANDLE FileHandle,
2471  _In_ FILE_INFORMATION_CLASS FileInformationClass,
2472  _Out_ PVOID *Buffer
2473  )
2474 {
2475  NTSTATUS status;
2476  IO_STATUS_BLOCK isb;
2477  PVOID buffer;
2478  ULONG bufferSize = 0x200;
2479 
2480  buffer = PhAllocate(bufferSize);
2481 
2482  while (TRUE)
2483  {
2484  status = NtQueryInformationFile(
2485  FileHandle,
2486  &isb,
2487  buffer,
2488  bufferSize,
2489  FileInformationClass
2490  );
2491 
2492  if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)
2493  {
2494  PhFree(buffer);
2495  bufferSize *= 2;
2496  buffer = PhAllocate(bufferSize);
2497  }
2498  else
2499  {
2500  break;
2501  }
2502  }
2503 
2504  if (NT_SUCCESS(status))
2505  {
2506  *Buffer = buffer;
2507  }
2508  else
2509  {
2510  PhFree(buffer);
2511  }
2512 
2513  return status;
2514 }
2515 
2516 NTSTATUS PhGetFileSize(
2517  _In_ HANDLE FileHandle,
2518  _Out_ PLARGE_INTEGER Size
2519  )
2520 {
2521  NTSTATUS status;
2522  FILE_STANDARD_INFORMATION standardInfo;
2523  IO_STATUS_BLOCK isb;
2524 
2525  status = NtQueryInformationFile(
2526  FileHandle,
2527  &isb,
2528  &standardInfo,
2529  sizeof(FILE_STANDARD_INFORMATION),
2531  );
2532 
2533  if (!NT_SUCCESS(status))
2534  return status;
2535 
2536  *Size = standardInfo.EndOfFile;
2537 
2538  return status;
2539 }
2540 
2541 NTSTATUS PhSetFileSize(
2542  _In_ HANDLE FileHandle,
2543  _In_ PLARGE_INTEGER Size
2544  )
2545 {
2546  FILE_END_OF_FILE_INFORMATION endOfFileInfo;
2547  IO_STATUS_BLOCK isb;
2548 
2549  endOfFileInfo.EndOfFile = *Size;
2550 
2551  return NtSetInformationFile(
2552  FileHandle,
2553  &isb,
2554  &endOfFileInfo,
2557  );
2558 }
2559 
2561  _In_ HANDLE TransactionManagerHandle,
2562  _In_ TRANSACTIONMANAGER_INFORMATION_CLASS TransactionManagerInformationClass,
2563  _Out_ PVOID *Buffer
2564  )
2565 {
2566  NTSTATUS status;
2567  PVOID buffer;
2568  ULONG bufferSize = 0x100;
2569 
2570  if (!NtQueryInformationTransactionManager_Import())
2571  return STATUS_NOT_SUPPORTED;
2572 
2573  buffer = PhAllocate(bufferSize);
2574 
2575  while (TRUE)
2576  {
2577  status = NtQueryInformationTransactionManager_Import()(
2578  TransactionManagerHandle,
2579  TransactionManagerInformationClass,
2580  buffer,
2581  bufferSize,
2582  NULL
2583  );
2584 
2585  if (status == STATUS_BUFFER_OVERFLOW)
2586  {
2587  PhFree(buffer);
2588  bufferSize *= 2;
2589 
2590  if (bufferSize > 1 * 1024 * 1024)
2591  return STATUS_INSUFFICIENT_RESOURCES;
2592 
2593  buffer = PhAllocate(bufferSize);
2594  }
2595  else
2596  {
2597  break;
2598  }
2599  }
2600 
2601  if (NT_SUCCESS(status))
2602  {
2603  *Buffer = buffer;
2604  }
2605  else
2606  {
2607  PhFree(buffer);
2608  }
2609 
2610  return status;
2611 }
2612 
2614  _In_ HANDLE TransactionManagerHandle,
2615  _Out_ PTRANSACTIONMANAGER_BASIC_INFORMATION BasicInformation
2616  )
2617 {
2618  if (NtQueryInformationTransactionManager_Import())
2619  {
2620  return NtQueryInformationTransactionManager_Import()(
2621  TransactionManagerHandle,
2622  TransactionManagerBasicInformation,
2623  BasicInformation,
2624  sizeof(TRANSACTIONMANAGER_BASIC_INFORMATION),
2625  NULL
2626  );
2627  }
2628  else
2629  {
2630  return STATUS_NOT_SUPPORTED;
2631  }
2632 }
2633 
2635  _In_ HANDLE TransactionManagerHandle,
2636  _Out_ PPH_STRING *LogFileName
2637  )
2638 {
2639  NTSTATUS status;
2640  PTRANSACTIONMANAGER_LOGPATH_INFORMATION logPathInfo;
2641 
2643  TransactionManagerHandle,
2644  TransactionManagerLogPathInformation,
2645  &logPathInfo
2646  );
2647 
2648  if (!NT_SUCCESS(status))
2649  return status;
2650 
2651  *LogFileName = PhCreateStringEx(
2652  logPathInfo->LogPath,
2653  logPathInfo->LogPathLength
2654  );
2655  PhFree(logPathInfo);
2656 
2657  return status;
2658 }
2659 
2661  _In_ HANDLE TransactionHandle,
2662  _In_ TRANSACTION_INFORMATION_CLASS TransactionInformationClass,
2663  _Out_ PVOID *Buffer
2664  )
2665 {
2666  NTSTATUS status;
2667  PVOID buffer;
2668  ULONG bufferSize = 0x100;
2669 
2670  if (!NtQueryInformationTransaction_Import())
2671  return STATUS_NOT_SUPPORTED;
2672 
2673  buffer = PhAllocate(bufferSize);
2674 
2675  while (TRUE)
2676  {
2677  status = NtQueryInformationTransaction_Import()(
2678  TransactionHandle,
2679  TransactionInformationClass,
2680  buffer,
2681  bufferSize,
2682  NULL
2683  );
2684 
2685  if (status == STATUS_BUFFER_OVERFLOW)
2686  {
2687  PhFree(buffer);
2688  bufferSize *= 2;
2689 
2690  if (bufferSize > 1 * 1024 * 1024)
2691  return STATUS_INSUFFICIENT_RESOURCES;
2692 
2693  buffer = PhAllocate(bufferSize);
2694  }
2695  else
2696  {
2697  break;
2698  }
2699  }
2700 
2701  if (NT_SUCCESS(status))
2702  {
2703  *Buffer = buffer;
2704  }
2705  else
2706  {
2707  PhFree(buffer);
2708  }
2709 
2710  return status;
2711 }
2712 
2714  _In_ HANDLE TransactionHandle,
2715  _Out_ PTRANSACTION_BASIC_INFORMATION BasicInformation
2716  )
2717 {
2718  if (NtQueryInformationTransaction_Import())
2719  {
2720  return NtQueryInformationTransaction_Import()(
2721  TransactionHandle,
2722  TransactionBasicInformation,
2723  BasicInformation,
2724  sizeof(TRANSACTION_BASIC_INFORMATION),
2725  NULL
2726  );
2727  }
2728  else
2729  {
2730  return STATUS_NOT_SUPPORTED;
2731  }
2732 }
2733 
2735  _In_ HANDLE TransactionHandle,
2736  _Out_opt_ PLARGE_INTEGER Timeout,
2737  _Out_opt_ TRANSACTION_OUTCOME *Outcome,
2738  _Out_opt_ PPH_STRING *Description
2739  )
2740 {
2741  NTSTATUS status;
2742  PTRANSACTION_PROPERTIES_INFORMATION propertiesInfo;
2743 
2745  TransactionHandle,
2746  TransactionPropertiesInformation,
2747  &propertiesInfo
2748  );
2749 
2750  if (!NT_SUCCESS(status))
2751  return status;
2752 
2753  if (Timeout)
2754  {
2755  *Timeout = propertiesInfo->Timeout;
2756  }
2757 
2758  if (Outcome)
2759  {
2760  *Outcome = propertiesInfo->Outcome;
2761  }
2762 
2763  if (Description)
2764  {
2765  *Description = PhCreateStringEx(
2766  propertiesInfo->Description,
2767  propertiesInfo->DescriptionLength
2768  );
2769  }
2770 
2771  PhFree(propertiesInfo);
2772 
2773  return status;
2774 }
2775 
2777  _In_ HANDLE ResourceManagerHandle,
2778  _In_ RESOURCEMANAGER_INFORMATION_CLASS ResourceManagerInformationClass,
2779  _Out_ PVOID *Buffer
2780  )
2781 {
2782  NTSTATUS status;
2783  PVOID buffer;
2784  ULONG bufferSize = 0x100;
2785 
2786  if (!NtQueryInformationResourceManager_Import())
2787  return STATUS_NOT_SUPPORTED;
2788 
2789  buffer = PhAllocate(bufferSize);
2790 
2791  while (TRUE)
2792  {
2793  status = NtQueryInformationResourceManager_Import()(
2794  ResourceManagerHandle,
2795  ResourceManagerInformationClass,
2796  buffer,
2797  bufferSize,
2798  NULL
2799  );
2800 
2801  if (status == STATUS_BUFFER_OVERFLOW)
2802  {
2803  PhFree(buffer);
2804  bufferSize *= 2;
2805 
2806  if (bufferSize > 1 * 1024 * 1024)
2807  return STATUS_INSUFFICIENT_RESOURCES;
2808 
2809  buffer = PhAllocate(bufferSize);
2810  }
2811  else
2812  {
2813  break;
2814  }
2815  }
2816 
2817  if (NT_SUCCESS(status))
2818  {
2819  *Buffer = buffer;
2820  }
2821  else
2822  {
2823  PhFree(buffer);
2824  }
2825 
2826  return status;
2827 }
2828 
2830  _In_ HANDLE ResourceManagerHandle,
2831  _Out_opt_ PGUID Guid,
2832  _Out_opt_ PPH_STRING *Description
2833  )
2834 {
2835  NTSTATUS status;
2836  PRESOURCEMANAGER_BASIC_INFORMATION basicInfo;
2837 
2839  ResourceManagerHandle,
2840  ResourceManagerBasicInformation,
2841  &basicInfo
2842  );
2843 
2844  if (!NT_SUCCESS(status))
2845  return status;
2846 
2847  if (Guid)
2848  {
2849  *Guid = basicInfo->ResourceManagerId;
2850  }
2851 
2852  if (Description)
2853  {
2854  *Description = PhCreateStringEx(
2855  basicInfo->Description,
2856  basicInfo->DescriptionLength
2857  );
2858  }
2859 
2860  PhFree(basicInfo);
2861 
2862  return status;
2863 }
2864 
2866  _In_ HANDLE EnlistmentHandle,
2867  _Out_ PENLISTMENT_BASIC_INFORMATION BasicInformation
2868  )
2869 {
2870  if (NtQueryInformationEnlistment_Import())
2871  {
2872  return NtQueryInformationEnlistment_Import()(
2873  EnlistmentHandle,
2874  EnlistmentBasicInformation,
2875  BasicInformation,
2876  sizeof(ENLISTMENT_BASIC_INFORMATION),
2877  NULL
2878  );
2879  }
2880  else
2881  {
2882  return STATUS_NOT_SUPPORTED;
2883  }
2884 }
2885 
2886 typedef struct _OPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT
2887 {
2888  NTSTATUS Status;
2889  PVOID BaseAddress;
2890  HANDLE DriverHandle;
2892 
2894  _In_ PPH_STRINGREF Name,
2895  _In_ PPH_STRINGREF TypeName,
2896  _In_opt_ PVOID Context
2897  )
2898 {
2899  static PH_STRINGREF driverDirectoryName = PH_STRINGREF_INIT(L"\\Driver\\");
2900 
2901  NTSTATUS status;
2902  POPEN_DRIVER_BY_BASE_ADDRESS_CONTEXT context = Context;
2903  PPH_STRING driverName;
2904  UNICODE_STRING driverNameUs;
2905  OBJECT_ATTRIBUTES objectAttributes;
2906  HANDLE driverHandle;
2907  DRIVER_BASIC_INFORMATION basicInfo;
2908 
2909  driverName = PhConcatStringRef2(&driverDirectoryName, Name);
2910 
2911  if (!PhStringRefToUnicodeString(&driverName->sr, &driverNameUs))
2912  {
2913  PhDereferenceObject(driverName);
2914  return TRUE;
2915  }
2916 
2918  &objectAttributes,
2919  &driverNameUs,
2920  0,
2921  NULL,
2922  NULL
2923  );
2924 
2925  status = KphOpenDriver(&driverHandle, &objectAttributes);
2926  PhDereferenceObject(driverName);
2927 
2928  if (!NT_SUCCESS(status))
2929  return TRUE;
2930 
2931  status = KphQueryInformationDriver(
2932  driverHandle,
2934  &basicInfo,
2935  sizeof(DRIVER_BASIC_INFORMATION),
2936  NULL
2937  );
2938 
2939  if (NT_SUCCESS(status))
2940  {
2941  if (basicInfo.DriverStart == context->BaseAddress)
2942  {
2943  context->Status = STATUS_SUCCESS;
2944  context->DriverHandle = driverHandle;
2945 
2946  return FALSE;
2947  }
2948  }
2949 
2950  NtClose(driverHandle);
2951 
2952  return TRUE;
2953 }
2954 
2970  _Out_ PHANDLE DriverHandle,
2971  _In_ PVOID BaseAddress
2972  )
2973 {
2974  NTSTATUS status;
2975  UNICODE_STRING driverDirectoryName;
2976  OBJECT_ATTRIBUTES objectAttributes;
2977  HANDLE driverDirectoryHandle;
2979 
2981  &driverDirectoryName,
2982  L"\\Driver"
2983  );
2985  &objectAttributes,
2986  &driverDirectoryName,
2987  0,
2988  NULL,
2989  NULL
2990  );
2991 
2992  if (!NT_SUCCESS(status = NtOpenDirectoryObject(
2993  &driverDirectoryHandle,
2994  DIRECTORY_QUERY,
2995  &objectAttributes
2996  )))
2997  return status;
2998 
2999  context.Status = STATUS_OBJECT_NAME_NOT_FOUND;
3000  context.BaseAddress = BaseAddress;
3001 
3002  status = PhEnumDirectoryObjects(
3003  driverDirectoryHandle,
3005  &context
3006  );
3007  NtClose(driverDirectoryHandle);
3008 
3009  if (!NT_SUCCESS(status) && !NT_SUCCESS(context.Status))
3010  return status;
3011 
3012  if (NT_SUCCESS(context.Status))
3013  {
3014  *DriverHandle = context.DriverHandle;
3015  }
3016 
3017  return context.Status;
3018 }
3019 
3035  _In_ HANDLE DriverHandle,
3036  _In_ DRIVER_INFORMATION_CLASS DriverInformationClass,
3037  _Out_ PVOID *Buffer
3038  )
3039 {
3040  NTSTATUS status;
3041  PVOID buffer;
3042  ULONG returnLength = 0;
3043 
3045  DriverHandle,
3046  DriverInformationClass,
3047  NULL,
3048  0,
3049  &returnLength
3050  );
3051  buffer = PhAllocate(returnLength);
3052  status = KphQueryInformationDriver(
3053  DriverHandle,
3054  DriverInformationClass,
3055  buffer,
3056  returnLength,
3057  &returnLength
3058  );
3059 
3060  if (NT_SUCCESS(status))
3061  {
3062  *Buffer = buffer;
3063  }
3064  else
3065  {
3066  PhFree(buffer);
3067  }
3068 
3069  return status;
3070 }
3071 
3085  _In_ HANDLE DriverHandle,
3086  _Out_ PPH_STRING *Name
3087  )
3088 {
3089  NTSTATUS status;
3090  PUNICODE_STRING unicodeString;
3091 
3092  if (!NT_SUCCESS(status = PhpQueryDriverVariableSize(
3093  DriverHandle,
3095  &unicodeString
3096  )))
3097  return status;
3098 
3099  *Name = PhCreateStringEx(
3100  unicodeString->Buffer,
3101  unicodeString->Length
3102  );
3103  PhFree(unicodeString);
3104 
3105  return status;
3106 }
3107 
3121  _In_ HANDLE DriverHandle,
3122  _Out_ PPH_STRING *ServiceKeyName
3123  )
3124 {
3125  NTSTATUS status;
3126  PUNICODE_STRING unicodeString;
3127 
3128  if (!NT_SUCCESS(status = PhpQueryDriverVariableSize(
3129  DriverHandle,
3131  &unicodeString
3132  )))
3133  return status;
3134 
3135  *ServiceKeyName = PhCreateStringEx(
3136  unicodeString->Buffer,
3137  unicodeString->Length
3138  );
3139  PhFree(unicodeString);
3140 
3141  return status;
3142 }
3143 
3145  _In_ PPH_STRING ServiceKeyName
3146  )
3147 {
3148  static PH_STRINGREF fullServicesKeyName = PH_STRINGREF_INIT(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\");
3149 
3150  NTSTATUS status;
3151  PPH_STRING fullServiceKeyName;
3152  UNICODE_STRING fullServiceKeyNameUs;
3153  HANDLE serviceKeyHandle;
3154  ULONG disposition;
3155 
3156  fullServiceKeyName = PhConcatStringRef2(&fullServicesKeyName, &ServiceKeyName->sr);
3157 
3158  if (!PhStringRefToUnicodeString(&fullServiceKeyName->sr, &fullServiceKeyNameUs))
3159  {
3160  PhDereferenceObject(fullServiceKeyName);
3161  return STATUS_NAME_TOO_LONG;
3162  }
3163 
3164  if (NT_SUCCESS(status = PhCreateKey(
3165  &serviceKeyHandle,
3166  KEY_WRITE | DELETE,
3167  NULL,
3168  &fullServiceKeyName->sr,
3169  0,
3170  0,
3171  &disposition
3172  )))
3173  {
3174  if (disposition == REG_CREATED_NEW_KEY)
3175  {
3176  static UNICODE_STRING imagePath = RTL_CONSTANT_STRING(L"\\SystemRoot\\system32\\drivers\\ntfs.sys");
3177 
3178  UNICODE_STRING valueName;
3179  ULONG dword;
3180 
3181  // Set up the required values.
3182  dword = 1;
3183  RtlInitUnicodeString(&valueName, L"ErrorControl");
3184  NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG));
3185  RtlInitUnicodeString(&valueName, L"Start");
3186  NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG));
3187  RtlInitUnicodeString(&valueName, L"Type");
3188  NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_DWORD, &dword, sizeof(ULONG));
3189 
3190  // Use a bogus name.
3191  RtlInitUnicodeString(&valueName, L"ImagePath");
3192  NtSetValueKey(serviceKeyHandle, &valueName, 0, REG_SZ, imagePath.Buffer, imagePath.Length + 2);
3193  }
3194 
3195  status = NtUnloadDriver(&fullServiceKeyNameUs);
3196 
3197  if (disposition == REG_CREATED_NEW_KEY)
3198  {
3199  // We added values, not subkeys, so this function will work correctly.
3200  NtDeleteKey(serviceKeyHandle);
3201  }
3202 
3203  NtClose(serviceKeyHandle);
3204  }
3205 
3206  PhDereferenceObject(fullServiceKeyName);
3207 
3208  return status;
3209 }
3210 
3228  _In_opt_ PVOID BaseAddress,
3229  _In_opt_ PWSTR Name
3230  )
3231 {
3232  NTSTATUS status;
3233  HANDLE driverHandle;
3234  PPH_STRING serviceKeyName = NULL;
3235 
3236  if (!BaseAddress && !Name)
3237  return STATUS_INVALID_PARAMETER_MIX;
3238  if (!Name && !KphIsConnected())
3239  return STATUS_INVALID_PARAMETER_MIX;
3240 
3241  // Try to get the service key name by scanning the
3242  // Driver directory.
3243 
3244  if (KphIsConnected() && BaseAddress)
3245  {
3247  &driverHandle,
3248  BaseAddress
3249  )))
3250  {
3251  PhGetDriverServiceKeyName(driverHandle, &serviceKeyName);
3252  NtClose(driverHandle);
3253  }
3254  }
3255 
3256  // Use the base name if we didn't get the service
3257  // key name.
3258 
3259  if (!serviceKeyName && Name)
3260  {
3261  PPH_STRING name;
3262 
3263  name = PhCreateString(Name);
3264 
3265  // Remove the extension if it is present.
3266  if (PhEndsWithString2(name, L".sys", TRUE))
3267  {
3268  serviceKeyName = PhSubstring(name, 0, name->Length / 2 - 4);
3269  PhDereferenceObject(name);
3270  }
3271  else
3272  {
3273  serviceKeyName = name;
3274  }
3275  }
3276 
3277  if (!serviceKeyName)
3278  return STATUS_OBJECT_NAME_NOT_FOUND;
3279 
3280  status = PhpUnloadDriver(serviceKeyName);
3281  PhDereferenceObject(serviceKeyName);
3282 
3283  return status;
3284 }
3285 
3310  _In_ HANDLE SourceProcessHandle,
3311  _In_ HANDLE SourceHandle,
3312  _In_opt_ HANDLE TargetProcessHandle,
3313  _Out_opt_ PHANDLE TargetHandle,
3314  _In_ ACCESS_MASK DesiredAccess,
3315  _In_ ULONG HandleAttributes,
3316  _In_ ULONG Options
3317  )
3318 {
3319  NTSTATUS status;
3320 
3321  if (KphIsConnected())
3322  {
3323  status = KphDuplicateObject(
3324  SourceProcessHandle,
3325  SourceHandle,
3326  TargetProcessHandle,
3327  TargetHandle,
3328  DesiredAccess,
3329  HandleAttributes,
3330  Options
3331  );
3332 
3333  // If KPH couldn't duplicate the handle, pass through to
3334  // NtDuplicateObject. This is for special objects like ALPC ports.
3335  if (status != STATUS_NOT_SUPPORTED)
3336  return status;
3337  }
3338 
3339  return NtDuplicateObject(
3340  SourceProcessHandle,
3341  SourceHandle,
3342  TargetProcessHandle,
3343  TargetHandle,
3344  DesiredAccess,
3345  HandleAttributes,
3346  Options
3347  );
3348 }
3349 
3351  _In_ HANDLE ProcessHandle,
3352  _In_ PPHP_ENUM_PROCESS_MODULES_CALLBACK Callback,
3353  _In_opt_ PVOID Context1,
3354  _In_opt_ PVOID Context2
3355  )
3356 {
3357  NTSTATUS status;
3358  PROCESS_BASIC_INFORMATION basicInfo;
3359  PPEB_LDR_DATA ldr;
3360  PEB_LDR_DATA pebLdrData;
3361  PLIST_ENTRY startLink;
3362  PLIST_ENTRY currentLink;
3363  ULONG dataTableEntrySize;
3364  LDR_DATA_TABLE_ENTRY currentEntry;
3365  ULONG i;
3366 
3367  // Get the PEB address.
3368  status = PhGetProcessBasicInformation(ProcessHandle, &basicInfo);
3369 
3370  if (!NT_SUCCESS(status))
3371  return status;
3372 
3373  // Read the address of the loader data.
3374  status = PhReadVirtualMemory(
3375  ProcessHandle,
3376  PTR_ADD_OFFSET(basicInfo.PebBaseAddress, FIELD_OFFSET(PEB, Ldr)),
3377  &ldr,
3378  sizeof(PVOID),
3379  NULL
3380  );
3381 
3382  if (!NT_SUCCESS(status))
3383  return status;
3384 
3385  // Read the loader data.
3386  status = PhReadVirtualMemory(
3387  ProcessHandle,
3388  ldr,
3389  &pebLdrData,
3390  sizeof(PEB_LDR_DATA),
3391  NULL
3392  );
3393 
3394  if (!NT_SUCCESS(status))
3395  return status;
3396 
3397  if (!pebLdrData.Initialized)
3398  return STATUS_UNSUCCESSFUL;
3399 
3400  if (WindowsVersion >= WINDOWS_8)
3401  dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8;
3402  else if (WindowsVersion >= WINDOWS_7)
3403  dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7;
3404  else
3405  dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WINXP;
3406 
3407  // Traverse the linked list (in load order).
3408 
3409  i = 0;
3410  startLink = PTR_ADD_OFFSET(ldr, FIELD_OFFSET(PEB_LDR_DATA, InLoadOrderModuleList));
3411  currentLink = pebLdrData.InLoadOrderModuleList.Flink;
3412 
3413  while (
3414  currentLink != startLink &&
3416  )
3417  {
3418  PVOID addressOfEntry;
3419 
3420  addressOfEntry = CONTAINING_RECORD(currentLink, LDR_DATA_TABLE_ENTRY, InLoadOrderLinks);
3421  status = PhReadVirtualMemory(
3422  ProcessHandle,
3423  addressOfEntry,
3424  &currentEntry,
3425  dataTableEntrySize,
3426  NULL
3427  );
3428 
3429  if (!NT_SUCCESS(status))
3430  return status;
3431 
3432  // Make sure the entry is valid.
3433  if (currentEntry.DllBase)
3434  {
3435  // Execute the callback.
3436  if (!Callback(
3437  ProcessHandle,
3438  &currentEntry,
3439  addressOfEntry,
3440  Context1,
3441  Context2
3442  ))
3443  break;
3444  }
3445 
3446  currentLink = currentEntry.InLoadOrderLinks.Flink;
3447  i++;
3448  }
3449 
3450  return status;
3451 }
3452 
3454  _In_ HANDLE ProcessHandle,
3455  _In_ PLDR_DATA_TABLE_ENTRY Entry,
3456  _In_ PVOID AddressOfEntry,
3457  _In_opt_ PVOID Context1,
3458  _In_opt_ PVOID Context2
3459  )
3460 {
3461  NTSTATUS status;
3463  BOOLEAN cont;
3464  PPH_STRING mappedFileName;
3465  PWSTR fullDllNameOriginal;
3466  PWSTR fullDllNameBuffer;
3467  PWSTR baseDllNameOriginal;
3468  PWSTR baseDllNameBuffer;
3469 
3470  parameters = Context1;
3471  mappedFileName = NULL;
3472 
3474  {
3475  PhGetProcessMappedFileName(ProcessHandle, Entry->DllBase, &mappedFileName);
3476  }
3477 
3478  if (mappedFileName)
3479  {
3480  ULONG_PTR indexOfLastBackslash;
3481 
3482  PhStringRefToUnicodeString(&mappedFileName->sr, &Entry->FullDllName);
3483  indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, '\\');
3484 
3485  if (indexOfLastBackslash != -1)
3486  {
3487  Entry->BaseDllName.Buffer = Entry->FullDllName.Buffer + indexOfLastBackslash + 1;
3488  Entry->BaseDllName.Length = Entry->FullDllName.Length - (USHORT)indexOfLastBackslash * 2 - 2;
3489  Entry->BaseDllName.MaximumLength = Entry->BaseDllName.Length;
3490  }
3491  else
3492  {
3493  Entry->BaseDllName = Entry->FullDllName;
3494  }
3495  }
3496  else
3497  {
3498  // Read the full DLL name string and add a null terminator.
3499 
3500  fullDllNameOriginal = Entry->FullDllName.Buffer;
3501  fullDllNameBuffer = PhAllocate(Entry->FullDllName.Length + 2);
3502  Entry->FullDllName.Buffer = fullDllNameBuffer;
3503 
3504  if (NT_SUCCESS(status = PhReadVirtualMemory(
3505  ProcessHandle,
3506  fullDllNameOriginal,
3507  fullDllNameBuffer,
3508  Entry->FullDllName.Length,
3509  NULL
3510  )))
3511  {
3512  fullDllNameBuffer[Entry->FullDllName.Length / 2] = 0;
3513  }
3514  else
3515  {
3516  fullDllNameBuffer[0] = 0;
3517  Entry->FullDllName.Length = 0;
3518  }
3519 
3520  baseDllNameOriginal = Entry->BaseDllName.Buffer;
3521 
3522  // Try to use the buffer we just read in.
3523  if (
3524  NT_SUCCESS(status) &&
3525  (ULONG_PTR)baseDllNameOriginal >= (ULONG_PTR)fullDllNameOriginal &&
3526  (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length >= (ULONG_PTR)baseDllNameOriginal &&
3527  (ULONG_PTR)baseDllNameOriginal + Entry->BaseDllName.Length <= (ULONG_PTR)fullDllNameOriginal + Entry->FullDllName.Length
3528  )
3529  {
3530  baseDllNameBuffer = NULL;
3531 
3532  Entry->BaseDllName.Buffer = (PWCHAR)((ULONG_PTR)Entry->FullDllName.Buffer +
3533  ((ULONG_PTR)baseDllNameOriginal - (ULONG_PTR)fullDllNameOriginal));
3534  }
3535  else
3536  {
3537  // Read the base DLL name string and add a null terminator.
3538 
3539  baseDllNameBuffer = PhAllocate(Entry->BaseDllName.Length + 2);
3540  Entry->BaseDllName.Buffer = baseDllNameBuffer;
3541 
3543  ProcessHandle,
3544  baseDllNameOriginal,
3545  baseDllNameBuffer,
3546  Entry->BaseDllName.Length,
3547  NULL
3548  )))
3549  {
3550  baseDllNameBuffer[Entry->BaseDllName.Length / 2] = 0;
3551  }
3552  else
3553  {
3554  baseDllNameBuffer[0] = 0;
3555  Entry->BaseDllName.Length = 0;
3556  }
3557  }
3558  }
3559 
3560  // Execute the callback.
3561  cont = parameters->Callback(Entry, parameters->Context);
3562 
3563  if (mappedFileName)
3564  {
3565  PhDereferenceObject(mappedFileName);
3566  }
3567  else
3568  {
3569  PhFree(fullDllNameBuffer);
3570 
3571  if (baseDllNameBuffer)
3572  PhFree(baseDllNameBuffer);
3573  }
3574 
3575  return cont;
3576 }
3577 
3590  _In_ HANDLE ProcessHandle,
3591  _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback,
3592  _In_opt_ PVOID Context
3593  )
3594 {
3596 
3597  parameters.Callback = Callback;
3598  parameters.Context = Context;
3599  parameters.Flags = 0;
3600 
3601  return PhEnumProcessModulesEx(ProcessHandle, &parameters);
3602 }
3603 
3615  _In_ HANDLE ProcessHandle,
3616  _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters
3617  )
3618 {
3619  return PhpEnumProcessModules(
3620  ProcessHandle,
3622  Parameters,
3623  NULL
3624  );
3625 }
3626 
3627 typedef struct _SET_PROCESS_MODULE_LOAD_COUNT_CONTEXT
3628 {
3629  NTSTATUS Status;
3630  PVOID BaseAddress;
3631  ULONG LoadCount;
3633 
3635  _In_ HANDLE ProcessHandle,
3636  _In_ PLDR_DATA_TABLE_ENTRY Entry,
3637  _In_ PVOID AddressOfEntry,
3638  _In_opt_ PVOID Context1,
3639  _In_opt_ PVOID Context2
3640  )
3641 {
3642  PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context = Context1;
3643 
3644  if (Entry->DllBase == context->BaseAddress)
3645  {
3646  context->Status = PhWriteVirtualMemory(
3647  ProcessHandle,
3648  PTR_ADD_OFFSET(AddressOfEntry, FIELD_OFFSET(LDR_DATA_TABLE_ENTRY, ObsoleteLoadCount)),
3649  &context->LoadCount,
3650  sizeof(USHORT),
3651  NULL
3652  );
3653 
3654  return FALSE;
3655  }
3656 
3657  return TRUE;
3658 }
3659 
3672  _In_ HANDLE ProcessHandle,
3673  _In_ PVOID BaseAddress,
3674  _In_ ULONG LoadCount
3675  )
3676 {
3677  NTSTATUS status;
3679 
3680  context.Status = STATUS_DLL_NOT_FOUND;
3681  context.BaseAddress = BaseAddress;
3682  context.LoadCount = LoadCount;
3683 
3684  status = PhpEnumProcessModules(
3685  ProcessHandle,
3687  &context,
3688  NULL
3689  );
3690 
3691  if (!NT_SUCCESS(status))
3692  return status;
3693 
3694  return context.Status;
3695 }
3696 
3698  _In_ HANDLE ProcessHandle,
3700  _In_opt_ PVOID Context1,
3701  _In_opt_ PVOID Context2
3702  )
3703 {
3704  NTSTATUS status;
3705  PPEB32 peb;
3706  ULONG ldr; // PEB_LDR_DATA32 *32
3707  PEB_LDR_DATA32 pebLdrData;
3708  ULONG startLink; // LIST_ENTRY32 *32
3709  ULONG currentLink; // LIST_ENTRY32 *32
3710  ULONG dataTableEntrySize;
3711  LDR_DATA_TABLE_ENTRY32 currentEntry;
3712  ULONG i;
3713 
3714  // Get the 32-bit PEB address.
3715  status = PhGetProcessPeb32(ProcessHandle, &peb);
3716 
3717  if (!NT_SUCCESS(status))
3718  return status;
3719 
3720  if (!peb)
3721  return STATUS_NOT_SUPPORTED; // not a WOW64 process
3722 
3723  // Read the address of the loader data.
3724  status = PhReadVirtualMemory(
3725  ProcessHandle,
3726  PTR_ADD_OFFSET(peb, FIELD_OFFSET(PEB32, Ldr)),
3727  &ldr,
3728  sizeof(ULONG),
3729  NULL
3730  );
3731 
3732  if (!NT_SUCCESS(status))
3733  return status;
3734 
3735  // Read the loader data.
3736  status = PhReadVirtualMemory(
3737  ProcessHandle,
3738  UlongToPtr(ldr),
3739  &pebLdrData,
3740  sizeof(PEB_LDR_DATA32),
3741  NULL
3742  );
3743 
3744  if (!NT_SUCCESS(status))
3745  return status;
3746 
3747  if (!pebLdrData.Initialized)
3748  return STATUS_UNSUCCESSFUL;
3749 
3750  if (WindowsVersion >= WINDOWS_8)
3751  dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN8_32;
3752  else if (WindowsVersion >= WINDOWS_7)
3753  dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WIN7_32;
3754  else
3755  dataTableEntrySize = LDR_DATA_TABLE_ENTRY_SIZE_WINXP_32;
3756 
3757  // Traverse the linked list (in load order).
3758 
3759  i = 0;
3760  startLink = (ULONG)(ldr + FIELD_OFFSET(PEB_LDR_DATA32, InLoadOrderModuleList));
3761  currentLink = pebLdrData.InLoadOrderModuleList.Flink;
3762 
3763  while (
3764  currentLink != startLink &&
3766  )
3767  {
3768  ULONG addressOfEntry;
3769 
3770  addressOfEntry = (ULONG)CONTAINING_RECORD(UlongToPtr(currentLink), LDR_DATA_TABLE_ENTRY32, InLoadOrderLinks);
3771  status = PhReadVirtualMemory(
3772  ProcessHandle,
3773  UlongToPtr(addressOfEntry),
3774  &currentEntry,
3775  dataTableEntrySize,
3776  NULL
3777  );
3778 
3779  if (!NT_SUCCESS(status))
3780  return status;
3781 
3782  // Make sure the entry is valid.
3783  if (currentEntry.DllBase)
3784  {
3785  // Execute the callback.
3786  if (!Callback(
3787  ProcessHandle,
3788  &currentEntry,
3789  addressOfEntry,
3790  Context1,
3791  Context2
3792  ))
3793  break;
3794  }
3795 
3796  currentLink = currentEntry.InLoadOrderLinks.Flink;
3797  i++;
3798  }
3799 
3800  return status;
3801 }
3802 
3804  _In_ HANDLE ProcessHandle,
3805  _In_ PLDR_DATA_TABLE_ENTRY32 Entry,
3806  _In_ ULONG AddressOfEntry,
3807  _In_opt_ PVOID Context1,
3808  _In_opt_ PVOID Context2
3809  )
3810 {
3811  static PH_STRINGREF system32String = PH_STRINGREF_INIT(L"\\system32\\");
3812 
3814  BOOLEAN cont;
3815  LDR_DATA_TABLE_ENTRY nativeEntry;
3816  PPH_STRING mappedFileName;
3817  PWSTR baseDllNameBuffer;
3818  PWSTR fullDllNameBuffer;
3819  PH_STRINGREF fullDllName;
3820  PH_STRINGREF systemRootString;
3821 
3822  parameters = Context1;
3823 
3824  // Convert the 32-bit entry to a native-sized entry.
3825 
3826  memset(&nativeEntry, 0, sizeof(LDR_DATA_TABLE_ENTRY));
3827  nativeEntry.DllBase = UlongToPtr(Entry->DllBase);
3828  nativeEntry.EntryPoint = UlongToPtr(Entry->EntryPoint);
3829  nativeEntry.SizeOfImage = Entry->SizeOfImage;
3830  UStr32ToUStr(&nativeEntry.FullDllName, &Entry->FullDllName);
3831  UStr32ToUStr(&nativeEntry.BaseDllName, &Entry->BaseDllName);
3832  nativeEntry.Flags = Entry->Flags;
3833  nativeEntry.ObsoleteLoadCount = Entry->ObsoleteLoadCount;
3834  nativeEntry.TlsIndex = Entry->TlsIndex;
3835  nativeEntry.TimeDateStamp = Entry->TimeDateStamp;
3836  nativeEntry.OriginalBase = Entry->OriginalBase;
3837  nativeEntry.LoadTime = Entry->LoadTime;
3838  nativeEntry.BaseNameHashValue = Entry->BaseNameHashValue;
3839  nativeEntry.LoadReason = Entry->LoadReason;
3840 
3841  mappedFileName = NULL;
3842 
3844  {
3845  PhGetProcessMappedFileName(ProcessHandle, nativeEntry.DllBase, &mappedFileName);
3846  }
3847 
3848  if (mappedFileName)
3849  {
3850  ULONG_PTR indexOfLastBackslash;
3851 
3852  PhStringRefToUnicodeString(&mappedFileName->sr, &nativeEntry.FullDllName);
3853  indexOfLastBackslash = PhFindLastCharInString(mappedFileName, 0, '\\');
3854 
3855  if (indexOfLastBackslash != -1)
3856  {
3857  nativeEntry.BaseDllName.Buffer = nativeEntry.FullDllName.Buffer + indexOfLastBackslash + 1;
3858  nativeEntry.BaseDllName.Length = nativeEntry.FullDllName.Length - (USHORT)indexOfLastBackslash * 2 - 2;
3859  nativeEntry.BaseDllName.MaximumLength = nativeEntry.BaseDllName.Length;
3860  }
3861  else
3862  {
3863  nativeEntry.BaseDllName = nativeEntry.FullDllName;
3864  }
3865  }
3866  else
3867  {
3868  // Read the base DLL name string and add a null terminator.
3869 
3870  baseDllNameBuffer = PhAllocate(nativeEntry.BaseDllName.Length + 2);
3871 
3873  ProcessHandle,
3874  nativeEntry.BaseDllName.Buffer,
3875  baseDllNameBuffer,
3876  nativeEntry.BaseDllName.Length,
3877  NULL
3878  )))
3879  {
3880  baseDllNameBuffer[nativeEntry.BaseDllName.Length / 2] = 0;
3881  }
3882  else
3883  {
3884  baseDllNameBuffer[0] = 0;
3885  nativeEntry.BaseDllName.Length = 0;
3886  }
3887 
3888  nativeEntry.BaseDllName.Buffer = baseDllNameBuffer;
3889 
3890  // Read the full DLL name string and add a null terminator.
3891 
3892  fullDllNameBuffer = PhAllocate(nativeEntry.FullDllName.Length + 2);
3893 
3895  ProcessHandle,
3896  nativeEntry.FullDllName.Buffer,
3897  fullDllNameBuffer,
3898  nativeEntry.FullDllName.Length,
3899  NULL
3900  )))
3901  {
3902  fullDllNameBuffer[nativeEntry.FullDllName.Length / 2] = 0;
3903 
3905  {
3906  // WOW64 file system redirection - convert "system32" to "SysWOW64".
3907  if (!(nativeEntry.FullDllName.Length & 1)) // validate the string length
3908  {
3909  fullDllName.Buffer = fullDllNameBuffer;
3910  fullDllName.Length = nativeEntry.FullDllName.Length;
3911 
3912  PhGetSystemRoot(&systemRootString);
3913 
3914  if (PhStartsWithStringRef(&fullDllName, &systemRootString, TRUE))
3915  {
3916  PhSkipStringRef(&fullDllName, systemRootString.Length);
3917 
3918  if (PhStartsWithStringRef(&fullDllName, &system32String, TRUE))
3919  {
3920  fullDllName.Buffer[1] = 'S';
3921  fullDllName.Buffer[4] = 'W';
3922  fullDllName.Buffer[5] = 'O';
3923  fullDllName.Buffer[6] = 'W';
3924  fullDllName.Buffer[7] = '6';
3925  fullDllName.Buffer[8] = '4';
3926  }
3927  }
3928  }
3929  }
3930  }
3931  else
3932  {
3933  fullDllNameBuffer[0] = 0;
3934  nativeEntry.FullDllName.Length = 0;
3935  }
3936 
3937  nativeEntry.FullDllName.Buffer = fullDllNameBuffer;
3938  }
3939 
3940  // Execute the callback.
3941  cont = parameters->Callback(&nativeEntry, parameters->Context);
3942 
3943  if (mappedFileName)
3944  {
3945  PhDereferenceObject(mappedFileName);
3946  }
3947  else
3948  {
3949  PhFree(baseDllNameBuffer);
3950  PhFree(fullDllNameBuffer);
3951  }
3952 
3953  return cont;
3954 }
3955 
3974  _In_ HANDLE ProcessHandle,
3975  _In_ PPH_ENUM_PROCESS_MODULES_CALLBACK Callback,
3976  _In_opt_ PVOID Context
3977  )
3978 {
3980 
3981  parameters.Callback = Callback;
3982  parameters.Context = Context;
3983  parameters.Flags = 0;
3984 
3985  return PhEnumProcessModules32Ex(ProcessHandle, &parameters);
3986 }
3987 
4005  _In_ HANDLE ProcessHandle,
4006  _In_ PPH_ENUM_PROCESS_MODULES_PARAMETERS Parameters
4007  )
4008 {
4009  return PhpEnumProcessModules32(
4010  ProcessHandle,
4012  Parameters,
4013  NULL
4014  );
4015 }
4016 
4018  _In_ HANDLE ProcessHandle,
4019  _In_ PLDR_DATA_TABLE_ENTRY32 Entry,
4020  _In_ ULONG AddressOfEntry,
4021  _In_opt_ PVOID Context1,
4022  _In_opt_ PVOID Context2
4023  )
4024 {
4025  PSET_PROCESS_MODULE_LOAD_COUNT_CONTEXT context = Context1;
4026 
4027  if (UlongToPtr(Entry->DllBase) == context->BaseAddress)
4028  {
4029  context->Status = PhWriteVirtualMemory(
4030  ProcessHandle,
4031  UlongToPtr(AddressOfEntry + FIELD_OFFSET(LDR_DATA_TABLE_ENTRY32, ObsoleteLoadCount)),
4032  &context->LoadCount,
4033  sizeof(USHORT),
4034  NULL
4035  );
4036 
4037  return FALSE;
4038  }
4039 
4040  return TRUE;
4041 }
4042 
4060  _In_ HANDLE ProcessHandle,
4061  _In_ PVOID BaseAddress,
4062  _In_ ULONG LoadCount
4063  )
4064 {
4065  NTSTATUS status;
4067 
4068  context.Status = STATUS_DLL_NOT_FOUND;
4069  context.BaseAddress = BaseAddress;
4070  context.LoadCount = LoadCount;
4071 
4072  status = PhpEnumProcessModules32(
4073  ProcessHandle,
4075  &context,
4076  NULL
4077  );
4078 
4079  if (!NT_SUCCESS(status))
4080  return status;
4081 
4082  return context.Status;
4083 }
4084 
4085 typedef struct _GET_PROCEDURE_ADDRESS_REMOTE_CONTEXT
4086 {
4087  PH_STRINGREF FileName;
4088  PVOID DllBase;
4090 
4091 static BOOLEAN PhpGetProcedureAddressRemoteCallback(
4092  _In_ PLDR_DATA_TABLE_ENTRY Module,
4093  _In_opt_ PVOID Context
4094  )
4095 {
4096  PGET_PROCEDURE_ADDRESS_REMOTE_CONTEXT context = Context;
4097  PH_STRINGREF fullDllName;
4098 
4099  PhUnicodeStringToStringRef(&Module->FullDllName, &fullDllName);
4100 
4101  if (PhEqualStringRef(&fullDllName, &context->FileName, TRUE))
4102  {
4103  context->DllBase = Module->DllBase;
4104  return FALSE;
4105  }
4106 
4107  return TRUE;
4108 }
4109 
4127  _In_ HANDLE ProcessHandle,
4128  _In_ PWSTR FileName,
4129  _In_opt_ PSTR ProcedureName,
4130  _In_opt_ ULONG ProcedureNumber,
4131  _Out_ PVOID *ProcedureAddress,
4132  _Out_opt_ PVOID *DllBase
4133  )
4134 {
4135  NTSTATUS status;
4136  PH_MAPPED_IMAGE mappedImage;
4137  PH_MAPPED_IMAGE_EXPORTS exports;
4139 
4140  if (!NT_SUCCESS(status = PhLoadMappedImage(FileName, NULL, TRUE, &mappedImage)))
4141  return status;
4142 
4143  PhInitializeStringRef(&context.FileName, FileName);
4144  context.DllBase = NULL;
4145 
4146  if (mappedImage.Magic == IMAGE_NT_OPTIONAL_HDR32_MAGIC)
4147  {
4148 #ifdef _WIN64
4149  status = PhEnumProcessModules32(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context);
4150 #else
4151  status = PhEnumProcessModules(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context);
4152 #endif
4153  }
4154  else
4155  {
4156 #ifdef _WIN64
4157  status = PhEnumProcessModules(ProcessHandle, PhpGetProcedureAddressRemoteCallback, &context);
4158 #else
4159  status = STATUS_NOT_SUPPORTED;
4160 #endif
4161  }
4162 
4163  if (!NT_SUCCESS(status))
4164  goto CleanupExit;
4165 
4166  if (!NT_SUCCESS(status = PhGetMappedImageExports(&exports, &mappedImage)))
4167  goto CleanupExit;
4168 
4170  &exports,
4171  ProcedureName,
4172  (USHORT)ProcedureNumber,
4173  context.DllBase,
4174  ProcedureAddress
4175  );
4176 
4177  if (NT_SUCCESS(status))
4178  {
4179  if (DllBase)
4180  *DllBase = context.DllBase;
4181  }
4182 
4183 CleanupExit:
4184  PhUnloadMappedImage(&mappedImage);
4185 
4186  return status;
4187 }
4188 
4198  _Out_ PRTL_PROCESS_MODULES *Modules
4199  )
4200 {
4201  NTSTATUS status;
4202  PVOID buffer;
4203  ULONG bufferSize = 2048;
4204 
4205  buffer = PhAllocate(bufferSize);
4206 
4207  status = NtQuerySystemInformation(
4209  buffer,
4210  bufferSize,
4211  &bufferSize
4212  );
4213 
4214  if (status == STATUS_INFO_LENGTH_MISMATCH)
4215  {
4216  PhFree(buffer);
4217  buffer = PhAllocate(bufferSize);
4218 
4219  status = NtQuerySystemInformation(
4221  buffer,
4222  bufferSize,
4223  &bufferSize
4224  );
4225  }
4226 
4227  if (!NT_SUCCESS(status))
4228  return status;
4229 
4230  *Modules = buffer;
4231 
4232  return status;
4233 }
4234 
4244  _Out_ PRTL_PROCESS_MODULE_INFORMATION_EX *Modules
4245  )
4246 {
4247  NTSTATUS status;
4248  PVOID buffer;
4249  ULONG bufferSize = 2048;
4250 
4251  buffer = PhAllocate(bufferSize);
4252 
4253  status = NtQuerySystemInformation(
4255  buffer,
4256  bufferSize,
4257  &bufferSize
4258  );
4259 
4260  if (status == STATUS_INFO_LENGTH_MISMATCH)
4261  {
4262  PhFree(buffer);
4263  buffer = PhAllocate(bufferSize);
4264 
4265  status = NtQuerySystemInformation(
4267  buffer,
4268  bufferSize,
4269  &bufferSize
4270  );
4271  }
4272 
4273  if (!NT_SUCCESS(status))
4274  return status;
4275 
4276  *Modules = buffer;
4277 
4278  return status;
4279 }
4280 
4290  VOID
4291  )
4292 {
4293  PRTL_PROCESS_MODULES modules;
4294  PPH_STRING fileName = NULL;
4295 
4296  if (!NT_SUCCESS(PhEnumKernelModules(&modules)))
4297  return NULL;
4298 
4299  if (modules->NumberOfModules >= 1)
4300  {
4301  fileName = PhConvertMultiByteToUtf16(modules->Modules[0].FullPathName);
4302  }
4303 
4304  PhFree(modules);
4305 
4306  return fileName;
4307 }
4308 
4322  _Out_ PVOID *Processes
4323  )
4324 {
4325  return PhEnumProcessesEx(Processes, SystemProcessInformation);
4326 }
4327 
4341  _Out_ PVOID *Processes,
4342  _In_ SYSTEM_INFORMATION_CLASS SystemInformationClass
4343  )
4344 {
4345  static ULONG initialBufferSize[3] = { 0x4000, 0x4000, 0x4000 };
4346  NTSTATUS status;
4347  ULONG classIndex;
4348  PVOID buffer;
4349  ULONG bufferSize;
4350 
4351  switch (SystemInformationClass)
4352  {
4354  classIndex = 0;
4355  break;
4357  classIndex = 1;
4358  break;
4360  classIndex = 2;
4361  break;
4362  default:
4363  return STATUS_INVALID_INFO_CLASS;
4364  }
4365 
4366  bufferSize = initialBufferSize[classIndex];
4367  buffer = PhAllocate(bufferSize);
4368 
4369  while (TRUE)
4370  {
4371  status = NtQuerySystemInformation(
4372  SystemInformationClass,
4373  buffer,
4374  bufferSize,
4375  &bufferSize
4376  );
4377 
4378  if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)
4379  {
4380  PhFree(buffer);
4381  buffer = PhAllocate(bufferSize);
4382  }
4383  else
4384  {
4385  break;
4386  }
4387  }
4388 
4389  if (!NT_SUCCESS(status))
4390  {
4391  PhFree(buffer);
4392  return status;
4393  }
4394 
4395  if (bufferSize <= 0x40000) initialBufferSize[classIndex] = bufferSize;
4396  *Processes = buffer;
4397 
4398  return status;
4399 }
4400 
4415  _Out_ PVOID *Processes,
4416  _In_ ULONG SessionId
4417  )
4418 {
4419  static ULONG initialBufferSize = 0x4000;
4420  NTSTATUS status;
4421  SYSTEM_SESSION_PROCESS_INFORMATION sessionProcessInfo;
4422  PVOID buffer;
4423  ULONG bufferSize;
4424 
4425  bufferSize = initialBufferSize;
4426  buffer = PhAllocate(bufferSize);
4427 
4428  sessionProcessInfo.SessionId = SessionId;
4429 
4430  while (TRUE)
4431  {
4432  sessionProcessInfo.SizeOfBuf = bufferSize;
4433  sessionProcessInfo.Buffer = buffer;
4434 
4435  status = NtQuerySystemInformation(
4437  &sessionProcessInfo,
4439  &bufferSize // size of the inner buffer gets returned
4440  );
4441 
4442  if (status == STATUS_BUFFER_TOO_SMALL || status == STATUS_INFO_LENGTH_MISMATCH)
4443  {
4444  PhFree(buffer);
4445  buffer = PhAllocate(bufferSize);
4446  }
4447  else
4448  {
4449  break;
4450  }
4451  }
4452 
4453  if (!NT_SUCCESS(status))
4454  {
4455  PhFree(buffer);
4456  return status;
4457  }
4458 
4459  if (bufferSize <= 0x20000) initialBufferSize = bufferSize;
4460  *Processes = buffer;
4461 
4462  return status;
4463 }
4464 
4478  _In_ PVOID Processes,
4479  _In_ HANDLE ProcessId
4480  )
4481 {
4483 
4484  process = PH_FIRST_PROCESS(Processes);
4485 
4486  do
4487  {
4488  if (process->UniqueProcessId == ProcessId)
4489  return process;
4490  } while (process = PH_NEXT_PROCESS(process));
4491 
4492  return NULL;
4493 }
4494 
4508  _In_ PVOID Processes,
4509  _In_ PPH_STRINGREF ImageName
4510  )
4511 {
4513  PH_STRINGREF processImageName;
4514 
4515  process = PH_FIRST_PROCESS(Processes);
4516 
4517  do
4518  {
4519  PhUnicodeStringToStringRef(&process->ImageName, &processImageName);
4520 
4521  if (PhEqualStringRef(&processImageName, ImageName, TRUE))
4522  return process;
4523  } while (process = PH_NEXT_PROCESS(process));
4524 
4525  return NULL;
4526 }
4527 
4540 NTSTATUS PhEnumHandles(
4541  _Out_ PSYSTEM_HANDLE_INFORMATION *Handles
4542  )
4543 {
4544  static ULONG initialBufferSize = 0x4000;
4545  NTSTATUS status;
4546  PVOID buffer;
4547  ULONG bufferSize;
4548 
4549  bufferSize = initialBufferSize;
4550  buffer = PhAllocate(bufferSize);
4551 
4552  while ((status = NtQuerySystemInformation(
4554  buffer,
4555  bufferSize,
4556  NULL
4557  )) == STATUS_INFO_LENGTH_MISMATCH)
4558  {
4559  PhFree(buffer);
4560  bufferSize *= 2;
4561 
4562  // Fail if we're resizing the buffer to something very large.
4563  if (bufferSize > PH_LARGE_BUFFER_SIZE)
4564  return STATUS_INSUFFICIENT_RESOURCES;
4565 
4566  buffer = PhAllocate(bufferSize);
4567  }
4568 
4569  if (!NT_SUCCESS(status))
4570  {
4571  PhFree(buffer);
4572  return status;
4573  }
4574 
4575  if (bufferSize <= 0x100000) initialBufferSize = bufferSize;
4576  *Handles = (PSYSTEM_HANDLE_INFORMATION)buffer;
4577 
4578  return status;
4579 }
4580 
4597  _Out_ PSYSTEM_HANDLE_INFORMATION_EX *Handles
4598  )
4599 {
4600  static ULONG initialBufferSize = 0x10000;
4601  NTSTATUS status;
4602  PVOID buffer;
4603  ULONG bufferSize;
4604 
4605  bufferSize = initialBufferSize;
4606  buffer = PhAllocate(bufferSize);
4607 
4608  while ((status = NtQuerySystemInformation(
4610  buffer,
4611  bufferSize,
4612  NULL
4613  )) == STATUS_INFO_LENGTH_MISMATCH)
4614  {
4615  PhFree(buffer);
4616  bufferSize *= 2;
4617 
4618  // Fail if we're resizing the buffer to something very large.
4619  if (bufferSize > PH_LARGE_BUFFER_SIZE)
4620  return STATUS_INSUFFICIENT_RESOURCES;
4621 
4622  buffer = PhAllocate(bufferSize);
4623  }
4624 
4625  if (!NT_SUCCESS(status))
4626  {
4627  PhFree(buffer);
4628  return status;
4629  }
4630 
4631  if (bufferSize <= 0x200000) initialBufferSize = bufferSize;
4632  *Handles = (PSYSTEM_HANDLE_INFORMATION_EX)buffer;
4633 
4634  return status;
4635 }
4636 
4650  _Out_ PVOID *Pagefiles
4651  )
4652 {
4653  NTSTATUS status;
4654  PVOID buffer;
4655  ULONG bufferSize = 0x200;
4656 
4657  buffer = PhAllocate(bufferSize);
4658 
4659  while ((status = NtQuerySystemInformation(
4661  buffer,
4662  bufferSize,
4663  NULL
4664  )) == STATUS_INFO_LENGTH_MISMATCH)
4665  {
4666  PhFree(buffer);
4667  bufferSize *= 2;
4668 
4669  // Fail if we're resizing the buffer to something very large.
4670  if (bufferSize > PH_LARGE_BUFFER_SIZE)
4671  return STATUS_INSUFFICIENT_RESOURCES;
4672 
4673  buffer = PhAllocate(bufferSize);
4674  }
4675 
4676  if (!NT_SUCCESS(status))
4677  {
4678  PhFree(buffer);
4679  return status;
4680  }
4681 
4682  *Pagefiles = buffer;
4683 
4684  return status;
4685 }
4686 
4700  _In_ HANDLE ProcessId,
4701  _Out_ PPH_STRING *FileName
4702  )
4703 {
4704  NTSTATUS status;
4705  PVOID buffer;
4706  ULONG bufferSize = 0x100;
4707  SYSTEM_PROCESS_ID_INFORMATION processIdInfo;
4708 
4709  buffer = PhAllocate(bufferSize);
4710 
4711  processIdInfo.ProcessId = ProcessId;
4712  processIdInfo.ImageName.Length = 0;
4713  processIdInfo.ImageName.MaximumLength = (USHORT)bufferSize;
4714  processIdInfo.ImageName.Buffer = buffer;
4715 
4716  status = NtQuerySystemInformation(
4718  &processIdInfo,
4720  NULL
4721  );
4722 
4723  if (status == STATUS_INFO_LENGTH_MISMATCH)
4724  {
4725  // Required length is stored in MaximumLength.
4726 
4727  PhFree(buffer);
4728  buffer = PhAllocate(processIdInfo.ImageName.MaximumLength);
4729  processIdInfo.ImageName.Buffer = buffer;
4730 
4731  status = NtQuerySystemInformation(
4733  &processIdInfo,
4735  NULL
4736  );
4737  }
4738 
4739  if (!NT_SUCCESS(status))
4740  {
4741  PhFree(buffer);
4742  return status;
4743  }
4744 
4745  *FileName = PhCreateStringFromUnicodeString(&processIdInfo.ImageName);
4746  PhFree(buffer);
4747 
4748  return status;
4749 }
4750 
4759  _In_ HANDLE ProcessId,
4760  _Out_ PBOOLEAN IsDotNet
4761  )
4762 {
4763  return PhGetProcessIsDotNetEx(ProcessId, NULL, 0, IsDotNet, NULL);
4764 }
4765 
4767  _In_ PLDR_DATA_TABLE_ENTRY Module,
4768  _In_opt_ PVOID Context
4769  )
4770 {
4771  static UNICODE_STRING clrString = RTL_CONSTANT_STRING(L"clr.dll");
4772  static UNICODE_STRING mscorwksString = RTL_CONSTANT_STRING(L"mscorwks.dll");
4773  static UNICODE_STRING mscorsvrString = RTL_CONSTANT_STRING(L"mscorsvr.dll");
4774  static UNICODE_STRING mscorlibString = RTL_CONSTANT_STRING(L"mscorlib.dll");
4775  static UNICODE_STRING mscorlibNiString = RTL_CONSTANT_STRING(L"mscorlib.ni.dll");
4776  static UNICODE_STRING frameworkString = RTL_CONSTANT_STRING(L"\\Microsoft.NET\\Framework\\");
4777  static UNICODE_STRING framework64String = RTL_CONSTANT_STRING(L"\\Microsoft.NET\\Framework64\\");
4778 
4779  if (
4780  RtlEqualUnicodeString(&Module->BaseDllName, &clrString, TRUE) ||
4781  RtlEqualUnicodeString(&Module->BaseDllName, &mscorwksString, TRUE) ||
4782  RtlEqualUnicodeString(&Module->BaseDllName, &mscorsvrString, TRUE)
4783  )
4784  {
4785  UNICODE_STRING fileName;
4786  PH_STRINGREF systemRootSr;
4787  UNICODE_STRING systemRoot;
4788  PUNICODE_STRING frameworkPart;
4789 
4790 #ifdef _WIN64
4791  if (*(PULONG)Context & PH_CLR_PROCESS_IS_WOW64)
4792  {
4793 #endif
4794  frameworkPart = &frameworkString;
4795 #ifdef _WIN64
4796  }
4797  else
4798  {
4799  frameworkPart = &framework64String;
4800  }
4801 #endif
4802 
4803  fileName = Module->FullDllName;
4804  PhGetSystemRoot(&systemRootSr);
4805  PhStringRefToUnicodeString(&systemRootSr, &systemRoot);
4806 
4807  if (RtlPrefixUnicodeString(&systemRoot, &fileName, TRUE))
4808  {
4809  fileName.Buffer = (PWCHAR)((PCHAR)fileName.Buffer + systemRoot.Length);
4810  fileName.Length -= systemRoot.Length;
4811 
4812  if (RtlPrefixUnicodeString(frameworkPart, &fileName, TRUE))
4813  {
4814  fileName.Buffer = (PWCHAR)((PCHAR)fileName.Buffer + frameworkPart->Length);
4815  fileName.Length -= frameworkPart->Length;
4816 
4817  if (fileName.Length >= 4 * sizeof(WCHAR)) // vx.x
4818  {
4819  if (fileName.Buffer[1] == '1')
4820  {
4821  if (fileName.Buffer[3] == '0')
4822  *(PULONG)Context |= PH_CLR_VERSION_1_0;
4823  else if (fileName.Buffer[3] == '1')
4824  *(PULONG)Context |= PH_CLR_VERSION_1_1;
4825  }
4826  else if (fileName.Buffer[1] == '2')
4827  {
4828  *(PULONG)Context |= PH_CLR_VERSION_2_0;
4829  }
4830  else if (fileName.Buffer[1] >= '4' && fileName.Buffer[1] <= '9')
4831  {
4832  *(PULONG)Context |= PH_CLR_VERSION_4_ABOVE;
4833  }
4834  }
4835  }
4836  }
4837  }
4838  else if (
4839  RtlEqualUnicodeString(&Module->BaseDllName, &mscorlibString, TRUE) ||
4840  RtlEqualUnicodeString(&Module->BaseDllName, &mscorlibNiString, TRUE)
4841  )
4842  {
4843  *(PULONG)Context |= PH_CLR_MSCORLIB_PRESENT;
4844  }
4845 
4846  return TRUE;
4847 }
4848 
4869  _In_ HANDLE ProcessId,
4870  _In_opt_ HANDLE ProcessHandle,
4871  _In_ ULONG InFlags,
4872  _Out_opt_ PBOOLEAN IsDotNet,
4873  _Out_opt_ PULONG Flags
4874  )
4875 {
4876  NTSTATUS status = STATUS_SUCCESS;
4877  HANDLE processHandle;
4878  ULONG flags;
4879 #ifdef _WIN64
4880  BOOLEAN isWow64;
4881 #endif
4882 
4883  if (InFlags & PH_CLR_USE_SECTION_CHECK)
4884  {
4885  HANDLE sectionHandle;
4886  OBJECT_ATTRIBUTES objectAttributes;
4887  PPH_STRING sectionName;
4888  UNICODE_STRING sectionNameUs;
4889  PH_FORMAT format[2];
4890 
4891  // Most .NET processes have a handle open to a section named
4892  // \BaseNamedObjects\Cor_Private_IPCBlock(_v4)_<ProcessId>.
4893  // This is the same object used by the ICorPublish::GetProcess
4894  // function. Instead of calling that function, we simply check
4895  // for the existence of that section object. This means:
4896  // * Better performance.
4897  // * No need for admin rights to get .NET status of processes
4898  // owned by other users.
4899 
4900  PhInitFormatIU(&format[1], (ULONG_PTR)ProcessId);
4901 
4902  // Version 4 section object
4903 
4904  PhInitFormatS(&format[0], L"\\BaseNamedObjects\\Cor_Private_IPCBlock_v4_");
4905  sectionName = PhFormat(format, 2, 96);
4906  PhStringRefToUnicodeString(&sectionName->sr, &sectionNameUs);
4907 
4909  &objectAttributes,
4910  &sectionNameUs,
4912  NULL,
4913  NULL
4914  );
4915  status = NtOpenSection(
4916  &sectionHandle,
4917  SECTION_QUERY,
4918  &objectAttributes
4919  );
4920  PhDereferenceObject(sectionName);
4921 
4922  if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED)
4923  {
4924  if (NT_SUCCESS(status))
4925  NtClose(sectionHandle);
4926 
4927  if (IsDotNet)
4928  *IsDotNet = TRUE;
4929 
4930  if (Flags)
4931  *Flags = PH_CLR_VERSION_4_ABOVE;
4932 
4933  return STATUS_SUCCESS;
4934  }
4935 
4936  // Version 2 section object
4937 
4938  PhInitFormatS(&format[0], L"\\BaseNamedObjects\\Cor_Private_IPCBlock_");
4939  sectionName = PhFormat(format, 2, 90);
4940  PhStringRefToUnicodeString(&sectionName->sr, &sectionNameUs);
4941 
4943  &objectAttributes,
4944  &sectionNameUs,
4946  NULL,
4947  NULL
4948  );
4949  status = NtOpenSection(
4950  &sectionHandle,
4951  SECTION_QUERY,
4952  &objectAttributes
4953  );
4954  PhDereferenceObject(sectionName);
4955 
4956  if (NT_SUCCESS(status) || status == STATUS_ACCESS_DENIED)
4957  {
4958  if (NT_SUCCESS(status))
4959  NtClose(sectionHandle);
4960 
4961  if (IsDotNet)
4962  *IsDotNet = TRUE;
4963 
4964  if (Flags)
4965  *Flags = PH_CLR_VERSION_2_0;
4966 
4967  return STATUS_SUCCESS;
4968  }
4969  }
4970 
4971  flags = 0;
4972  processHandle = NULL;
4973 
4974  if (!ProcessHandle)
4975  {
4976  if (!NT_SUCCESS(status = PhOpenProcess(&processHandle, ProcessQueryAccess | PROCESS_VM_READ, ProcessId)))
4977  return status;
4978 
4979  ProcessHandle = processHandle;
4980  }
4981 
4982 #ifdef _WIN64
4983  if (InFlags & PH_CLR_NO_WOW64_CHECK)
4984  {
4985  isWow64 = !!(InFlags & PH_CLR_KNOWN_IS_WOW64);
4986  }
4987  else
4988  {
4989  isWow64 = FALSE;
4990  PhGetProcessIsWow64(ProcessHandle, &isWow64);
4991  }
4992 
4993  if (isWow64)
4994  {
4995  flags |= PH_CLR_PROCESS_IS_WOW64;
4997  }
4998  else
4999  {
5000 #endif
5002 #ifdef _WIN64
5003  }
5004 #endif
5005 
5006  if (processHandle)
5007  NtClose(processHandle);
5008 
5009  if (IsDotNet)
5010  *IsDotNet = (flags & PH_CLR_VERSION_MASK) && (flags & PH_CLR_MSCORLIB_PRESENT);
5011 
5012  if (Flags)
5013  *Flags = flags;
5014 
5015  return status;
5016 }
5017 
5029  _In_ HANDLE DirectoryHandle,
5030  _In_ PPH_ENUM_DIRECTORY_OBJECTS Callback,
5031  _In_opt_ PVOID Context
5032  )
5033 {
5034  NTSTATUS status;
5035  ULONG context = 0;
5036  BOOLEAN firstTime = TRUE;
5037  ULONG bufferSize;
5038  POBJECT_DIRECTORY_INFORMATION buffer;
5039  ULONG i;
5040  BOOLEAN cont;
5041 
5042  bufferSize = 0x200;
5043  buffer = PhAllocate(bufferSize);
5044 
5045  while (TRUE)
5046  {
5047  // Get a batch of entries.
5048 
5049  while ((status = NtQueryDirectoryObject(
5050  DirectoryHandle,
5051  buffer,
5052  bufferSize,
5053  FALSE,
5054  firstTime,
5055  &context,
5056  NULL
5057  )) == STATUS_MORE_ENTRIES)
5058  {
5059  // Check if we have at least one entry. If not,
5060  // we'll double the buffer size and try again.
5061  if (buffer[0].Name.Buffer)
5062  break;
5063 
5064  // Make sure we don't use too much memory.
5065  if (bufferSize > PH_LARGE_BUFFER_SIZE)
5066  {
5067  PhFree(buffer);
5068  return STATUS_INSUFFICIENT_RESOURCES;
5069  }
5070 
5071  PhFree(buffer);
5072  bufferSize *= 2;
5073  buffer = PhAllocate(bufferSize);
5074  }
5075 
5076  if (!NT_SUCCESS(status))
5077  {
5078  PhFree(buffer);
5079  return status;
5080  }
5081 
5082  // Read the batch and execute the callback function
5083  // for each object.
5084 
5085  i = 0;
5086  cont = TRUE;
5087 
5088  while (TRUE)
5089  {
5090  POBJECT_DIRECTORY_INFORMATION info;
5091  PH_STRINGREF name;
5092  PH_STRINGREF typeName;
5093 
5094  info = &buffer[i];
5095 
5096  if (!info->Name.Buffer)
5097  break;
5098 
5099  PhUnicodeStringToStringRef(&info->Name, &name);
5100  PhUnicodeStringToStringRef(&info->TypeName, &typeName);
5101 
5102  cont = Callback(&name, &typeName, Context);
5103 
5104  if (!cont)
5105  break;
5106 
5107  i++;
5108  }
5109 
5110  if (!cont)
5111  break;
5112 
5113  if (status != STATUS_MORE_ENTRIES)
5114  break;
5115 
5116  firstTime = FALSE;
5117  }
5118 
5119  PhFree(buffer);
5120 
5121  return STATUS_SUCCESS;
5122 }
5123 
5125  _In_ HANDLE FileHandle,
5126  _In_opt_ PUNICODE_STRING SearchPattern,
5127  _In_ PPH_ENUM_DIRECTORY_FILE Callback,
5128  _In_opt_ PVOID Context
5129  )
5130 {
5131  NTSTATUS status;
5132  IO_STATUS_BLOCK isb;
5133  BOOLEAN firstTime = TRUE;
5134  PVOID buffer;
5135  ULONG bufferSize = 0x400;
5136  ULONG i;
5137  BOOLEAN cont;
5138 
5139  buffer = PhAllocate(bufferSize);
5140 
5141  while (TRUE)
5142  {
5143  // Query the directory, doubling the buffer each time NtQueryDirectoryFile
5144  // fails.
5145  while (TRUE)
5146  {
5147  status = NtQueryDirectoryFile(
5148  FileHandle,
5149  NULL,
5150  NULL,
5151  NULL,
5152  &isb,
5153  buffer,
5154  bufferSize,
5156  FALSE,
5157  SearchPattern,
5158  firstTime
5159  );
5160 
5161  // Our ISB is on the stack, so we have to wait for the operation to
5162  // complete before continuing.
5163  if (status == STATUS_PENDING)
5164  {
5165  status = NtWaitForSingleObject(FileHandle, FALSE, NULL);
5166 
5167  if (NT_SUCCESS(status))
5168  status = isb.Status;
5169  }
5170 
5171  if (status == STATUS_BUFFER_OVERFLOW || status == STATUS_INFO_LENGTH_MISMATCH)
5172  {
5173  PhFree(buffer);
5174  bufferSize *= 2;
5175  buffer = PhAllocate(bufferSize);
5176  }
5177  else
5178  {
5179  break;
5180  }
5181  }
5182 
5183  // If we don't have any entries to read, exit.
5184  if (status == STATUS_NO_MORE_FILES)
5185  {
5186  status = STATUS_SUCCESS;
5187  break;
5188  }
5189 
5190  if (!NT_SUCCESS(status))
5191  break;
5192 
5193  // Read the batch and execute the callback function
5194  // for each file.
5195 
5196  i = 0;
5197  cont = TRUE;
5198 
5199  while (TRUE)
5200  {
5201  PFILE_DIRECTORY_INFORMATION information;
5202 
5203  information = (PFILE_DIRECTORY_INFORMATION)(PTR_ADD_OFFSET(buffer, i));
5204 
5205  if (!Callback(
5206  information,
5207  Context
5208  ))
5209  {
5210  cont = FALSE;
5211  break;
5212  }
5213 
5214  if (information->NextEntryOffset != 0)
5215  i += information->NextEntryOffset;
5216  else
5217  break;
5218  }
5219 
5220  if (!cont)
5221  break;
5222 
5223  firstTime = FALSE;
5224  }
5225 
5226  PhFree(buffer);
5227 
5228  return status;
5229 }
5230 
5232  _In_ HANDLE FileHandle,
5233  _Out_ PVOID *Streams
5234  )
5235 {
5236  return PhpQueryFileVariableSize(
5237  FileHandle,
5239  Streams
5240  );
5241 }
5242 
5247  VOID
5248  )
5249 {
5250  ULONG i;
5251  PUCHAR buffer;
5252 
5253  // Allocate one buffer for all 26 prefixes to reduce overhead.
5254  buffer = PhAllocate(PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR) * 26);
5255 
5256  for (i = 0; i < 26; i++)
5257  {
5258  PhDevicePrefixes[i].Length = 0;
5259  PhDevicePrefixes[i].MaximumLength = PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR);
5260  PhDevicePrefixes[i].Buffer = (PWCHAR)buffer;
5261  buffer += PH_DEVICE_PREFIX_LENGTH * sizeof(WCHAR);
5262  }
5263 }
5264 
5266  VOID
5267  )
5268 {
5269  static PH_STRINGREF orderKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Control\\NetworkProvider\\Order");
5270  static PH_STRINGREF servicesStringPart = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\");
5271  static PH_STRINGREF networkProviderStringPart = PH_STRINGREF_INIT(L"\\NetworkProvider");
5272 
5273  HANDLE orderKeyHandle;
5274  PPH_STRING providerOrder = NULL;
5275  ULONG i;
5276  PH_STRINGREF remainingPart;
5277  PH_STRINGREF part;
5278 
5279  // The provider names are stored in the ProviderOrder value in this key:
5280  // HKLM\System\CurrentControlSet\Control\NetworkProvider\Order
5281  // Each name can then be looked up, its device name in the DeviceName value in:
5282  // HKLM\System\CurrentControlSet\Services<ProviderName>\NetworkProvider
5283 
5284  // Note that we assume the providers only claim their device name. Some providers
5285  // such as DFS claim an extra part, and are not resolved correctly here.
5286 
5287  if (NT_SUCCESS(PhOpenKey(
5288  &orderKeyHandle,
5289  KEY_READ,
5291  &orderKeyName,
5292  0
5293  )))
5294  {
5295  providerOrder = PhQueryRegistryString(orderKeyHandle, L"ProviderOrder");
5296  NtClose(orderKeyHandle);
5297  }
5298 
5299  if (!providerOrder)
5300  return;
5301 
5302  PhAcquireQueuedLockExclusive(&PhDeviceMupPrefixesLock);
5303 
5304  for (i = 0; i < PhDeviceMupPrefixesCount; i++)
5305  {
5306  PhDereferenceObject(PhDeviceMupPrefixes[i]);
5307  PhDeviceMupPrefixes[i] = NULL;
5308  }
5309 
5310  PhDeviceMupPrefixesCount = 0;
5311 
5312  PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\Mup");
5313 
5314  // DFS claims an extra part of file names, which we don't handle.
5315  /*if (WindowsVersion >= WINDOWS_VISTA)
5316  PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\DfsClient");
5317  else
5318  PhDeviceMupPrefixes[PhDeviceMupPrefixesCount++] = PhCreateString(L"\\Device\\WinDfs");*/
5319 
5320  remainingPart = providerOrder->sr;
5321 
5322  while (remainingPart.Length != 0)
5323  {
5324  PPH_STRING serviceKeyName;
5325  HANDLE networkProviderKeyHandle;
5326  PPH_STRING deviceName;
5327 
5328  if (PhDeviceMupPrefixesCount == PH_DEVICE_MUP_PREFIX_MAX_COUNT)
5329  break;
5330 
5331  PhSplitStringRefAtChar(&remainingPart, ',', &part, &remainingPart);
5332 
5333  if (part.Length != 0)
5334  {
5335  serviceKeyName = PhConcatStringRef3(&servicesStringPart, &part, &networkProviderStringPart);
5336 
5337  if (NT_SUCCESS(PhOpenKey(
5338  &networkProviderKeyHandle,
5339  KEY_READ,
5341  &serviceKeyName->sr,
5342  0
5343  )))
5344  {
5345  if (deviceName = PhQueryRegistryString(networkProviderKeyHandle, L"DeviceName"))
5346  {
5347  PhDeviceMupPrefixes[PhDeviceMupPrefixesCount] = deviceName;
5348  PhDeviceMupPrefixesCount++;
5349  }
5350 
5351  NtClose(networkProviderKeyHandle);
5352  }
5353 
5354  PhDereferenceObject(serviceKeyName);
5355  }
5356  }
5357 
5358  PhReleaseQueuedLockExclusive(&PhDeviceMupPrefixesLock);
5359 
5360  PhDereferenceObject(providerOrder);
5361 }
5362 
5367  VOID
5368  )
5369 {
5370  WCHAR deviceNameBuffer[7] = L"\\??\\ :";
5371  ULONG i;
5372 
5373  for (i = 0; i < 26; i++)
5374  {
5375  HANDLE linkHandle;
5376  OBJECT_ATTRIBUTES oa;
5377  UNICODE_STRING deviceName;
5378 
5379  deviceNameBuffer[4] = (WCHAR)('A' + i);
5380  deviceName.Buffer = deviceNameBuffer;
5381  deviceName.Length = 6 * sizeof(WCHAR);
5382 
5384  &oa,
5385  &deviceName,
5387  NULL,
5388  NULL
5389  );
5390 
5391  if (NT_SUCCESS(NtOpenSymbolicLinkObject(
5392  &linkHandle,
5393  SYMBOLIC_LINK_QUERY,
5394  &oa
5395  )))
5396  {
5397  PhAcquireQueuedLockExclusive(&PhDevicePrefixesLock);
5398 
5399  if (!NT_SUCCESS(NtQuerySymbolicLinkObject(
5400  linkHandle,
5401  &PhDevicePrefixes[i],
5402  NULL
5403  )))
5404  {
5405  PhDevicePrefixes[i].Length = 0;
5406  }
5407 
5408  PhReleaseQueuedLockExclusive(&PhDevicePrefixesLock);
5409 
5410  NtClose(linkHandle);
5411  }
5412  else
5413  {
5414  PhDevicePrefixes[i].Length = 0;
5415  }
5416  }
5417 }
5418 
5429  _In_ PPH_STRING Name
5430  )
5431 {
5432  ULONG i;
5433  PPH_STRING newName = NULL;
5434 
5435  if (PhBeginInitOnce(&PhDevicePrefixesInitOnce))
5436  {
5440 
5441  PhEndInitOnce(&PhDevicePrefixesInitOnce);
5442  }
5443 
5444  // Go through the DOS devices and try to find a matching prefix.
5445  for (i = 0; i < 26; i++)
5446  {
5447  BOOLEAN isPrefix = FALSE;
5448  PH_STRINGREF prefix;
5449 
5450  PhAcquireQueuedLockShared(&PhDevicePrefixesLock);
5451 
5452  PhUnicodeStringToStringRef(&PhDevicePrefixes[i], &prefix);
5453 
5454  if (prefix.Length != 0)
5455  {
5456  if (PhStartsWithStringRef(&Name->sr, &prefix, TRUE))
5457  {
5458  // To ensure we match the longest prefix, make sure the next character is a backslash or
5459  // the path is equal to the prefix.
5460  if (Name->Length == prefix.Length || Name->Buffer[prefix.Length / sizeof(WCHAR)] == '\\')
5461  {
5462  isPrefix = TRUE;
5463  }
5464  }
5465  }
5466 
5467  PhReleaseQueuedLockShared(&PhDevicePrefixesLock);
5468 
5469  if (isPrefix)
5470  {
5471  // <letter>:path
5472  newName = PhCreateStringEx(NULL, 2 * sizeof(WCHAR) + Name->Length - prefix.Length);
5473  newName->Buffer[0] = (WCHAR)('A' + i);
5474  newName->Buffer[1] = ':';
5475  memcpy(
5476  &newName->Buffer[2],
5477  &Name->Buffer[prefix.Length / sizeof(WCHAR)],
5478  Name->Length - prefix.Length
5479  );
5480 
5481  break;
5482  }
5483  }
5484 
5485  if (i == 26)
5486  {
5487  // Resolve network providers.
5488 
5489  PhAcquireQueuedLockShared(&PhDeviceMupPrefixesLock);
5490 
5491  for (i = 0; i < PhDeviceMupPrefixesCount; i++)
5492  {
5493  BOOLEAN isPrefix = FALSE;
5494  SIZE_T prefixLength;
5495 
5496  prefixLength = PhDeviceMupPrefixes[i]->Length;
5497 
5498  if (prefixLength != 0)
5499  {
5500  if (PhStartsWithString(Name, PhDeviceMupPrefixes[i], TRUE))
5501  {
5502  // To ensure we match the longest prefix, make sure the next character is a backslash.
5503  // Don't resolve if the name *is* the prefix. Otherwise, we will end up with a useless
5504  // string like "\".
5505  if (Name->Length != prefixLength && Name->Buffer[prefixLength / sizeof(WCHAR)] == '\\')
5506  {
5507  isPrefix = TRUE;
5508  }
5509  }
5510  }
5511 
5512  if (isPrefix)
5513  {
5514  // \path
5515  newName = PhCreateStringEx(NULL, 1 * sizeof(WCHAR) + Name->Length - prefixLength);
5516  newName->Buffer[0] = '\\';
5517  memcpy(
5518  &newName->Buffer[1],
5519  &Name->Buffer[prefixLength / sizeof(WCHAR)],
5520  Name->Length - prefixLength
5521  );
5522 
5523  break;
5524  }
5525  }
5526 
5527  PhReleaseQueuedLockShared(&PhDeviceMupPrefixesLock);
5528  }
5529 
5530  return newName;
5531 }
5532 
5548  _In_ PPH_STRING FileName
5549  )
5550 {
5551  PPH_STRING newFileName;
5552 
5553  newFileName = FileName;
5554 
5555  // "\??\" refers to \GLOBAL??\. Just remove it.
5556  if (PhStartsWithString2(FileName, L"\\??\\", FALSE))
5557  {
5558  newFileName = PhCreateStringEx(NULL, FileName->Length - 4 * 2);
5559  memcpy(newFileName->Buffer, &FileName->Buffer[4], FileName->Length - 4 * 2);
5560  }
5561  // "\SystemRoot" means "C:\Windows".
5562  else if (PhStartsWithString2(FileName, L"\\SystemRoot", TRUE))
5563  {
5564  PH_STRINGREF systemRoot;
5565 
5566  PhGetSystemRoot(&systemRoot);
5567  newFileName = PhCreateStringEx(NULL, systemRoot.Length + FileName->Length - 11 * 2);
5568  memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length);
5569  memcpy((PCHAR)newFileName->Buffer + systemRoot.Length, &FileName->Buffer[11], FileName->Length - 11 * 2);
5570  }
5571  // "system32\" means "C:\Windows\system32\".
5572  else if (PhStartsWithString2(FileName, L"system32\\", TRUE))
5573  {
5574  PH_STRINGREF systemRoot;
5575 
5576  PhGetSystemRoot(&systemRoot);
5577  newFileName = PhCreateStringEx(NULL, systemRoot.Length + 2 + FileName->Length);
5578  memcpy(newFileName->Buffer, systemRoot.Buffer, systemRoot.Length);
5579  newFileName->Buffer[systemRoot.Length / 2] = '\\';
5580  memcpy((PCHAR)newFileName->Buffer + systemRoot.Length + 2, FileName->Buffer, FileName->Length);
5581  }
5582  else if (FileName->Length != 0 && FileName->Buffer[0] == '\\')
5583  {
5584  PPH_STRING resolvedName;
5585 
5586  resolvedName = PhResolveDevicePrefix(FileName);
5587 
5588  if (resolvedName)
5589  {
5590  newFileName = resolvedName;
5591  }
5592  else
5593  {
5594  // We didn't find a match.
5595  // If the file name starts with "\Windows", prepend the system drive.
5596  if (PhStartsWithString2(newFileName, L"\\Windows", TRUE))
5597  {
5598  newFileName = PhCreateStringEx(NULL, FileName->Length + 2 * 2);
5599  newFileName->Buffer[0] = USER_SHARED_DATA->NtSystemRoot[0];
5600  newFileName->Buffer[1] = ':';
5601  memcpy(&newFileName->Buffer[2], FileName->Buffer, FileName->Length);
5602  }
5603  else
5604  {
5605  PhReferenceObject(newFileName);
5606  }
5607  }
5608  }
5609  else
5610  {
5611  // Just return the supplied file name. Note that we need
5612  // to add a reference.
5613  PhReferenceObject(newFileName);
5614  }
5615 
5616  return newFileName;
5617 }
5618 
5619 typedef struct _ENUM_GENERIC_PROCESS_MODULES_CONTEXT
5620 {
5622  PVOID Context;
5623  ULONG Type;
5624  PPH_HASHTABLE BaseAddressHashtable;
5625 
5626  ULONG LoadOrderIndex;
5628 
5629 static BOOLEAN EnumGenericProcessModulesCallback(
5630  _In_ PLDR_DATA_TABLE_ENTRY Module,
5631  _In_opt_ PVOID Context
5632  )
5633 {
5634  PENUM_GENERIC_PROCESS_MODULES_CONTEXT context;
5635  PH_MODULE_INFO moduleInfo;
5636  PPH_STRING fileName;
5637  BOOLEAN cont;
5638 
5639  context = (PENUM_GENERIC_PROCESS_MODULES_CONTEXT)Context;
5640 
5641  // Check if we have a duplicate base address.
5642  if (PhFindEntryHashtable(context->BaseAddressHashtable, &Module->DllBase))
5643  {
5644  return TRUE;
5645  }
5646  else
5647  {
5648  PhAddEntryHashtable(context->BaseAddressHashtable, &Module->DllBase);
5649  }
5650 
5651  fileName = PhCreateStringFromUnicodeString(&Module->FullDllName);
5652 
5653  moduleInfo.Type = context->Type;
5654  moduleInfo.BaseAddress = Module->DllBase;
5655  moduleInfo.Size = Module->SizeOfImage;
5656  moduleInfo.EntryPoint = Module->EntryPoint;
5657  moduleInfo.Flags = Module->Flags;
5658  moduleInfo.Name = PhCreateStringFromUnicodeString(&Module->BaseDllName);
5659  moduleInfo.FileName = PhGetFileName(fileName);
5660  moduleInfo.LoadOrderIndex = (USHORT)(context->LoadOrderIndex++);
5661  moduleInfo.LoadCount = Module->ObsoleteLoadCount;
5662 
5663  if (WindowsVersion >= WINDOWS_8)
5664  {
5665  moduleInfo.LoadReason = (USHORT)Module->LoadReason;
5666  moduleInfo.LoadTime = Module->LoadTime;
5667  }
5668  else
5669  {
5670  moduleInfo.LoadReason = -1;
5671  moduleInfo.LoadTime.QuadPart = 0;
5672  }
5673 
5674  PhDereferenceObject(fileName);
5675 
5676  cont = context->Callback(&moduleInfo, context->Context);
5677 
5678  PhDereferenceObject(moduleInfo.Name);
5679  PhDereferenceObject(moduleInfo.FileName);
5680 
5681  return cont;
5682 }
5683 
5685  _In_ PRTL_PROCESS_MODULES Modules,
5686  _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,
5687  _In_opt_ PVOID Context,
5688  _In_ PPH_HASHTABLE BaseAddressHashtable
5689  )
5690 {
5692  ULONG i;
5693  PH_MODULE_INFO moduleInfo;
5694  BOOLEAN cont;
5695 
5696  for (i = 0; i < Modules->NumberOfModules; i++)
5697  {
5698  PPH_STRING fileName;
5699 
5700  module = &Modules->Modules[i];
5701 
5702  // Check if we have a duplicate base address.
5703  if (PhFindEntryHashtable(BaseAddressHashtable, &module->ImageBase))
5704  {
5705  continue;
5706  }
5707  else
5708  {
5709  PhAddEntryHashtable(BaseAddressHashtable, &module->ImageBase);
5710  }
5711 
5712  fileName = PhConvertMultiByteToUtf16(module->FullPathName);
5713 
5714  if ((ULONG_PTR)module->ImageBase <= PhSystemBasicInformation.MaximumUserModeAddress)
5715  moduleInfo.Type = PH_MODULE_TYPE_MODULE;
5716  else
5717  moduleInfo.Type = PH_MODULE_TYPE_KERNEL_MODULE;
5718 
5719  moduleInfo.BaseAddress = module->ImageBase;
5720  moduleInfo.Size = module->ImageSize;
5721  moduleInfo.EntryPoint = NULL;
5722  moduleInfo.Flags = module->Flags;
5723  moduleInfo.Name = PhConvertMultiByteToUtf16(&module->FullPathName[module->OffsetToFileName]);
5724  moduleInfo.FileName = PhGetFileName(fileName); // convert to DOS file name
5725  moduleInfo.LoadOrderIndex = module->LoadOrderIndex;
5726  moduleInfo.LoadCount = module->LoadCount;
5727  moduleInfo.LoadReason = -1;
5728  moduleInfo.LoadTime.QuadPart = 0;
5729 
5730  PhDereferenceObject(fileName);
5731 
5732  if (module->OffsetToFileName == 0)
5733  {
5734  static PH_STRINGREF driversString = PH_STRINGREF_INIT(L"\\System32\\Drivers\\");
5735  PH_STRINGREF systemRoot;
5736  PPH_STRING newFileName;
5737 
5738  // We only have the file name, without a path. The driver must be in the
5739  // default drivers directory.
5740  PhGetSystemRoot(&systemRoot);
5741  newFileName = PhConcatStringRef3(&systemRoot, &driversString, &moduleInfo.Name->sr);
5742  PhDereferenceObject(moduleInfo.FileName);
5743  moduleInfo.FileName = newFileName;
5744  }
5745 
5746  cont = Callback(&moduleInfo, Context);
5747 
5748  PhDereferenceObject(moduleInfo.Name);
5749  PhDereferenceObject(moduleInfo.FileName);
5750 
5751  if (!cont)
5752  break;
5753  }
5754 }
5755 
5758  _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,
5759  _In_opt_ PVOID Context,
5760  _In_ PPH_HASHTABLE BaseAddressHashtable
5761  )
5762 {
5764  PH_MODULE_INFO moduleInfo;
5765  BOOLEAN cont;
5766 
5767  module = Modules;
5768 
5769  while (module->NextOffset != 0)
5770  {
5771  PPH_STRING fileName;
5772 
5773  // Check if we have a duplicate base address.
5774  if (PhFindEntryHashtable(BaseAddressHashtable, &module->BaseInfo.ImageBase))
5775  {
5776  continue;
5777  }
5778  else
5779  {
5780  PhAddEntryHashtable(BaseAddressHashtable, &module->BaseInfo.ImageBase);
5781  }
5782 
5783  fileName = PhConvertMultiByteToUtf16(module->BaseInfo.FullPathName);
5784 
5786  moduleInfo.Type = PH_MODULE_TYPE_MODULE;
5787  else
5788  moduleInfo.Type = PH_MODULE_TYPE_KERNEL_MODULE;
5789 
5790  moduleInfo.BaseAddress = module->BaseInfo.ImageBase;
5791  moduleInfo.Size = module->BaseInfo.ImageSize;
5792  moduleInfo.EntryPoint = NULL;
5793  moduleInfo.Flags = module->BaseInfo.Flags;
5795  moduleInfo.FileName = PhGetFileName(fileName); // convert to DOS file name
5796  moduleInfo.LoadOrderIndex = module->BaseInfo.LoadOrderIndex;
5797  moduleInfo.LoadCount = module->BaseInfo.LoadCount;
5798  moduleInfo.LoadReason = -1;
5799  moduleInfo.LoadTime.QuadPart = 0;
5800 
5801  PhDereferenceObject(fileName);
5802 
5803  cont = Callback(&moduleInfo, Context);
5804 
5805  PhDereferenceObject(moduleInfo.Name);
5806  PhDereferenceObject(moduleInfo.FileName);
5807 
5808  if (!cont)
5809  break;
5810 
5811  module = PTR_ADD_OFFSET(module, module->NextOffset);
5812  }
5813 }
5814 
5816  _In_ PVOID AllocationBase,
5817  _In_ SIZE_T AllocationSize,
5818  _In_ ULONG Type,
5819  _In_ PPH_STRING FileName,
5820  _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,
5821  _In_opt_ PVOID Context,
5822  _In_ PPH_HASHTABLE BaseAddressHashtable
5823  )
5824 {
5825  PH_MODULE_INFO moduleInfo;
5826  BOOLEAN cont;
5827 
5828  moduleInfo.Type = Type;
5829  moduleInfo.BaseAddress = AllocationBase;
5830  moduleInfo.Size = (ULONG)AllocationSize;
5831  moduleInfo.EntryPoint = NULL;
5832  moduleInfo.Flags = 0;
5833  moduleInfo.FileName = PhGetFileName(FileName);
5834  moduleInfo.Name = PhGetBaseName(moduleInfo.FileName);
5835  moduleInfo.LoadOrderIndex = -1;
5836  moduleInfo.LoadCount = -1;
5837  moduleInfo.LoadReason = -1;
5838  moduleInfo.LoadTime.QuadPart = 0;
5839 
5840  cont = Callback(&moduleInfo, Context);
5841 
5842  PhDereferenceObject(moduleInfo.FileName);
5843  PhDereferenceObject(moduleInfo.Name);
5844 
5845  return cont;
5846 }
5847 
5849  _In_ HANDLE ProcessHandle,
5850  _In_ ULONG Flags,
5851  _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,
5852  _In_opt_ PVOID Context,
5853  _In_ PPH_HASHTABLE BaseAddressHashtable
5854  )
5855 {
5856  BOOLEAN querySucceeded;
5857  PVOID baseAddress;
5858  MEMORY_BASIC_INFORMATION basicInfo;
5859 
5860  baseAddress = (PVOID)0;
5861 
5863  ProcessHandle,
5864  baseAddress,
5866  &basicInfo,
5867  sizeof(MEMORY_BASIC_INFORMATION),
5868  NULL
5869  )))
5870  {
5871  return;
5872  }
5873 
5874  querySucceeded = TRUE;
5875 
5876  while (querySucceeded)
5877  {
5878  PVOID allocationBase;
5879  SIZE_T allocationSize;
5880  ULONG type;
5881  PPH_STRING fileName;
5882  BOOLEAN cont;
5883 
5884  if (basicInfo.Type == MEM_MAPPED || basicInfo.Type == MEM_IMAGE)
5885  {
5886  if (basicInfo.Type == MEM_MAPPED)
5888  else
5890 
5891  // Find the total allocation size.
5892 
5893  allocationBase = basicInfo.AllocationBase;
5894  allocationSize = 0;
5895 
5896  do
5897  {
5898  baseAddress = (PVOID)((ULONG_PTR)baseAddress + basicInfo.RegionSize);
5899  allocationSize += basicInfo.RegionSize;
5900 
5902  ProcessHandle,
5903  baseAddress,
5905  &basicInfo,
5906  sizeof(MEMORY_BASIC_INFORMATION),
5907  NULL
5908  )))
5909  {
5910  querySucceeded = FALSE;
5911  break;
5912  }
5913  } while (basicInfo.AllocationBase == allocationBase);
5914 
5915  if ((type == PH_MODULE_TYPE_MAPPED_FILE && !(Flags & PH_ENUM_GENERIC_MAPPED_FILES)) ||
5917  {
5918  // The user doesn't want this type of entry.
5919  continue;
5920  }
5921 
5922  // Check if we have a duplicate base address.
5923  if (PhFindEntryHashtable(BaseAddressHashtable, &allocationBase))
5924  {
5925  continue;
5926  }
5927 
5929  ProcessHandle,
5930  allocationBase,
5931  &fileName
5932  )))
5933  {
5934  continue;
5935  }
5936 
5937  PhAddEntryHashtable(BaseAddressHashtable, &allocationBase);
5938 
5940  allocationBase,
5941  allocationSize,
5942  type,
5943  fileName,
5944  Callback,
5945  Context,
5946  BaseAddressHashtable
5947  );
5948 
5949  PhDereferenceObject(fileName);
5950 
5951  if (!cont)
5952  break;
5953  }
5954  else
5955  {
5956  baseAddress = (PVOID)((ULONG_PTR)baseAddress + basicInfo.RegionSize);
5957 
5959  ProcessHandle,
5960  baseAddress,
5962  &basicInfo,
5963  sizeof(MEMORY_BASIC_INFORMATION),
5964  NULL
5965  )))
5966  {
5967  querySucceeded = FALSE;
5968  }
5969  }
5970  }
5971 }
5972 
5974  _In_ PVOID Entry1,
5975  _In_ PVOID Entry2
5976  )
5977 {
5978  return *(PVOID *)Entry1 == *(PVOID *)Entry2;
5979 }
5980 
5982  _In_ PVOID Entry
5983  )
5984 {
5985  return PhHashIntPtr((ULONG_PTR)*(PVOID *)Entry);
5986 }
5987 
6007  _In_ HANDLE ProcessId,
6008  _In_opt_ HANDLE ProcessHandle,
6009  _In_ ULONG Flags,
6010  _In_ PPH_ENUM_GENERIC_MODULES_CALLBACK Callback,
6011  _In_opt_ PVOID Context
6012  )
6013 {
6014  NTSTATUS status;
6015  PPH_HASHTABLE baseAddressHashtable;
6016 
6017  baseAddressHashtable = PhCreateHashtable(
6018  sizeof(PVOID),
6021  32
6022  );
6023 
6024  if (ProcessId == SYSTEM_PROCESS_ID)
6025  {
6026  // Kernel modules
6027 
6028  PVOID modules;
6029 
6030  if (NT_SUCCESS(status = PhEnumKernelModules((PRTL_PROCESS_MODULES *)&modules)))
6031  {
6033  modules,
6034  Callback,
6035  Context,
6036  baseAddressHashtable
6037  );
6038  PhFree(modules);
6039  }
6040  }
6041  else
6042  {
6043  // Process modules
6044 
6045  BOOLEAN opened = FALSE;
6046 #ifdef _WIN64
6047  BOOLEAN isWow64 = FALSE;
6048 #endif
6051 
6052  if (!ProcessHandle)
6053  {
6054  if (!NT_SUCCESS(status = PhOpenProcess(
6055  &ProcessHandle,
6056  PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, // needed for enumerating mapped files
6057  ProcessId
6058  )))
6059  {
6060  if (!NT_SUCCESS(status = PhOpenProcess(
6061  &ProcessHandle,
6063  ProcessId
6064  )))
6065  {
6066  goto CleanupExit;
6067  }
6068  }
6069 
6070  opened = TRUE;
6071  }
6072 
6073  context.Callback = Callback;
6074  context.Context = Context;
6075  context.Type = PH_MODULE_TYPE_MODULE;
6076  context.BaseAddressHashtable = baseAddressHashtable;
6077  context.LoadOrderIndex = 0;
6078 
6079  parameters.Callback = EnumGenericProcessModulesCallback;
6080  parameters.Context = &context;
6082 
6083  status = PhEnumProcessModulesEx(
6084  ProcessHandle,
6085  &parameters
6086  );
6087 
6088 #ifdef _WIN64
6089  PhGetProcessIsWow64(ProcessHandle, &isWow64);
6090 
6091  // 32-bit process modules
6092  if (isWow64)
6093  {
6094  context.Callback = Callback;
6095  context.Context = Context;
6096  context.Type = PH_MODULE_TYPE_WOW64_MODULE;
6097  context.BaseAddressHashtable = baseAddressHashtable;
6098  context.LoadOrderIndex = 0;
6099 
6100  status = PhEnumProcessModules32Ex(
6101  ProcessHandle,
6102  &parameters
6103  );
6104  }
6105 #endif
6106 
6107  // Mapped files and mapped images
6108  // This is done last because it provides the least amount of information.
6109 
6111  {
6113  ProcessHandle,
6114  Flags,
6115  Callback,
6116  Context,
6117  baseAddressHashtable
6118  );
6119  }
6120 
6121  if (opened)
6122  NtClose(ProcessHandle);
6123  }
6124 
6125 CleanupExit:
6126  PhDereferenceObject(baseAddressHashtable);
6127 
6128  return status;
6129 }
6130 
6135  VOID
6136  )
6137 {
6138  static UNICODE_STRING currentUserPrefix = RTL_CONSTANT_STRING(L"\\Registry\\User\\");
6139 
6140  NTSTATUS status;
6141  HANDLE tokenHandle;
6142  PTOKEN_USER tokenUser;
6143  UNICODE_STRING stringSid;
6144  WCHAR stringSidBuffer[MAX_UNICODE_STACK_BUFFER_LENGTH];
6145  PUNICODE_STRING currentUserKeyName;
6146 
6147  // Get the string SID of the current user.
6148  if (NT_SUCCESS(status = NtOpenProcessToken(NtCurrentProcess(), TOKEN_QUERY, &tokenHandle)))
6149  {
6150  if (NT_SUCCESS(status = PhGetTokenUser(tokenHandle, &tokenUser)))
6151  {
6152  stringSid.Buffer = stringSidBuffer;
6153  stringSid.MaximumLength = sizeof(stringSidBuffer);
6154 
6156  &stringSid,
6157  tokenUser->User.Sid,
6158  FALSE
6159  );
6160 
6161  PhFree(tokenUser);
6162  }
6163 
6164  NtClose(tokenHandle);
6165  }
6166 
6167  // Construct the current user key name.
6168  if (NT_SUCCESS(status))
6169  {
6170  currentUserKeyName = &PhPredefineKeyNames[PH_KEY_CURRENT_USER_NUMBER];
6171  currentUserKeyName->Length = currentUserPrefix.Length + stringSid.Length;
6172  currentUserKeyName->Buffer = PhAllocate(currentUserKeyName->Length + sizeof(WCHAR));
6173  memcpy(currentUserKeyName->Buffer, currentUserPrefix.Buffer, currentUserPrefix.Length);
6174  memcpy(&currentUserKeyName->Buffer[currentUserPrefix.Length / sizeof(WCHAR)], stringSid.Buffer, stringSid.Length);
6175  }
6176 }
6177 
6191  _In_opt_ HANDLE RootDirectory,
6192  _In_ PUNICODE_STRING ObjectName,
6193  _In_ ULONG Attributes,
6194  _Out_ POBJECT_ATTRIBUTES ObjectAttributes,
6195  _Out_ PHANDLE NeedsClose
6196  )
6197 {
6198  NTSTATUS status;
6199  ULONG predefineIndex;
6200  HANDLE predefineHandle;
6201  OBJECT_ATTRIBUTES predefineObjectAttributes;
6202 
6204  ObjectAttributes,
6205  ObjectName,
6206  Attributes | OBJ_CASE_INSENSITIVE,
6207  RootDirectory,
6208  NULL
6209  );
6210 
6211  *NeedsClose = NULL;
6212 
6213  if (RootDirectory && PH_KEY_IS_PREDEFINED(RootDirectory))
6214  {
6215  predefineIndex = PH_KEY_PREDEFINE_TO_NUMBER(RootDirectory);
6216 
6217  if (predefineIndex < PH_KEY_MAXIMUM_PREDEFINE)
6218  {
6219  if (PhBeginInitOnce(&PhPredefineKeyInitOnce))
6220  {
6222  PhEndInitOnce(&PhPredefineKeyInitOnce);
6223  }
6224 
6225  predefineHandle = PhPredefineKeyHandles[predefineIndex];
6226 
6227  if (!predefineHandle)
6228  {
6229  // The predefined key has not been opened yet. Do so now.
6230 
6231  if (!PhPredefineKeyNames[predefineIndex].Buffer) // we may have failed in getting the current user key name
6232  return STATUS_UNSUCCESSFUL;
6233 
6235  &predefineObjectAttributes,
6236  &PhPredefineKeyNames[predefineIndex],
6238  NULL,
6239  NULL
6240  );
6241 
6242  status = NtOpenKey(
6243  &predefineHandle,
6244  KEY_READ,
6245  &predefineObjectAttributes
6246  );
6247 
6248  if (!NT_SUCCESS(status))
6249  return status;
6250 
6252  &PhPredefineKeyHandles[predefineIndex],
6253  predefineHandle,
6254  NULL
6255  ) != NULL)
6256  {
6257  // Someone else already opened the key and cached it. Indicate that
6258  // the caller needs to close the handle later, since it isn't shared.
6259  *NeedsClose = predefineHandle;
6260  }
6261  }
6262 
6263  ObjectAttributes->RootDirectory = predefineHandle;
6264  }
6265  }
6266 
6267  return STATUS_SUCCESS;
6268 }
6269 
6289 NTSTATUS PhCreateKey(
6290  _Out_ PHANDLE KeyHandle,
6291  _In_ ACCESS_MASK DesiredAccess,
6292  _In_opt_ HANDLE RootDirectory,
6293  _In_ PPH_STRINGREF ObjectName,
6294  _In_ ULONG Attributes,
6295  _In_ ULONG CreateOptions,
6296  _Out_opt_ PULONG Disposition
6297  )
6298 {
6299  NTSTATUS status;
6300  UNICODE_STRING objectName;
6301  OBJECT_ATTRIBUTES objectAttributes;
6302  HANDLE needsClose;
6303 
6304  if (!PhStringRefToUnicodeString(ObjectName, &objectName))
6305  return STATUS_NAME_TOO_LONG;
6306 
6308  RootDirectory,
6309  &objectName,
6310  Attributes,
6311  &objectAttributes,
6312  &needsClose
6313  )))
6314  {
6315  return status;
6316  }
6317 
6318  status = NtCreateKey(
6319  KeyHandle,
6320  DesiredAccess,
6321  &objectAttributes,
6322  0,
6323  NULL,
6324  CreateOptions,
6325  Disposition
6326  );
6327 
6328  if (needsClose)
6329  NtClose(needsClose);
6330 
6331  return status;
6332 }
6333 
6344 NTSTATUS PhOpenKey(
6345  _Out_ PHANDLE KeyHandle,
6346  _In_ ACCESS_MASK DesiredAccess,
6347  _In_opt_ HANDLE RootDirectory,
6348  _In_ PPH_STRINGREF ObjectName,
6349  _In_ ULONG Attributes
6350  )
6351 {
6352  NTSTATUS status;
6353  UNICODE_STRING objectName;
6354  OBJECT_ATTRIBUTES objectAttributes;
6355  HANDLE needsClose;
6356 
6357  if (!PhStringRefToUnicodeString(ObjectName, &objectName))
6358  return STATUS_NAME_TOO_LONG;
6359 
6361  RootDirectory,
6362  &objectName,
6363  Attributes,
6364  &objectAttributes,
6365  &needsClose
6366  )))
6367  {
6368  return status;
6369  }
6370 
6371  status = NtOpenKey(
6372  KeyHandle,
6373  DesiredAccess,
6374  &objectAttributes
6375  );
6376 
6377  if (needsClose)
6378  NtClose(needsClose);
6379 
6380  return status;
6381 }