Process Hacker
svcsup.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * service support functions
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 <ph.h>
24 #include <winmisc.h>
25 
26 #define SIP(String, Integer) { (String), (PVOID)(Integer) }
27 
28 static PH_KEY_VALUE_PAIR PhpServiceStatePairs[] =
29 {
30  SIP(L"Stopped", SERVICE_STOPPED),
31  SIP(L"Start Pending", SERVICE_START_PENDING),
32  SIP(L"Stop Pending", SERVICE_STOP_PENDING),
33  SIP(L"Running", SERVICE_RUNNING),
34  SIP(L"Continue Pending", SERVICE_CONTINUE_PENDING),
35  SIP(L"Pause Pending", SERVICE_PAUSE_PENDING),
36  SIP(L"Paused", SERVICE_PAUSED)
37 };
38 
39 static PH_KEY_VALUE_PAIR PhpServiceTypePairs[] =
40 {
41  SIP(L"Driver", SERVICE_KERNEL_DRIVER),
42  SIP(L"FS Driver", SERVICE_FILE_SYSTEM_DRIVER),
43  SIP(L"Own Process", SERVICE_WIN32_OWN_PROCESS),
44  SIP(L"Share Process", SERVICE_WIN32_SHARE_PROCESS),
45  SIP(L"Own Interactive Process", SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS),
46  SIP(L"Share Interactive Process", SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS)
47 };
48 
49 static PH_KEY_VALUE_PAIR PhpServiceStartTypePairs[] =
50 {
51  SIP(L"Disabled", SERVICE_DISABLED),
52  SIP(L"Boot Start", SERVICE_BOOT_START),
53  SIP(L"System Start", SERVICE_SYSTEM_START),
54  SIP(L"Auto Start", SERVICE_AUTO_START),
55  SIP(L"Demand Start", SERVICE_DEMAND_START)
56 };
57 
58 static PH_KEY_VALUE_PAIR PhpServiceErrorControlPairs[] =
59 {
60  SIP(L"Ignore", SERVICE_ERROR_IGNORE),
61  SIP(L"Normal", SERVICE_ERROR_NORMAL),
62  SIP(L"Severe", SERVICE_ERROR_SEVERE),
63  SIP(L"Critical", SERVICE_ERROR_CRITICAL)
64 };
65 
66 WCHAR *PhServiceTypeStrings[6] = { L"Driver", L"FS Driver", L"Own Process", L"Share Process",
67  L"Own Interactive Process", L"Share Interactive Process" };
68 WCHAR *PhServiceStartTypeStrings[5] = { L"Disabled", L"Boot Start", L"System Start",
69  L"Auto Start", L"Demand Start" };
70 WCHAR *PhServiceErrorControlStrings[4] = { L"Ignore", L"Normal", L"Severe", L"Critical" };
71 
73  _In_ SC_HANDLE ScManagerHandle,
74  _In_opt_ ULONG Type,
75  _In_opt_ ULONG State,
76  _Out_ PULONG Count
77  )
78 {
79  static ULONG initialBufferSize = 0x8000;
80  LOGICAL result;
81  PVOID buffer;
82  ULONG bufferSize;
83  ULONG returnLength;
84  ULONG servicesReturned;
85 
86  if (!Type)
87  Type = SERVICE_DRIVER | SERVICE_WIN32;
88  if (!State)
89  State = SERVICE_STATE_ALL;
90 
91  bufferSize = initialBufferSize;
92  buffer = PhAllocate(bufferSize);
93 
94  if (!(result = EnumServicesStatusEx(
95  ScManagerHandle,
96  SC_ENUM_PROCESS_INFO,
97  Type,
98  State,
99  buffer,
100  bufferSize,
101  &returnLength,
102  &servicesReturned,
103  NULL,
104  NULL
105  )))
106  {
107  if (GetLastError() == ERROR_MORE_DATA)
108  {
109  PhFree(buffer);
110  bufferSize += returnLength;
111  buffer = PhAllocate(bufferSize);
112 
113  result = EnumServicesStatusEx(
114  ScManagerHandle,
115  SC_ENUM_PROCESS_INFO,
116  Type,
117  State,
118  buffer,
119  bufferSize,
120  &returnLength,
121  &servicesReturned,
122  NULL,
123  NULL
124  );
125  }
126 
127  if (!result)
128  {
129  PhFree(buffer);
130  return NULL;
131  }
132  }
133 
134  if (bufferSize <= 0x20000) initialBufferSize = bufferSize;
135  *Count = servicesReturned;
136 
137  return buffer;
138 }
139 
140 SC_HANDLE PhOpenService(
141  _In_ PWSTR ServiceName,
142  _In_ ACCESS_MASK DesiredAccess
143  )
144 {
145  SC_HANDLE scManagerHandle;
146  SC_HANDLE serviceHandle;
147 
148  scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
149 
150  if (!scManagerHandle)
151  return NULL;
152 
153  serviceHandle = OpenService(scManagerHandle, ServiceName, DesiredAccess);
154  CloseServiceHandle(scManagerHandle);
155 
156  return serviceHandle;
157 }
158 
160  _In_ SC_HANDLE ServiceHandle
161  )
162 {
163  PVOID buffer;
164  ULONG bufferSize = 0x200;
165 
166  buffer = PhAllocate(bufferSize);
167 
168  if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize))
169  {
170  PhFree(buffer);
171  buffer = PhAllocate(bufferSize);
172 
173  if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize))
174  {
175  PhFree(buffer);
176  return NULL;
177  }
178  }
179 
180  return buffer;
181 }
182 
184  _In_ SC_HANDLE ServiceHandle,
185  _In_ ULONG InfoLevel
186  )
187 {
188  PVOID buffer;
189  ULONG bufferSize = 0x100;
190 
191  buffer = PhAllocate(bufferSize);
192 
193  if (!QueryServiceConfig2(
194  ServiceHandle,
195  InfoLevel,
196  (BYTE *)buffer,
197  bufferSize,
198  &bufferSize
199  ))
200  {
201  PhFree(buffer);
202  buffer = PhAllocate(bufferSize);
203 
204  if (!QueryServiceConfig2(
205  ServiceHandle,
206  InfoLevel,
207  (BYTE *)buffer,
208  bufferSize,
209  &bufferSize
210  ))
211  {
212  PhFree(buffer);
213  return NULL;
214  }
215  }
216 
217  return buffer;
218 }
219 
221  _In_ SC_HANDLE ServiceHandle
222  )
223 {
224  PPH_STRING description = NULL;
225  LPSERVICE_DESCRIPTION serviceDescription;
226 
227  serviceDescription = PhQueryServiceVariableSize(ServiceHandle, SERVICE_CONFIG_DESCRIPTION);
228 
229  if (serviceDescription)
230  {
231  if (serviceDescription->lpDescription)
232  description = PhCreateString(serviceDescription->lpDescription);
233 
234  PhFree(serviceDescription);
235 
236  return description;
237  }
238  else
239  {
240  return NULL;
241  }
242 }
243 
245  _In_ SC_HANDLE ServiceHandle,
246  _Out_ PBOOLEAN DelayedAutoStart
247  )
248 {
249  SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;
250  ULONG returnLength;
251 
252  if (QueryServiceConfig2(
253  ServiceHandle,
254  SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
255  (BYTE *)&delayedAutoStartInfo,
256  sizeof(SERVICE_DELAYED_AUTO_START_INFO),
257  &returnLength
258  ))
259  {
260  *DelayedAutoStart = !!delayedAutoStartInfo.fDelayedAutostart;
261  return TRUE;
262  }
263  else
264  {
265  return FALSE;
266  }
267 }
268 
270  _In_ SC_HANDLE ServiceHandle,
271  _In_ BOOLEAN DelayedAutoStart
272  )
273 {
274  SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;
275 
276  delayedAutoStartInfo.fDelayedAutostart = DelayedAutoStart;
277 
278  return !!ChangeServiceConfig2(
279  ServiceHandle,
280  SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
281  &delayedAutoStartInfo
282  );
283 }
284 
286  _In_ ULONG ServiceState
287  )
288 {
289  PWSTR string;
290 
292  PhpServiceStatePairs,
293  sizeof(PhpServiceStatePairs),
294  ServiceState,
295  &string
296  ))
297  return string;
298  else
299  return L"Unknown";
300 }
301 
303  _In_ ULONG ServiceType
304  )
305 {
306  PWSTR string;
307 
309  PhpServiceTypePairs,
310  sizeof(PhpServiceTypePairs),
311  ServiceType,
312  &string
313  ))
314  return string;
315  else
316  return L"Unknown";
317 }
318 
320  _In_ PWSTR ServiceType
321  )
322 {
323  ULONG integer;
324 
326  PhpServiceTypePairs,
327  sizeof(PhpServiceTypePairs),
328  ServiceType,
329  &integer
330  ))
331  return integer;
332  else
333  return -1;
334 }
335 
337  _In_ ULONG ServiceStartType
338  )
339 {
340  PWSTR string;
341 
343  PhpServiceStartTypePairs,
344  sizeof(PhpServiceStartTypePairs),
345  ServiceStartType,
346  &string
347  ))
348  return string;
349  else
350  return L"Unknown";
351 }
352 
354  _In_ PWSTR ServiceStartType
355  )
356 {
357  ULONG integer;
358 
360  PhpServiceStartTypePairs,
361  sizeof(PhpServiceStartTypePairs),
362  ServiceStartType,
363  &integer
364  ))
365  return integer;
366  else
367  return -1;
368 }
369 
371  _In_ ULONG ServiceErrorControl
372  )
373 {
374  PWSTR string;
375 
377  PhpServiceErrorControlPairs,
378  sizeof(PhpServiceErrorControlPairs),
379  ServiceErrorControl,
380  &string
381  ))
382  return string;
383  else
384  return L"Unknown";
385 }
386 
388  _In_ PWSTR ServiceErrorControl
389  )
390 {
391  ULONG integer;
392 
394  PhpServiceErrorControlPairs,
395  sizeof(PhpServiceErrorControlPairs),
396  ServiceErrorControl,
397  &integer
398  ))
399  return integer;
400  else
401  return -1;
402 }
403 
405  _In_ HANDLE ProcessId,
406  _In_ PVOID ServiceTag
407  )
408 {
410  PPH_STRING serviceName = NULL;
411  TAG_INFO_NAME_FROM_TAG nameFromTag;
412 
413  if (!I_QueryTagInformation)
414  {
415  I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation");
416 
417  if (!I_QueryTagInformation)
418  return NULL;
419  }
420 
421  memset(&nameFromTag, 0, sizeof(TAG_INFO_NAME_FROM_TAG));
422  nameFromTag.InParams.dwPid = (ULONG)ProcessId;
423  nameFromTag.InParams.dwTag = (ULONG)ServiceTag;
424 
425  I_QueryTagInformation(NULL, eTagInfoLevelNameFromTag, &nameFromTag);
426 
427  if (nameFromTag.OutParams.pszName)
428  {
429  serviceName = PhCreateString(nameFromTag.OutParams.pszName);
430  LocalFree(nameFromTag.OutParams.pszName);
431  }
432 
433  return serviceName;
434 }
435 
437  _In_ HANDLE ThreadHandle,
438  _In_opt_ HANDLE ProcessHandle,
439  _Out_ PVOID *ServiceTag
440  )
441 {
442  NTSTATUS status;
443  THREAD_BASIC_INFORMATION basicInfo;
444  BOOLEAN openedProcessHandle = FALSE;
445 
446  if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))
447  return status;
448 
449  if (!ProcessHandle)
450  {
451  if (!NT_SUCCESS(status = PhOpenThreadProcess(
452  &ProcessHandle,
454  ThreadHandle
455  )))
456  return status;
457 
458  openedProcessHandle = TRUE;
459  }
460 
461  status = PhReadVirtualMemory(
462  ProcessHandle,
463  PTR_ADD_OFFSET(basicInfo.TebBaseAddress, FIELD_OFFSET(TEB, SubProcessTag)),
464  ServiceTag,
465  sizeof(PVOID),
466  NULL
467  );
468 
469  if (openedProcessHandle)
470  NtClose(ProcessHandle);
471 
472  return status;
473 }
474 
477  _Out_ PPH_STRING *ServiceDll
478  )
479 {
480  static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\");
481  static PH_STRINGREF parameters = PH_STRINGREF_INIT(L"\\Parameters");
482 
483  NTSTATUS status;
484  HANDLE keyHandle;
485  PPH_STRING keyName;
486 
487  keyName = PhConcatStringRef3(&servicesKeyName, ServiceName, &parameters);
488 
489  if (NT_SUCCESS(status = PhOpenKey(
490  &keyHandle,
491  KEY_READ,
493  &keyName->sr,
494  0
495  )))
496  {
497  PPH_STRING serviceDllString;
498 
499  if (serviceDllString = PhQueryRegistryString(keyHandle, L"ServiceDll"))
500  {
501  PPH_STRING expandedString;
502 
503  if (expandedString = PhExpandEnvironmentStrings(&serviceDllString->sr))
504  {
505  *ServiceDll = expandedString;
506  PhDereferenceObject(serviceDllString);
507  }
508  else
509  {
510  *ServiceDll = serviceDllString;
511  }
512  }
513  else
514  {
515  status = STATUS_NOT_FOUND;
516  }
517 
518  NtClose(keyHandle);
519  }
520 
521  PhDereferenceObject(keyName);
522 
523  return status;
524 }