Process Hacker
clapi.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * phsvc client
4  *
5  * Copyright (C) 2011-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 <phapp.h>
24 #include <phsvccl.h>
25 
29 
31  _In_ PUNICODE_STRING PortName,
32  _In_opt_ SIZE_T PortSectionSize
33  )
34 {
35  NTSTATUS status;
36  HANDLE sectionHandle;
37  LARGE_INTEGER sectionSize;
38  PORT_VIEW clientView;
39  REMOTE_PORT_VIEW serverView;
40  SECURITY_QUALITY_OF_SERVICE securityQos;
41  ULONG maxMessageLength;
42  PHSVC_API_CONNECTINFO connectInfo;
43  ULONG connectInfoLength;
44 
46  return STATUS_ADDRESS_ALREADY_EXISTS;
47 
48  if (PortSectionSize == 0)
49  PortSectionSize = 512 * 1024;
50 
51  // Create the port section and connect to the port.
52 
53  sectionSize.QuadPart = PortSectionSize;
54  status = NtCreateSection(
55  &sectionHandle,
56  SECTION_ALL_ACCESS,
57  NULL,
58  &sectionSize,
59  PAGE_READWRITE,
60  SEC_COMMIT,
61  NULL
62  );
63 
64  if (!NT_SUCCESS(status))
65  return status;
66 
67  clientView.Length = sizeof(PORT_VIEW);
68  clientView.SectionHandle = sectionHandle;
69  clientView.SectionOffset = 0;
70  clientView.ViewSize = PortSectionSize;
71  clientView.ViewBase = NULL;
72  clientView.ViewRemoteBase = NULL;
73 
74  serverView.Length = sizeof(REMOTE_PORT_VIEW);
75  serverView.ViewSize = 0;
76  serverView.ViewBase = NULL;
77 
78  securityQos.Length = sizeof(SECURITY_QUALITY_OF_SERVICE);
79  securityQos.ImpersonationLevel = SecurityImpersonation;
80  securityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
81  securityQos.EffectiveOnly = TRUE;
82 
83  connectInfoLength = sizeof(PHSVC_API_CONNECTINFO);
84 
85  status = NtConnectPort(
87  PortName,
88  &securityQos,
89  &clientView,
90  &serverView,
91  &maxMessageLength,
92  &connectInfo,
93  &connectInfoLength
94  );
95  NtClose(sectionHandle);
96 
97  if (!NT_SUCCESS(status))
98  return status;
99 
100  PhSvcClServerProcessId = UlongToHandle(connectInfo.ServerProcessId);
101 
102  // Create the port heap.
103 
105  HEAP_CLASS_1,
106  clientView.ViewBase,
107  clientView.ViewSize,
108  PAGE_SIZE,
109  NULL,
110  NULL
111  );
112 
113  if (!PhSvcClPortHeap)
114  {
115  NtClose(PhSvcClPortHandle);
116  return STATUS_INSUFFICIENT_RESOURCES;
117  }
118 
119  return status;
120 }
121 
123  VOID
124  )
125 {
126  if (PhSvcClPortHeap)
127  {
129  PhSvcClPortHeap = NULL;
130  }
131 
132  if (PhSvcClPortHandle)
133  {
134  NtClose(PhSvcClPortHandle);
135  PhSvcClPortHandle = NULL;
136  }
137 
138  PhSvcClServerProcessId = NULL;
139 }
140 
142  _In_ SIZE_T Size,
143  _Out_ PULONG Offset
144  )
145 {
146  PVOID memory;
147 
148  if (!PhSvcClPortHeap)
149  return NULL;
150 
151  memory = RtlAllocateHeap(PhSvcClPortHeap, 0, Size);
152 
153  if (!memory)
154  return NULL;
155 
156  *Offset = (ULONG)((ULONG_PTR)memory - (ULONG_PTR)PhSvcClPortHeap);
157 
158  return memory;
159 }
160 
162  _In_ PVOID Memory
163  )
164 {
165  if (!PhSvcClPortHeap)
166  return;
167 
168  RtlFreeHeap(PhSvcClPortHeap, 0, Memory);
169 }
170 
172  _In_opt_ PVOID String,
173  _In_ SIZE_T Length,
174  _Out_ PPH_RELATIVE_STRINGREF StringRef
175  )
176 {
177  PVOID memory;
178  SIZE_T length;
179  ULONG offset;
180 
181  if (Length != -1)
182  length = Length;
183  else
184  length = PhCountStringZ(String) * sizeof(WCHAR);
185 
186  if (length > MAXULONG32)
187  return NULL;
188 
189  memory = PhSvcpAllocateHeap(length, &offset);
190 
191  if (!memory)
192  return NULL;
193 
194  if (String)
195  memcpy(memory, String, length);
196 
197  StringRef->Length = (ULONG)length;
198  StringRef->Offset = offset;
199 
200  return memory;
201 }
202 
204  _Inout_ PPHSVC_API_MSG Message
205  )
206 {
207  NTSTATUS status;
208 
209  Message->h.u1.s1.DataLength = sizeof(PHSVC_API_MSG) - FIELD_OFFSET(PHSVC_API_MSG, p);
210  Message->h.u1.s1.TotalLength = sizeof(PHSVC_API_MSG);
211  Message->h.u2.ZeroInit = 0;
212 
213  status = NtRequestWaitReplyPort(PhSvcClPortHandle, &Message->h, &Message->h);
214 
215  if (!NT_SUCCESS(status))
216  return status;
217 
218  return Message->p.ReturnStatus;
219 }
220 
222  _In_ PPH_STRINGREF ApiId,
223  _In_reads_bytes_opt_(InLength) PVOID InBuffer,
224  _In_ ULONG InLength,
225  _Out_writes_bytes_opt_(OutLength) PVOID OutBuffer,
226  _In_ ULONG OutLength
227  )
228 {
229  NTSTATUS status;
230  PHSVC_API_MSG m;
231  PVOID apiId = NULL;
232 
233  memset(&m, 0, sizeof(PHSVC_API_MSG));
234 
235  if (!PhSvcClPortHandle)
236  return STATUS_PORT_DISCONNECTED;
237  if (InLength > sizeof(m.p.u.Plugin.i.Data))
238  return STATUS_BUFFER_OVERFLOW;
239 
241 
242  if (!(apiId = PhSvcpCreateString(ApiId->Buffer, ApiId->Length, &m.p.u.Plugin.i.ApiId)))
243  return STATUS_NO_MEMORY;
244 
245  if (InLength != 0)
246  memcpy(m.p.u.Plugin.i.Data, InBuffer, InLength);
247 
248  status = PhSvcpCallServer(&m);
249 
250  if (OutLength != 0)
251  memcpy(OutBuffer, m.p.u.Plugin.o.Data, min(OutLength, sizeof(m.p.u.Plugin.o.Data)));
252 
253  if (apiId)
254  PhSvcpFreeHeap(apiId);
255 
256  return status;
257 }
258 
260  _In_ PHSVC_API_NUMBER ApiNumber,
261  _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters
262  )
263 {
264  NTSTATUS status;
265  PHSVC_API_MSG m;
266  PVOID userName = NULL;
267  PVOID password = NULL;
268  ULONG passwordLength;
269  PVOID currentDirectory = NULL;
270  PVOID commandLine = NULL;
271  PVOID fileName = NULL;
272  PVOID desktopName = NULL;
273  PVOID serviceName = NULL;
274 
275  memset(&m, 0, sizeof(PHSVC_API_MSG));
276 
277  if (!PhSvcClPortHandle)
278  return STATUS_PORT_DISCONNECTED;
279 
280  m.p.ApiNumber = ApiNumber;
281 
282  m.p.u.ExecuteRunAsCommand.i.ProcessId = Parameters->ProcessId;
283  m.p.u.ExecuteRunAsCommand.i.LogonType = Parameters->LogonType;
284  m.p.u.ExecuteRunAsCommand.i.SessionId = Parameters->SessionId;
285  m.p.u.ExecuteRunAsCommand.i.UseLinkedToken = Parameters->UseLinkedToken;
286 
287  status = STATUS_NO_MEMORY;
288 
289  if (Parameters->UserName && !(userName = PhSvcpCreateString(Parameters->UserName, -1, &m.p.u.ExecuteRunAsCommand.i.UserName)))
290  goto CleanupExit;
291 
292  if (Parameters->Password)
293  {
294  if (!(password = PhSvcpCreateString(Parameters->Password, -1, &m.p.u.ExecuteRunAsCommand.i.Password)))
295  goto CleanupExit;
296 
297  passwordLength = m.p.u.ExecuteRunAsCommand.i.Password.Length;
298  }
299 
300  if (Parameters->CurrentDirectory && !(currentDirectory = PhSvcpCreateString(Parameters->CurrentDirectory, -1, &m.p.u.ExecuteRunAsCommand.i.CurrentDirectory)))
301  goto CleanupExit;
302  if (Parameters->CommandLine && !(commandLine = PhSvcpCreateString(Parameters->CommandLine, -1, &m.p.u.ExecuteRunAsCommand.i.CommandLine)))
303  goto CleanupExit;
304  if (Parameters->FileName && !(fileName = PhSvcpCreateString(Parameters->FileName, -1, &m.p.u.ExecuteRunAsCommand.i.FileName)))
305  goto CleanupExit;
306  if (Parameters->DesktopName && !(desktopName = PhSvcpCreateString(Parameters->DesktopName, -1, &m.p.u.ExecuteRunAsCommand.i.DesktopName)))
307  goto CleanupExit;
308  if (Parameters->ServiceName && !(serviceName = PhSvcpCreateString(Parameters->ServiceName, -1, &m.p.u.ExecuteRunAsCommand.i.ServiceName)))
309  goto CleanupExit;
310 
311  status = PhSvcpCallServer(&m);
312 
313 CleanupExit:
314  if (serviceName) PhSvcpFreeHeap(serviceName);
315  if (desktopName) PhSvcpFreeHeap(desktopName);
316  if (fileName) PhSvcpFreeHeap(fileName);
317  if (commandLine) PhSvcpFreeHeap(commandLine);
318  if (currentDirectory) PhSvcpFreeHeap(currentDirectory);
319 
320  if (password)
321  {
322  RtlSecureZeroMemory(password, passwordLength);
323  PhSvcpFreeHeap(password);
324  }
325 
326  if (userName) PhSvcpFreeHeap(userName);
327 
328  return status;
329 }
330 
332  _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters
333  )
334 {
336 }
337 
339  _In_opt_ PVOID BaseAddress,
340  _In_opt_ PWSTR Name
341  )
342 {
343  NTSTATUS status;
344  PHSVC_API_MSG m;
345  PVOID name = NULL;
346 
347  memset(&m, 0, sizeof(PHSVC_API_MSG));
348 
349  if (!PhSvcClPortHandle)
350  return STATUS_PORT_DISCONNECTED;
351 
353 
354  m.p.u.UnloadDriver.i.BaseAddress = BaseAddress;
355 
356  if (Name)
357  {
358  name = PhSvcpCreateString(Name, -1, &m.p.u.UnloadDriver.i.Name);
359 
360  if (!name)
361  return STATUS_NO_MEMORY;
362  }
363 
364  status = PhSvcpCallServer(&m);
365 
366  if (name)
367  PhSvcpFreeHeap(name);
368 
369  return status;
370 }
371 
373  _In_ HANDLE ProcessId,
375  _In_ ULONG Argument
376  )
377 {
378  PHSVC_API_MSG m;
379 
380  if (!PhSvcClPortHandle)
381  return STATUS_PORT_DISCONNECTED;
382 
384  m.p.u.ControlProcess.i.ProcessId = ProcessId;
385  m.p.u.ControlProcess.i.Command = Command;
386  m.p.u.ControlProcess.i.Argument = Argument;
387 
388  return PhSvcpCallServer(&m);
389 }
390 
392  _In_ PWSTR ServiceName,
394  )
395 {
396  NTSTATUS status;
397  PHSVC_API_MSG m;
398  PVOID serviceName;
399 
400  if (!PhSvcClPortHandle)
401  return STATUS_PORT_DISCONNECTED;
402 
404 
405  serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.ControlService.i.ServiceName);
406  m.p.u.ControlService.i.Command = Command;
407 
408  if (serviceName)
409  {
410  status = PhSvcpCallServer(&m);
411  }
412  else
413  {
414  status = STATUS_NO_MEMORY;
415  }
416 
417  if (serviceName)
418  PhSvcpFreeHeap(serviceName);
419 
420  return status;
421 }
422 
424  _In_ PWSTR ServiceName,
425  _In_opt_ PWSTR DisplayName,
426  _In_ ULONG ServiceType,
427  _In_ ULONG StartType,
428  _In_ ULONG ErrorControl,
429  _In_opt_ PWSTR BinaryPathName,
430  _In_opt_ PWSTR LoadOrderGroup,
431  _Out_opt_ PULONG TagId,
432  _In_opt_ PWSTR Dependencies,
433  _In_opt_ PWSTR ServiceStartName,
434  _In_opt_ PWSTR Password
435  )
436 {
437  NTSTATUS status;
438  PHSVC_API_MSG m;
439  PVOID serviceName = NULL;
440  PVOID displayName = NULL;
441  PVOID binaryPathName = NULL;
442  PVOID loadOrderGroup = NULL;
443  PVOID dependencies = NULL;
444  PVOID serviceStartName = NULL;
445  PVOID password = NULL;
446  ULONG passwordLength;
447 
448  memset(&m, 0, sizeof(PHSVC_API_MSG));
449 
450  if (!PhSvcClPortHandle)
451  return STATUS_PORT_DISCONNECTED;
452 
454 
455  m.p.u.CreateService.i.ServiceType = ServiceType;
456  m.p.u.CreateService.i.StartType = StartType;
457  m.p.u.CreateService.i.ErrorControl = ErrorControl;
458  m.p.u.CreateService.i.TagIdSpecified = TagId != NULL;
459 
460  status = STATUS_NO_MEMORY;
461 
462  if (!(serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.CreateService.i.ServiceName)))
463  goto CleanupExit;
464  if (DisplayName && !(displayName = PhSvcpCreateString(DisplayName, -1, &m.p.u.CreateService.i.DisplayName)))
465  goto CleanupExit;
466  if (BinaryPathName && !(binaryPathName = PhSvcpCreateString(BinaryPathName, -1, &m.p.u.CreateService.i.BinaryPathName)))
467  goto CleanupExit;
468  if (LoadOrderGroup && !(loadOrderGroup = PhSvcpCreateString(LoadOrderGroup, -1, &m.p.u.CreateService.i.LoadOrderGroup)))
469  goto CleanupExit;
470 
471  if (Dependencies)
472  {
473  SIZE_T dependenciesLength;
474  SIZE_T partCount;
475  PWSTR part;
476 
477  dependenciesLength = sizeof(WCHAR);
478  part = Dependencies;
479 
480  do
481  {
482  partCount = PhCountStringZ(part) + 1;
483  part += partCount;
484  dependenciesLength += partCount * sizeof(WCHAR);
485  } while (partCount != 1); // stop at empty dependency part
486 
487  if (!(dependencies = PhSvcpCreateString(Dependencies, dependenciesLength, &m.p.u.CreateService.i.Dependencies)))
488  goto CleanupExit;
489  }
490 
491  if (ServiceStartName && !(serviceStartName = PhSvcpCreateString(ServiceStartName, -1, &m.p.u.CreateService.i.ServiceStartName)))
492  goto CleanupExit;
493 
494  if (Password)
495  {
496  if (!(password = PhSvcpCreateString(Password, -1, &m.p.u.CreateService.i.Password)))
497  goto CleanupExit;
498 
499  passwordLength = m.p.u.CreateService.i.Password.Length;
500  }
501 
502  status = PhSvcpCallServer(&m);
503 
504  if (NT_SUCCESS(status))
505  {
506  if (TagId)
507  *TagId = m.p.u.CreateService.o.TagId;
508  }
509 
510 CleanupExit:
511  if (password)
512  {
513  RtlSecureZeroMemory(password, passwordLength);
514  PhSvcpFreeHeap(password);
515  }
516 
517  if (serviceStartName) PhSvcpFreeHeap(serviceStartName);
518  if (dependencies) PhSvcpFreeHeap(dependencies);
519  if (loadOrderGroup) PhSvcpFreeHeap(loadOrderGroup);
520  if (binaryPathName) PhSvcpFreeHeap(binaryPathName);
521  if (displayName) PhSvcpFreeHeap(displayName);
522  if (serviceName) PhSvcpFreeHeap(serviceName);
523 
524  return status;
525 }
526 
528  _In_ PWSTR ServiceName,
529  _In_ ULONG ServiceType,
530  _In_ ULONG StartType,
531  _In_ ULONG ErrorControl,
532  _In_opt_ PWSTR BinaryPathName,
533  _In_opt_ PWSTR LoadOrderGroup,
534  _Out_opt_ PULONG TagId,
535  _In_opt_ PWSTR Dependencies,
536  _In_opt_ PWSTR ServiceStartName,
537  _In_opt_ PWSTR Password,
538  _In_opt_ PWSTR DisplayName
539  )
540 {
541  NTSTATUS status;
542  PHSVC_API_MSG m;
543  PVOID serviceName = NULL;
544  PVOID binaryPathName = NULL;
545  PVOID loadOrderGroup = NULL;
546  PVOID dependencies = NULL;
547  PVOID serviceStartName = NULL;
548  PVOID password = NULL;
549  ULONG passwordLength;
550  PVOID displayName = NULL;
551 
552  memset(&m, 0, sizeof(PHSVC_API_MSG));
553 
554  if (!PhSvcClPortHandle)
555  return STATUS_PORT_DISCONNECTED;
556 
558 
559  m.p.u.ChangeServiceConfig.i.ServiceType = ServiceType;
560  m.p.u.ChangeServiceConfig.i.StartType = StartType;
561  m.p.u.ChangeServiceConfig.i.ErrorControl = ErrorControl;
562  m.p.u.ChangeServiceConfig.i.TagIdSpecified = TagId != NULL;
563 
564  status = STATUS_NO_MEMORY;
565 
566  if (!(serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.ChangeServiceConfig.i.ServiceName)))
567  goto CleanupExit;
568  if (BinaryPathName && !(binaryPathName = PhSvcpCreateString(BinaryPathName, -1, &m.p.u.ChangeServiceConfig.i.BinaryPathName)))
569  goto CleanupExit;
570  if (LoadOrderGroup && !(loadOrderGroup = PhSvcpCreateString(LoadOrderGroup, -1, &m.p.u.ChangeServiceConfig.i.LoadOrderGroup)))
571  goto CleanupExit;
572 
573  if (Dependencies)
574  {
575  SIZE_T dependenciesLength;
576  SIZE_T partCount;
577  PWSTR part;
578 
579  dependenciesLength = sizeof(WCHAR);
580  part = Dependencies;
581 
582  do
583  {
584  partCount = PhCountStringZ(part) + 1;
585  part += partCount;
586  dependenciesLength += partCount * sizeof(WCHAR);
587  } while (partCount != 1); // stop at empty dependency part
588 
589  if (!(dependencies = PhSvcpCreateString(Dependencies, dependenciesLength, &m.p.u.ChangeServiceConfig.i.Dependencies)))
590  goto CleanupExit;
591  }
592 
593  if (ServiceStartName && !(serviceStartName = PhSvcpCreateString(ServiceStartName, -1, &m.p.u.ChangeServiceConfig.i.ServiceStartName)))
594  goto CleanupExit;
595 
596  if (Password)
597  {
598  if (!(password = PhSvcpCreateString(Password, -1, &m.p.u.ChangeServiceConfig.i.Password)))
599  goto CleanupExit;
600 
601  passwordLength = m.p.u.ChangeServiceConfig.i.Password.Length;
602  }
603 
604  if (DisplayName && !(displayName = PhSvcpCreateString(DisplayName, -1, &m.p.u.ChangeServiceConfig.i.DisplayName)))
605  goto CleanupExit;
606 
607  status = PhSvcpCallServer(&m);
608 
609  if (NT_SUCCESS(status))
610  {
611  if (TagId)
612  *TagId = m.p.u.ChangeServiceConfig.o.TagId;
613  }
614 
615 CleanupExit:
616  if (displayName) PhSvcpFreeHeap(displayName);
617 
618  if (password)
619  {
620  RtlSecureZeroMemory(password, passwordLength);
621  PhSvcpFreeHeap(password);
622  }
623 
624  if (serviceStartName) PhSvcpFreeHeap(serviceStartName);
625  if (dependencies) PhSvcpFreeHeap(dependencies);
626  if (loadOrderGroup) PhSvcpFreeHeap(loadOrderGroup);
627  if (binaryPathName) PhSvcpFreeHeap(binaryPathName);
628  if (serviceName) PhSvcpFreeHeap(serviceName);
629 
630  return status;
631 }
632 
634  _Inout_ PPH_BYTES_BUILDER BytesBuilder,
635  _In_ PVOID Buffer,
636  _In_ SIZE_T Length
637  )
638 {
639  return PhAppendBytesBuilderEx(BytesBuilder, Buffer, Length, sizeof(ULONG_PTR), NULL);
640 }
641 
643  _Inout_ PPH_BYTES_BUILDER BytesBuilder,
644  _Inout_ PVOID *PointerInBytesBuilder,
645  _In_ SIZE_T Length,
646  _In_ SIZE_T Alignment,
647  _In_ ULONG NumberOfPointersToRebase,
648  _In_ va_list ArgPtr
649  )
650 {
651  va_list argptr;
652  ULONG_PTR oldBase;
653  SIZE_T oldLength;
654  ULONG_PTR newBase;
655  SIZE_T offset;
656  ULONG i;
657  PVOID *pointer;
658 
659  oldBase = (ULONG_PTR)BytesBuilder->Bytes->Buffer;
660  oldLength = BytesBuilder->Bytes->Length;
661  assert((ULONG_PTR)PointerInBytesBuilder >= oldBase && (ULONG_PTR)PointerInBytesBuilder + sizeof(PVOID) <= oldBase + oldLength);
662 
663  if (!*PointerInBytesBuilder)
664  return;
665 
666  PhAppendBytesBuilderEx(BytesBuilder, *PointerInBytesBuilder, Length, Alignment, &offset);
667  newBase = (ULONG_PTR)BytesBuilder->Bytes->Buffer;
668 
669  PointerInBytesBuilder = (PVOID *)((ULONG_PTR)PointerInBytesBuilder - oldBase + newBase);
670  *PointerInBytesBuilder = (PVOID)offset;
671 
672  argptr = ArgPtr;
673 
674  for (i = 0; i < NumberOfPointersToRebase; i++)
675  {
676  pointer = va_arg(argptr, PVOID *);
677  assert(!*pointer || ((ULONG_PTR)*pointer >= oldBase && (ULONG_PTR)*pointer + sizeof(PVOID) <= oldBase + oldLength));
678 
679  if (*pointer)
680  *pointer = (PVOID)((ULONG_PTR)*pointer - oldBase + newBase);
681  }
682 }
683 
685  _Inout_ PPH_BYTES_BUILDER BytesBuilder,
686  _Inout_ PVOID *PointerInBytesBuilder,
687  _In_ SIZE_T Length,
688  _In_ SIZE_T Alignment,
689  _In_ ULONG NumberOfPointersToRebase,
690  ...
691  )
692 {
693  va_list argptr;
694 
695  va_start(argptr, NumberOfPointersToRebase);
696  PhSvcpPackBuffer_V(BytesBuilder, PointerInBytesBuilder, Length, Alignment, NumberOfPointersToRebase, argptr);
697 }
698 
700  _In_opt_ PWSTR String,
701  _In_ BOOLEAN Multi
702  )
703 {
704  SIZE_T length = 0;
705 
706  if (String)
707  {
708  if (Multi)
709  {
710  PWSTR part = String;
711  SIZE_T partCount;
712 
713  while (TRUE)
714  {
715  partCount = PhCountStringZ(part);
716  length += (partCount + 1) * sizeof(WCHAR);
717 
718  if (partCount == 0)
719  break;
720 
721  part += partCount + 1;
722  }
723  }
724  else
725  {
726  length = (PhCountStringZ(String) + 1) * sizeof(WCHAR);
727  }
728  }
729 
730  return length;
731 }
732 
734  _In_ PWSTR ServiceName,
735  _In_ ULONG InfoLevel,
736  _In_ PVOID Info
737  )
738 {
739  NTSTATUS status;
740  PHSVC_API_MSG m;
741  PVOID serviceName = NULL;
742  PVOID info = NULL;
743  PH_BYTES_BUILDER bb;
744 
745  if (!PhSvcClPortHandle)
746  return STATUS_PORT_DISCONNECTED;
747 
749 
750  m.p.u.ChangeServiceConfig2.i.InfoLevel = InfoLevel;
751 
752  if (serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.ChangeServiceConfig2.i.ServiceName))
753  {
754  switch (InfoLevel)
755  {
756  case SERVICE_CONFIG_FAILURE_ACTIONS:
757  {
758  LPSERVICE_FAILURE_ACTIONS failureActions = Info;
759  LPSERVICE_FAILURE_ACTIONS packedFailureActions;
760 
761  PhInitializeBytesBuilder(&bb, 200);
762  packedFailureActions = PhSvcpPackRoot(&bb, failureActions, sizeof(SERVICE_FAILURE_ACTIONS));
763  PhSvcpPackBuffer(&bb, &packedFailureActions->lpRebootMsg, PhSvcpBufferLengthStringZ(failureActions->lpRebootMsg, FALSE), sizeof(WCHAR),
764  1, &packedFailureActions);
765  PhSvcpPackBuffer(&bb, &packedFailureActions->lpCommand, PhSvcpBufferLengthStringZ(failureActions->lpCommand, FALSE), sizeof(WCHAR),
766  1, &packedFailureActions);
767 
768  if (failureActions->cActions != 0 && failureActions->lpsaActions)
769  {
770  PhSvcpPackBuffer(&bb, &packedFailureActions->lpsaActions, failureActions->cActions * sizeof(SC_ACTION), __alignof(SC_ACTION),
771  1, &packedFailureActions);
772  }
773 
774  info = PhSvcpCreateString(bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info);
776  }
777  break;
778  case SERVICE_CONFIG_DELAYED_AUTO_START_INFO:
779  info = PhSvcpCreateString(Info, sizeof(SERVICE_DELAYED_AUTO_START_INFO), &m.p.u.ChangeServiceConfig2.i.Info);
780  break;
781  case SERVICE_CONFIG_FAILURE_ACTIONS_FLAG:
782  info = PhSvcpCreateString(Info, sizeof(SERVICE_FAILURE_ACTIONS_FLAG), &m.p.u.ChangeServiceConfig2.i.Info);
783  break;
784  case SERVICE_CONFIG_SERVICE_SID_INFO:
785  info = PhSvcpCreateString(Info, sizeof(SERVICE_SID_INFO), &m.p.u.ChangeServiceConfig2.i.Info);
786  break;
787  case SERVICE_CONFIG_REQUIRED_PRIVILEGES_INFO:
788  {
789  LPSERVICE_REQUIRED_PRIVILEGES_INFO requiredPrivilegesInfo = Info;
790  LPSERVICE_REQUIRED_PRIVILEGES_INFO packedRequiredPrivilegesInfo;
791 
792  PhInitializeBytesBuilder(&bb, 100);
793  packedRequiredPrivilegesInfo = PhSvcpPackRoot(&bb, requiredPrivilegesInfo, sizeof(SERVICE_REQUIRED_PRIVILEGES_INFO));
794  PhSvcpPackBuffer(&bb, &packedRequiredPrivilegesInfo->pmszRequiredPrivileges, PhSvcpBufferLengthStringZ(requiredPrivilegesInfo->pmszRequiredPrivileges, TRUE), sizeof(WCHAR),
795  1, &packedRequiredPrivilegesInfo);
796 
797  info = PhSvcpCreateString(bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info);
799  }
800  break;
801  case SERVICE_CONFIG_PRESHUTDOWN_INFO:
802  info = PhSvcpCreateString(Info, sizeof(SERVICE_PRESHUTDOWN_INFO), &m.p.u.ChangeServiceConfig2.i.Info);
803  break;
804  case SERVICE_CONFIG_TRIGGER_INFO:
805  {
806  PSERVICE_TRIGGER_INFO triggerInfo = Info;
807  PSERVICE_TRIGGER_INFO packedTriggerInfo;
808  ULONG i;
809  PSERVICE_TRIGGER packedTrigger;
810  ULONG j;
811  PSERVICE_TRIGGER_SPECIFIC_DATA_ITEM packedDataItem;
812  ULONG alignment;
813 
814  PhInitializeBytesBuilder(&bb, 400);
815  packedTriggerInfo = PhSvcpPackRoot(&bb, triggerInfo, sizeof(SERVICE_TRIGGER_INFO));
816 
817  if (triggerInfo->cTriggers != 0 && triggerInfo->pTriggers)
818  {
819  PhSvcpPackBuffer(&bb, &packedTriggerInfo->pTriggers, triggerInfo->cTriggers * sizeof(SERVICE_TRIGGER), __alignof(SERVICE_TRIGGER),
820  1, &packedTriggerInfo);
821 
822  for (i = 0; i < triggerInfo->cTriggers; i++)
823  {
824  packedTrigger = PhOffsetBytesBuilder(&bb, (SIZE_T)packedTriggerInfo->pTriggers + i * sizeof(SERVICE_TRIGGER));
825 
826  PhSvcpPackBuffer(&bb, &packedTrigger->pTriggerSubtype, sizeof(GUID), __alignof(GUID),
827  2, &packedTriggerInfo, &packedTrigger);
828 
829  if (packedTrigger->cDataItems != 0 && packedTrigger->pDataItems)
830  {
831  PhSvcpPackBuffer(&bb, &packedTrigger->pDataItems, packedTrigger->cDataItems * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM), __alignof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM),
832  2, &packedTriggerInfo, &packedTrigger);
833 
834  for (j = 0; j < packedTrigger->cDataItems; j++)
835  {
836  packedDataItem = PhOffsetBytesBuilder(&bb, (SIZE_T)packedTrigger->pDataItems + j * sizeof(SERVICE_TRIGGER_SPECIFIC_DATA_ITEM));
837  alignment = 1;
838 
839  switch (packedDataItem->dwDataType)
840  {
841  case SERVICE_TRIGGER_DATA_TYPE_BINARY:
842  case SERVICE_TRIGGER_DATA_TYPE_LEVEL:
843  alignment = sizeof(CHAR);
844  break;
845  case SERVICE_TRIGGER_DATA_TYPE_STRING:
846  alignment = sizeof(WCHAR);
847  break;
848  case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ANY:
849  case SERVICE_TRIGGER_DATA_TYPE_KEYWORD_ALL:
850  alignment = sizeof(ULONG64);
851  break;
852  }
853 
854  PhSvcpPackBuffer(&bb, &packedDataItem->pData, packedDataItem->cbData, alignment,
855  3, &packedTriggerInfo, &packedTrigger, &packedDataItem);
856  }
857  }
858  }
859  }
860 
861  info = PhSvcpCreateString(bb.Bytes->Buffer, bb.Bytes->Length, &m.p.u.ChangeServiceConfig2.i.Info);
863  }
864  break;
865  case SERVICE_CONFIG_LAUNCH_PROTECTED:
866  info = PhSvcpCreateString(Info, sizeof(SERVICE_LAUNCH_PROTECTED_INFO), &m.p.u.ChangeServiceConfig2.i.Info);
867  break;
868  default:
869  status = STATUS_INVALID_PARAMETER;
870  break;
871  }
872  }
873 
874  if (serviceName && info)
875  {
876  status = PhSvcpCallServer(&m);
877  }
878  else
879  {
880  status = STATUS_NO_MEMORY;
881  }
882 
883  if (info)
884  PhSvcpFreeHeap(info);
885  if (serviceName)
886  PhSvcpFreeHeap(serviceName);
887 
888  return status;
889 }
890 
892  _In_ PVOID TcpRow
893  )
894 {
895  PHSVC_API_MSG m;
896  struct
897  {
898  DWORD dwState;
899  DWORD dwLocalAddr;
900  DWORD dwLocalPort;
901  DWORD dwRemoteAddr;
902  DWORD dwRemotePort;
903  } *tcpRow = TcpRow;
904 
905  if (!PhSvcClPortHandle)
906  return STATUS_PORT_DISCONNECTED;
907 
909 
910  m.p.u.SetTcpEntry.i.State = tcpRow->dwState;
911  m.p.u.SetTcpEntry.i.LocalAddress = tcpRow->dwLocalAddr;
912  m.p.u.SetTcpEntry.i.LocalPort = tcpRow->dwLocalPort;
913  m.p.u.SetTcpEntry.i.RemoteAddress = tcpRow->dwRemoteAddr;
914  m.p.u.SetTcpEntry.i.RemotePort = tcpRow->dwRemotePort;
915 
916  return PhSvcpCallServer(&m);
917 }
918 
920  _In_ HANDLE ThreadId,
921  _In_ PHSVC_API_CONTROLTHREAD_COMMAND Command,
922  _In_ ULONG Argument
923  )
924 {
925  PHSVC_API_MSG m;
926 
927  if (!PhSvcClPortHandle)
928  return STATUS_PORT_DISCONNECTED;
929 
931  m.p.u.ControlThread.i.ThreadId = ThreadId;
932  m.p.u.ControlThread.i.Command = Command;
933  m.p.u.ControlThread.i.Argument = Argument;
934 
935  return PhSvcpCallServer(&m);
936 }
937 
939  _In_ PSID AccountSid,
940  _In_ PUNICODE_STRING UserRight
941  )
942 {
943  NTSTATUS status;
944  PHSVC_API_MSG m;
945  PVOID accountSid = NULL;
946  PVOID userRight = NULL;
947 
948  if (!PhSvcClPortHandle)
949  return STATUS_PORT_DISCONNECTED;
950 
952 
953  status = STATUS_NO_MEMORY;
954 
955  if (!(accountSid = PhSvcpCreateString(AccountSid, RtlLengthSid(AccountSid), &m.p.u.AddAccountRight.i.AccountSid)))
956  goto CleanupExit;
957  if (!(userRight = PhSvcpCreateString(UserRight->Buffer, UserRight->Length, &m.p.u.AddAccountRight.i.UserRight)))
958  goto CleanupExit;
959 
960  status = PhSvcpCallServer(&m);
961 
962 CleanupExit:
963  if (userRight) PhSvcpFreeHeap(userRight);
964  if (accountSid) PhSvcpFreeHeap(accountSid);
965 
966  return status;
967 }
968 
970  _In_ PPH_RUNAS_SERVICE_PARAMETERS Parameters
971  )
972 {
974 }
975 
977  _In_ SYSTEM_MEMORY_LIST_COMMAND Command
978  )
979 {
980  PHSVC_API_MSG m;
981 
982  if (!PhSvcClPortHandle)
983  return STATUS_PORT_DISCONNECTED;
984 
986  m.p.u.IssueMemoryListCommand.i.Command = Command;
987 
988  return PhSvcpCallServer(&m);
989 }
990 
992  _In_opt_ HWND hWnd,
993  _In_ UINT Msg,
994  _In_ WPARAM wParam,
995  _In_ LPARAM lParam
996  )
997 {
998  PHSVC_API_MSG m;
999 
1000  if (!PhSvcClPortHandle)
1001  return STATUS_PORT_DISCONNECTED;
1002 
1004  m.p.u.PostMessage.i.hWnd = hWnd;
1005  m.p.u.PostMessage.i.Msg = Msg;
1006  m.p.u.PostMessage.i.wParam = wParam;
1007  m.p.u.PostMessage.i.lParam = lParam;
1008 
1009  return PhSvcpCallServer(&m);
1010 }
1011 
1013  _In_opt_ HWND hWnd,
1014  _In_ UINT Msg,
1015  _In_ WPARAM wParam,
1016  _In_ LPARAM lParam
1017  )
1018 {
1019  PHSVC_API_MSG m;
1020 
1021  if (!PhSvcClPortHandle)
1022  return STATUS_PORT_DISCONNECTED;
1023 
1025  m.p.u.PostMessage.i.hWnd = hWnd;
1026  m.p.u.PostMessage.i.Msg = Msg;
1027  m.p.u.PostMessage.i.wParam = wParam;
1028  m.p.u.PostMessage.i.lParam = lParam;
1029 
1030  return PhSvcpCallServer(&m);
1031 }
1032 
1034  _In_ PWSTR FileName
1035  )
1036 {
1037  NTSTATUS status;
1038  PHSVC_API_MSG m;
1039  PVOID fileName = NULL;
1040 
1041  memset(&m, 0, sizeof(PHSVC_API_MSG));
1042 
1043  if (!PhSvcClPortHandle)
1044  return STATUS_PORT_DISCONNECTED;
1045 
1047  fileName = PhSvcpCreateString(FileName, -1, &m.p.u.CreateProcessIgnoreIfeoDebugger.i.FileName);
1048 
1049  if (!fileName)
1050  return STATUS_NO_MEMORY;
1051 
1052  status = PhSvcpCallServer(&m);
1053 
1054  if (fileName)
1055  PhSvcpFreeHeap(fileName);
1056 
1057  return status;
1058 }
1059 
1060 PSECURITY_DESCRIPTOR PhpAbsoluteToSelfRelativeSD(
1061  _In_ PSECURITY_DESCRIPTOR AbsoluteSecurityDescriptor,
1062  _Out_ PULONG BufferSize
1063  )
1064 {
1065  NTSTATUS status;
1066  ULONG bufferSize = 0;
1067  PSECURITY_DESCRIPTOR selfRelativeSecurityDescriptor;
1068 
1069  status = RtlAbsoluteToSelfRelativeSD(AbsoluteSecurityDescriptor, NULL, &bufferSize);
1070 
1071  if (status != STATUS_BUFFER_TOO_SMALL)
1072  return NULL;
1073 
1074  selfRelativeSecurityDescriptor = PhAllocate(bufferSize);
1075  status = RtlAbsoluteToSelfRelativeSD(AbsoluteSecurityDescriptor, selfRelativeSecurityDescriptor, &bufferSize);
1076 
1077  if (!NT_SUCCESS(status))
1078  {
1079  PhFree(selfRelativeSecurityDescriptor);
1080  return NULL;
1081  }
1082 
1083  *BufferSize = bufferSize;
1084 
1085  return selfRelativeSecurityDescriptor;
1086 }
1087 
1089  _In_ PWSTR ServiceName,
1090  _In_ SECURITY_INFORMATION SecurityInformation,
1091  _In_ PSECURITY_DESCRIPTOR SecurityDescriptor
1092  )
1093 {
1094  NTSTATUS status;
1095  PHSVC_API_MSG m;
1096  PSECURITY_DESCRIPTOR selfRelativeSecurityDescriptor = NULL;
1097  ULONG bufferSize;
1098  PVOID serviceName = NULL;
1099  PVOID copiedSelfRelativeSecurityDescriptor = NULL;
1100 
1101  if (!PhSvcClPortHandle)
1102  return STATUS_PORT_DISCONNECTED;
1103 
1104  selfRelativeSecurityDescriptor = PhpAbsoluteToSelfRelativeSD(SecurityDescriptor, &bufferSize);
1105 
1106  if (!selfRelativeSecurityDescriptor)
1107  {
1108  status = STATUS_BAD_DESCRIPTOR_FORMAT;
1109  goto CleanupExit;
1110  }
1111 
1113  m.p.u.SetServiceSecurity.i.SecurityInformation = SecurityInformation;
1114  status = STATUS_NO_MEMORY;
1115 
1116  if (!(serviceName = PhSvcpCreateString(ServiceName, -1, &m.p.u.SetServiceSecurity.i.ServiceName)))
1117  goto CleanupExit;
1118  if (!(copiedSelfRelativeSecurityDescriptor = PhSvcpCreateString(selfRelativeSecurityDescriptor, bufferSize, &m.p.u.SetServiceSecurity.i.SecurityDescriptor)))
1119  goto CleanupExit;
1120 
1121  status = PhSvcpCallServer(&m);
1122 
1123 CleanupExit:
1124  if (selfRelativeSecurityDescriptor) PhFree(selfRelativeSecurityDescriptor);
1125  if (serviceName) PhSvcpFreeHeap(serviceName);
1126  if (copiedSelfRelativeSecurityDescriptor) PhSvcpFreeHeap(copiedSelfRelativeSecurityDescriptor);
1127 
1128  return status;
1129 }
1130 
1132  _In_ PWSTR DbgHelpPath
1133  )
1134 {
1135  NTSTATUS status;
1136  PHSVC_API_MSG m;
1137  PVOID dbgHelpPath = NULL;
1138 
1139  memset(&m, 0, sizeof(PHSVC_API_MSG));
1140 
1141  if (!PhSvcClPortHandle)
1142  return STATUS_PORT_DISCONNECTED;
1143 
1145  dbgHelpPath = PhSvcpCreateString(DbgHelpPath, -1, &m.p.u.LoadDbgHelp.i.DbgHelpPath);
1146 
1147  if (!dbgHelpPath)
1148  return STATUS_NO_MEMORY;
1149 
1150  status = PhSvcpCallServer(&m);
1151 
1152  if (dbgHelpPath)
1153  PhSvcpFreeHeap(dbgHelpPath);
1154 
1155  return status;
1156 }
1157 
1159  _In_ HANDLE ProcessHandle,
1160  _In_ HANDLE ProcessId,
1161  _In_ HANDLE FileHandle,
1162  _In_ ULONG DumpType
1163  )
1164 {
1165  NTSTATUS status;
1166  PHSVC_API_MSG m;
1167  HANDLE serverHandle = NULL;
1168  HANDLE remoteProcessHandle = NULL;
1169  HANDLE remoteFileHandle = NULL;
1170 
1171  memset(&m, 0, sizeof(PHSVC_API_MSG));
1172 
1173  if (!PhSvcClPortHandle)
1174  return STATUS_PORT_DISCONNECTED;
1175 
1176  // For typical uses of this function, the client has more privileges than the server.
1177  // We therefore duplicate our handles into the server's process.
1178 
1180 
1181  if (!NT_SUCCESS(status = PhOpenProcess(&serverHandle, PROCESS_DUP_HANDLE, PhSvcClServerProcessId)))
1182  {
1183  goto CleanupExit;
1184  }
1185 
1186  if (!NT_SUCCESS(status = PhDuplicateObject(NtCurrentProcess(), ProcessHandle, serverHandle, &remoteProcessHandle,
1188  {
1189  goto CleanupExit;
1190  }
1191 
1192  if (!NT_SUCCESS(status = PhDuplicateObject(NtCurrentProcess(), FileHandle, serverHandle, &remoteFileHandle,
1193  FILE_GENERIC_WRITE, 0, 0)))
1194  {
1195  goto CleanupExit;
1196  }
1197 
1198  m.p.u.WriteMiniDumpProcess.i.LocalProcessHandle = HandleToUlong(remoteProcessHandle);
1199  m.p.u.WriteMiniDumpProcess.i.ProcessId = HandleToUlong(ProcessId);
1200  m.p.u.WriteMiniDumpProcess.i.LocalFileHandle = HandleToUlong(remoteFileHandle);
1201  m.p.u.WriteMiniDumpProcess.i.DumpType = DumpType;
1202 
1203  status = PhSvcpCallServer(&m);
1204 
1205 CleanupExit:
1206  if (serverHandle)
1207  {
1208  if (remoteProcessHandle)
1209  PhDuplicateObject(serverHandle, remoteProcessHandle, NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
1210  if (remoteFileHandle)
1211  PhDuplicateObject(serverHandle, remoteFileHandle, NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
1212 
1213  NtClose(serverHandle);
1214  }
1215 
1216  return status;
1217 }