Process Hacker
main.c
Go to the documentation of this file.
1 /*
2  * KProcessHacker
3  *
4  * Copyright (C) 2010-2011 wj32
5  *
6  * This file is part of Process Hacker.
7  *
8  * Process Hacker is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation, either version 3 of the License, or
11  * (at your option) any later version.
12  *
13  * Process Hacker is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include <kph.h>
23 #include <dyndata.h>
24 
25 DRIVER_INITIALIZE DriverEntry;
26 DRIVER_UNLOAD DriverUnload;
27 __drv_dispatchType(IRP_MJ_CREATE) DRIVER_DISPATCH KphDispatchCreate;
28 
30  __in_opt HANDLE KeyHandle,
31  __in PUNICODE_STRING ValueName,
32  __in ULONG DefaultValue
33  );
34 
36  __in PUNICODE_STRING RegistryPath
37  );
38 
39 #ifdef ALLOC_PRAGMA
40 #pragma alloc_text(PAGE, DriverEntry)
41 #pragma alloc_text(PAGE, DriverUnload)
42 #pragma alloc_text(PAGE, KphpReadIntegerParameter)
43 #pragma alloc_text(PAGE, KphpReadDriverParameters)
44 #pragma alloc_text(PAGE, KpiGetFeatures)
45 #endif
46 
47 PDRIVER_OBJECT KphDriverObject;
48 PDEVICE_OBJECT KphDeviceObject;
49 ULONG KphFeatures;
51 
52 NTSTATUS DriverEntry(
53  __in PDRIVER_OBJECT DriverObject,
54  __in PUNICODE_STRING RegistryPath
55  )
56 {
57  NTSTATUS status;
58  UNICODE_STRING deviceName;
59  PDEVICE_OBJECT deviceObject;
60 
61  PAGED_CODE();
62 
63  KphDriverObject = DriverObject;
64 
66  return status;
67 
69 
70  if (!NT_SUCCESS(status = KphpReadDriverParameters(RegistryPath)))
71  return status;
72 
73  // Create the device.
74 
76 
77  status = IoCreateDevice(
78  DriverObject,
79  0,
80  &deviceName,
81  FILE_DEVICE_UNKNOWN,
83  FALSE,
84  &deviceObject
85  );
86 
87  if (!NT_SUCCESS(status))
88  return status;
89 
90  KphDeviceObject = deviceObject;
91 
92  // Set up I/O.
93 
94  DriverObject->MajorFunction[IRP_MJ_CREATE] = KphDispatchCreate;
95  DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = KphDispatchDeviceControl;
96  DriverObject->DriverUnload = DriverUnload;
97 
98  deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
99 
100  dprintf("Driver loaded\n");
101 
102  return status;
103 }
104 
106  __in PDRIVER_OBJECT DriverObject
107  )
108 {
109  PAGED_CODE();
110 
111  IoDeleteDevice(KphDeviceObject);
112 
113  dprintf("Driver unloaded\n");
114 }
115 
117  __in PDEVICE_OBJECT DeviceObject,
118  __in PIRP Irp
119  )
120 {
121  NTSTATUS status = STATUS_SUCCESS;
122  PIO_STACK_LOCATION stackLocation;
123  PIO_SECURITY_CONTEXT securityContext;
124 
125  stackLocation = IoGetCurrentIrpStackLocation(Irp);
126  securityContext = stackLocation->Parameters.Create.SecurityContext;
127 
128  dprintf("Client (PID %Iu) is connecting\n", PsGetCurrentProcessId());
129 
130  if (KphParameters.SecurityLevel == KphSecurityPrivilegeCheck)
131  {
132  UCHAR requiredPrivilegesBuffer[FIELD_OFFSET(PRIVILEGE_SET, Privilege) + sizeof(LUID_AND_ATTRIBUTES)];
133  PPRIVILEGE_SET requiredPrivileges;
134 
135  // Check for SeDebugPrivilege.
136 
137  requiredPrivileges = (PPRIVILEGE_SET)requiredPrivilegesBuffer;
138  requiredPrivileges->PrivilegeCount = 1;
139  requiredPrivileges->Control = PRIVILEGE_SET_ALL_NECESSARY;
140  requiredPrivileges->Privilege[0].Luid.LowPart = SE_DEBUG_PRIVILEGE;
141  requiredPrivileges->Privilege[0].Luid.HighPart = 0;
142  requiredPrivileges->Privilege[0].Attributes = 0;
143 
144  if (!SePrivilegeCheck(
145  requiredPrivileges,
146  &securityContext->AccessState->SubjectSecurityContext,
147  Irp->RequestorMode
148  ))
149  {
150  status = STATUS_PRIVILEGE_NOT_HELD;
151  dprintf("Client (PID %Iu) was rejected\n", PsGetCurrentProcessId());
152  }
153  }
154 
155  Irp->IoStatus.Status = status;
156  Irp->IoStatus.Information = 0;
157  IoCompleteRequest(Irp, IO_NO_INCREMENT);
158 
159  return status;
160 }
161 
174  __in_opt HANDLE KeyHandle,
175  __in PUNICODE_STRING ValueName,
176  __in ULONG DefaultValue
177  )
178 {
179  NTSTATUS status;
180  UCHAR buffer[FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) + sizeof(ULONG)];
182  ULONG resultLength;
183 
184  PAGED_CODE();
185 
186  if (!KeyHandle)
187  return DefaultValue;
188 
189  info = (PKEY_VALUE_PARTIAL_INFORMATION)buffer;
190 
191  status = ZwQueryValueKey(
192  KeyHandle,
193  ValueName,
195  info,
196  sizeof(buffer),
197  &resultLength
198  );
199 
200  if (info->Type != REG_DWORD)
201  status = STATUS_OBJECT_TYPE_MISMATCH;
202 
203  if (!NT_SUCCESS(status))
204  {
205  dprintf("Unable to query parameter %.*S: 0x%x\n", ValueName->Length / sizeof(WCHAR), ValueName->Buffer, status);
206  return DefaultValue;
207  }
208 
209  return *(PULONG)info->Data;
210 }
211 
218  __in PUNICODE_STRING RegistryPath
219  )
220 {
221  NTSTATUS status;
222  HANDLE parametersKeyHandle;
223  UNICODE_STRING parametersString;
224  UNICODE_STRING parametersKeyName;
225  OBJECT_ATTRIBUTES objectAttributes;
226  UNICODE_STRING valueName;
227 
228  PAGED_CODE();
229 
230  // Open the Parameters key.
231 
232  RtlInitUnicodeString(&parametersString, L"\\Parameters");
233 
234  parametersKeyName.Length = RegistryPath->Length + parametersString.Length;
235  parametersKeyName.MaximumLength = parametersKeyName.Length;
236  parametersKeyName.Buffer = ExAllocatePoolWithTag(PagedPool, parametersKeyName.MaximumLength, 'ThpK');
237 
238  if (!parametersKeyName.Buffer)
239  return STATUS_INSUFFICIENT_RESOURCES;
240 
241  memcpy(parametersKeyName.Buffer, RegistryPath->Buffer, RegistryPath->Length);
242  memcpy(&parametersKeyName.Buffer[RegistryPath->Length / sizeof(WCHAR)], parametersString.Buffer, parametersString.Length);
243 
245  &objectAttributes,
246  &parametersKeyName,
248  NULL,
249  NULL
250  );
251  status = ZwOpenKey(
252  &parametersKeyHandle,
253  KEY_READ,
254  &objectAttributes
255  );
256  ExFreePoolWithTag(parametersKeyName.Buffer, 'ThpK');
257 
258  if (!NT_SUCCESS(status))
259  {
260  dprintf("Unable to open Parameters key: 0x%x\n", status);
261  status = STATUS_SUCCESS;
262  parametersKeyHandle = NULL;
263  // Continue so we can set up defaults.
264  }
265 
266  // Read in the parameters.
267 
268  RtlInitUnicodeString(&valueName, L"SecurityLevel");
269  KphParameters.SecurityLevel = KphpReadIntegerParameter(parametersKeyHandle, &valueName, KphSecurityPrivilegeCheck);
270 
271  RtlInitUnicodeString(&valueName, L"DisableDynamicProcedureScan");
272  KphParameters.DisableDynamicProcedureScan = KphpReadIntegerParameter(parametersKeyHandle, &valueName, FALSE);
273 
274  KphReadDynamicDataParameters(parametersKeyHandle);
275 
276  if (parametersKeyHandle)
277  ZwClose(parametersKeyHandle);
278 
279  return status;
280 }
281 
282 NTSTATUS KpiGetFeatures(
283  __out PULONG Features,
284  __in KPROCESSOR_MODE AccessMode
285  )
286 {
287  PAGED_CODE();
288 
289  if (AccessMode != KernelMode)
290  {
291  __try
292  {
293  ProbeForWrite(Features, sizeof(ULONG), sizeof(ULONG));
294  *Features = KphFeatures;
295  }
296  __except (EXCEPTION_EXECUTE_HANDLER)
297  {
298  return GetExceptionCode();
299  }
300  }
301  else
302  {
303  *Features = KphFeatures;
304  }
305 
306  return STATUS_SUCCESS;
307 }
308 
318  __out PRTL_PROCESS_MODULES *Modules
319  )
320 {
321  NTSTATUS status;
322  PVOID buffer;
323  ULONG bufferSize;
324  ULONG attempts;
325 
326  bufferSize = 2048;
327  attempts = 8;
328 
329  do
330  {
331  buffer = ExAllocatePoolWithTag(PagedPool, bufferSize, 'ThpK');
332 
333  if (!buffer)
334  {
335  status = STATUS_INSUFFICIENT_RESOURCES;
336  break;
337  }
338 
339  status = ZwQuerySystemInformation(
341  buffer,
342  bufferSize,
343  &bufferSize
344  );
345 
346  if (NT_SUCCESS(status))
347  {
348  *Modules = buffer;
349 
350  return status;
351  }
352 
353  ExFreePoolWithTag(buffer, 'ThpK');
354 
355  if (status != STATUS_INFO_LENGTH_MISMATCH)
356  {
357  break;
358  }
359  } while (--attempts);
360 
361  return status;
362 }
363 
371  __in PVOID Address,
372  __in SIZE_T Length
373  )
374 {
375  NTSTATUS status;
376  PRTL_PROCESS_MODULES modules;
377  ULONG i;
378  BOOLEAN valid;
379 
380  status = KphEnumerateSystemModules(&modules);
381 
382  if (!NT_SUCCESS(status))
383  return status;
384 
385  valid = FALSE;
386 
387  for (i = 0; i < modules->NumberOfModules; i++)
388  {
389  if (
390  (ULONG_PTR)Address + Length >= (ULONG_PTR)Address &&
391  (ULONG_PTR)Address >= (ULONG_PTR)modules->Modules[i].ImageBase &&
392  (ULONG_PTR)Address + Length <= (ULONG_PTR)modules->Modules[i].ImageBase + modules->Modules[i].ImageSize
393  )
394  {
395  dprintf("Validated address 0x%Ix in %s\n", Address, modules->Modules[i].FullPathName);
396  valid = TRUE;
397  break;
398  }
399  }
400 
401  ExFreePoolWithTag(modules, 'ThpK');
402 
403  if (valid)
404  status = STATUS_SUCCESS;
405  else
406  status = STATUS_ACCESS_VIOLATION;
407 
408  return status;
409 }