Process Hacker
cmdmode.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * command line action mode
4  *
5  * Copyright (C) 2010-2012 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 <phapp.h>
24 
25 NTSTATUS PhpGetDllBaseRemote(
26  _In_ HANDLE ProcessHandle,
27  _In_ PPH_STRINGREF BaseDllName,
28  _Out_ PVOID *DllBase
29  );
30 
31 static HWND CommandModeWindowHandle;
32 
33 #define PH_COMMAND_OPTION_HWND 1
34 
36  _In_opt_ PPH_COMMAND_LINE_OPTION Option,
37  _In_opt_ PPH_STRING Value,
38  _In_opt_ PVOID Context
39  )
40 {
41  ULONG64 integer;
42 
43  if (Option)
44  {
45  switch (Option->Id)
46  {
48  if (PhStringToInteger64(&Value->sr, 10, &integer))
49  CommandModeWindowHandle = (HWND)integer;
50  break;
51  }
52  }
53 
54  return TRUE;
55 }
56 
58  VOID
59  )
60 {
61  static PH_COMMAND_LINE_OPTION options[] =
62  {
64  };
65  NTSTATUS status = STATUS_SUCCESS;
66  PH_STRINGREF commandLine;
67 
68  PhUnicodeStringToStringRef(&NtCurrentPeb()->ProcessParameters->CommandLine, &commandLine);
69 
71  &commandLine,
72  options,
73  sizeof(options) / sizeof(PH_COMMAND_LINE_OPTION),
76  NULL
77  );
78 
80  {
81  SIZE_T i;
82  SIZE_T processIdLength;
83  HANDLE processId;
84  HANDLE processHandle;
85 
87  return STATUS_INVALID_PARAMETER;
88 
89  processIdLength = PhStartupParameters.CommandObject->Length / 2;
90 
91  for (i = 0; i < processIdLength; i++)
92  {
94  break;
95  }
96 
97  if (i == processIdLength)
98  {
99  ULONG64 processId64;
100 
101  if (!PhStringToInteger64(&PhStartupParameters.CommandObject->sr, 10, &processId64))
102  return STATUS_INVALID_PARAMETER;
103 
104  processId = (HANDLE)processId64;
105  }
106  else
107  {
108  PVOID processes;
110 
111  if (!NT_SUCCESS(status = PhEnumProcesses(&processes)))
112  return status;
113 
115  {
116  PhFree(processes);
117  return STATUS_NOT_FOUND;
118  }
119 
120  processId = process->UniqueProcessId;
121  PhFree(processes);
122  }
123 
125  {
126  if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_TERMINATE, processId)))
127  {
128  status = PhTerminateProcess(processHandle, STATUS_SUCCESS);
129  NtClose(processHandle);
130  }
131  }
132  else if (PhEqualString2(PhStartupParameters.CommandAction, L"suspend", TRUE))
133  {
134  if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SUSPEND_RESUME, processId)))
135  {
136  status = PhSuspendProcess(processHandle);
137  NtClose(processHandle);
138  }
139  }
141  {
142  if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SUSPEND_RESUME, processId)))
143  {
144  status = PhResumeProcess(processHandle);
145  NtClose(processHandle);
146  }
147  }
148  else if (PhEqualString2(PhStartupParameters.CommandAction, L"priority", TRUE))
149  {
150  UCHAR priority;
151 
153  return STATUS_INVALID_PARAMETER;
154 
156  priority = PROCESS_PRIORITY_CLASS_IDLE;
157  else if (PhEqualString2(PhStartupParameters.CommandValue, L"normal", TRUE))
160  priority = PROCESS_PRIORITY_CLASS_HIGH;
161  else if (PhEqualString2(PhStartupParameters.CommandValue, L"realtime", TRUE))
163  else if (PhEqualString2(PhStartupParameters.CommandValue, L"abovenormal", TRUE))
165  else if (PhEqualString2(PhStartupParameters.CommandValue, L"belownormal", TRUE))
167  else
168  return STATUS_INVALID_PARAMETER;
169 
170  if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SET_INFORMATION, processId)))
171  {
172  PROCESS_PRIORITY_CLASS priorityClass;
173  priorityClass.Foreground = FALSE;
174  priorityClass.PriorityClass = priority;
175  status = NtSetInformationProcess(processHandle, ProcessPriorityClass, &priorityClass, sizeof(PROCESS_PRIORITY_CLASS));
176  NtClose(processHandle);
177  }
178  }
179  else if (PhEqualString2(PhStartupParameters.CommandAction, L"iopriority", TRUE))
180  {
181  ULONG ioPriority;
182 
184  return STATUS_INVALID_PARAMETER;
185 
187  ioPriority = 0;
189  ioPriority = 1;
190  else if (PhEqualString2(PhStartupParameters.CommandValue, L"normal", TRUE))
191  ioPriority = 2;
193  ioPriority = 3;
194  else
195  return STATUS_INVALID_PARAMETER;
196 
197  if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SET_INFORMATION, processId)))
198  {
199  status = PhSetProcessIoPriority(processHandle, ioPriority);
200  NtClose(processHandle);
201  }
202  }
203  else if (PhEqualString2(PhStartupParameters.CommandAction, L"pagepriority", TRUE))
204  {
205  ULONG64 pagePriority64;
206  ULONG pagePriority;
207 
209  return STATUS_INVALID_PARAMETER;
210 
211  PhStringToInteger64(&PhStartupParameters.CommandValue->sr, 10, &pagePriority64);
212  pagePriority = (ULONG)pagePriority64;
213 
214  if (NT_SUCCESS(status = PhOpenProcess(&processHandle, PROCESS_SET_INFORMATION, processId)))
215  {
216  status = NtSetInformationProcess(
217  processHandle,
218  ProcessPagePriority,
219  &pagePriority,
220  sizeof(ULONG)
221  );
222  NtClose(processHandle);
223  }
224  }
225  else if (PhEqualString2(PhStartupParameters.CommandAction, L"injectdll", TRUE))
226  {
228  return STATUS_INVALID_PARAMETER;
229 
230  if (NT_SUCCESS(status = PhOpenProcess(
231  &processHandle,
233  processId
234  )))
235  {
236  LARGE_INTEGER timeout;
237 
238  timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
239  status = PhInjectDllProcess(
240  processHandle,
242  &timeout
243  );
244  NtClose(processHandle);
245  }
246  }
247  else if (PhEqualString2(PhStartupParameters.CommandAction, L"unloaddll", TRUE))
248  {
250  return STATUS_INVALID_PARAMETER;
251 
252  if (NT_SUCCESS(status = PhOpenProcess(
253  &processHandle,
255  processId
256  )))
257  {
258  PVOID baseAddress;
259 
260  if (NT_SUCCESS(status = PhpGetDllBaseRemote(
261  processHandle,
263  &baseAddress
264  )))
265  {
266  LARGE_INTEGER timeout;
267 
268  timeout.QuadPart = -5 * PH_TIMEOUT_SEC;
269  status = PhUnloadDllProcess(
270  processHandle,
271  baseAddress,
272  &timeout
273  );
274  }
275 
276  NtClose(processHandle);
277  }
278  }
279  }
280  else if (PhEqualString2(PhStartupParameters.CommandType, L"service", TRUE))
281  {
282  SC_HANDLE serviceHandle;
283  SERVICE_STATUS serviceStatus;
284 
286  return STATUS_INVALID_PARAMETER;
287 
289  {
290  if (!(serviceHandle = PhOpenService(
292  SERVICE_START
293  )))
295 
296  if (!StartService(serviceHandle, 0, NULL))
298 
299  CloseServiceHandle(serviceHandle);
300  }
301  else if (PhEqualString2(PhStartupParameters.CommandAction, L"continue", TRUE))
302  {
303  if (!(serviceHandle = PhOpenService(
305  SERVICE_PAUSE_CONTINUE
306  )))
308 
309  if (!ControlService(serviceHandle, SERVICE_CONTROL_CONTINUE, &serviceStatus))
311 
312  CloseServiceHandle(serviceHandle);
313  }
315  {
316  if (!(serviceHandle = PhOpenService(
318  SERVICE_PAUSE_CONTINUE
319  )))
321 
322  if (!ControlService(serviceHandle, SERVICE_CONTROL_PAUSE, &serviceStatus))
324 
325  CloseServiceHandle(serviceHandle);
326  }
328  {
329  if (!(serviceHandle = PhOpenService(
331  SERVICE_STOP
332  )))
334 
335  if (!ControlService(serviceHandle, SERVICE_CONTROL_STOP, &serviceStatus))
337 
338  CloseServiceHandle(serviceHandle);
339  }
341  {
342  if (!(serviceHandle = PhOpenService(
344  DELETE
345  )))
347 
348  if (!DeleteService(serviceHandle))
350 
351  CloseServiceHandle(serviceHandle);
352  }
353  }
354  else if (PhEqualString2(PhStartupParameters.CommandType, L"thread", TRUE))
355  {
356  ULONG64 threadId64;
357  HANDLE threadId;
358  HANDLE threadHandle;
359 
361  return STATUS_INVALID_PARAMETER;
362 
363  if (!PhStringToInteger64(&PhStartupParameters.CommandObject->sr, 10, &threadId64))
364  return STATUS_INVALID_PARAMETER;
365 
366  threadId = (HANDLE)threadId64;
367 
369  {
370  if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_TERMINATE, threadId)))
371  {
372  status = PhTerminateThread(threadHandle, STATUS_SUCCESS);
373  NtClose(threadHandle);
374  }
375  }
376  else if (PhEqualString2(PhStartupParameters.CommandAction, L"suspend", TRUE))
377  {
378  if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SUSPEND_RESUME, threadId)))
379  {
380  status = PhSuspendThread(threadHandle, NULL);
381  NtClose(threadHandle);
382  }
383  }
385  {
386  if (NT_SUCCESS(status = PhOpenThread(&threadHandle, THREAD_SUSPEND_RESUME, threadId)))
387  {
388  status = PhResumeThread(threadHandle, NULL);
389  NtClose(threadHandle);
390  }
391  }
392  }
393 
394  return status;
395 }
396 
397 typedef struct _GET_DLL_BASE_REMOTE_CONTEXT
398 {
399  PH_STRINGREF BaseDllName;
400  PVOID DllBase;
402 
403 static BOOLEAN PhpGetDllBaseRemoteCallback(
404  _In_ PLDR_DATA_TABLE_ENTRY Module,
405  _In_opt_ PVOID Context
406  )
407 {
408  PGET_DLL_BASE_REMOTE_CONTEXT context = Context;
409  PH_STRINGREF baseDllName;
410 
411  PhUnicodeStringToStringRef(&Module->BaseDllName, &baseDllName);
412 
413  if (PhEqualStringRef(&baseDllName, &context->BaseDllName, TRUE))
414  {
415  context->DllBase = Module->DllBase;
416  return FALSE;
417  }
418 
419  return TRUE;
420 }
421 
423  _In_ HANDLE ProcessHandle,
424  _In_ PPH_STRINGREF BaseDllName,
425  _Out_ PVOID *DllBase
426  )
427 {
428  NTSTATUS status;
430 #ifdef _WIN64
431  BOOLEAN isWow64 = FALSE;
432 #endif
433 
434  context.BaseDllName = *BaseDllName;
435  context.DllBase = NULL;
436 
437 #ifdef _WIN64
438  PhGetProcessIsWow64(ProcessHandle, &isWow64);
439 
440  if (isWow64)
441  status = PhEnumProcessModules32(ProcessHandle, PhpGetDllBaseRemoteCallback, &context);
442  if (!context.DllBase)
443 #endif
444  status = PhEnumProcessModules(ProcessHandle, PhpGetDllBaseRemoteCallback, &context);
445 
446  if (NT_SUCCESS(status))
447  *DllBase = context.DllBase;
448 
449  return status;
450 }