531 lines
13 KiB
C
531 lines
13 KiB
C
/*
|
|
* Process Hacker -
|
|
* service support functions
|
|
*
|
|
* Copyright (C) 2010-2012 wj32
|
|
*
|
|
* This file is part of Process Hacker.
|
|
*
|
|
* Process Hacker is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* Process Hacker is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include <ph.h>
|
|
#include <svcsup.h>
|
|
#include <subprocesstag.h>
|
|
|
|
#define SIP(String, Integer) { (String), (PVOID)(Integer) }
|
|
|
|
static PH_KEY_VALUE_PAIR PhpServiceStatePairs[] =
|
|
{
|
|
SIP(L"Stopped", SERVICE_STOPPED),
|
|
SIP(L"Start pending", SERVICE_START_PENDING),
|
|
SIP(L"Stop pending", SERVICE_STOP_PENDING),
|
|
SIP(L"Running", SERVICE_RUNNING),
|
|
SIP(L"Continue pending", SERVICE_CONTINUE_PENDING),
|
|
SIP(L"Pause pending", SERVICE_PAUSE_PENDING),
|
|
SIP(L"Paused", SERVICE_PAUSED)
|
|
};
|
|
|
|
static PH_KEY_VALUE_PAIR PhpServiceTypePairs[] =
|
|
{
|
|
SIP(L"Driver", SERVICE_KERNEL_DRIVER),
|
|
SIP(L"FS driver", SERVICE_FILE_SYSTEM_DRIVER),
|
|
SIP(L"Own process", SERVICE_WIN32_OWN_PROCESS),
|
|
SIP(L"Share process", SERVICE_WIN32_SHARE_PROCESS),
|
|
SIP(L"Own interactive process", SERVICE_WIN32_OWN_PROCESS | SERVICE_INTERACTIVE_PROCESS),
|
|
SIP(L"Share interactive process", SERVICE_WIN32_SHARE_PROCESS | SERVICE_INTERACTIVE_PROCESS),
|
|
SIP(L"User own process", SERVICE_USER_OWN_PROCESS),
|
|
SIP(L"User own process (instance)", SERVICE_USER_OWN_PROCESS | SERVICE_USERSERVICE_INSTANCE),
|
|
SIP(L"User share process", SERVICE_USER_SHARE_PROCESS),
|
|
SIP(L"User share process (instance)", SERVICE_USER_SHARE_PROCESS | SERVICE_USERSERVICE_INSTANCE),
|
|
};
|
|
|
|
static PH_KEY_VALUE_PAIR PhpServiceStartTypePairs[] =
|
|
{
|
|
SIP(L"Disabled", SERVICE_DISABLED),
|
|
SIP(L"Boot start", SERVICE_BOOT_START),
|
|
SIP(L"System start", SERVICE_SYSTEM_START),
|
|
SIP(L"Auto start", SERVICE_AUTO_START),
|
|
SIP(L"Demand start", SERVICE_DEMAND_START)
|
|
};
|
|
|
|
static PH_KEY_VALUE_PAIR PhpServiceErrorControlPairs[] =
|
|
{
|
|
SIP(L"Ignore", SERVICE_ERROR_IGNORE),
|
|
SIP(L"Normal", SERVICE_ERROR_NORMAL),
|
|
SIP(L"Severe", SERVICE_ERROR_SEVERE),
|
|
SIP(L"Critical", SERVICE_ERROR_CRITICAL)
|
|
};
|
|
|
|
WCHAR *PhServiceTypeStrings[10] = { L"Driver", L"FS driver", L"Own process", L"Share process",
|
|
L"Own interactive process", L"Share interactive process", L"User own process", L"User own process (instance)",
|
|
L"User share process", L"User share process (instance)" };
|
|
WCHAR *PhServiceStartTypeStrings[5] = { L"Disabled", L"Boot start", L"System start",
|
|
L"Auto start", L"Demand start" };
|
|
WCHAR *PhServiceErrorControlStrings[4] = { L"Ignore", L"Normal", L"Severe", L"Critical" };
|
|
|
|
PVOID PhEnumServices(
|
|
_In_ SC_HANDLE ScManagerHandle,
|
|
_In_opt_ ULONG Type,
|
|
_In_opt_ ULONG State,
|
|
_Out_ PULONG Count
|
|
)
|
|
{
|
|
static ULONG initialBufferSize = 0x8000;
|
|
LOGICAL result;
|
|
PVOID buffer;
|
|
ULONG bufferSize;
|
|
ULONG returnLength;
|
|
ULONG servicesReturned;
|
|
|
|
if (!Type)
|
|
Type = WindowsVersion >= WINDOWS_10 ? SERVICE_TYPE_ALL : (SERVICE_DRIVER | SERVICE_WIN32);
|
|
if (!State)
|
|
State = SERVICE_STATE_ALL;
|
|
|
|
bufferSize = initialBufferSize;
|
|
buffer = PhAllocate(bufferSize);
|
|
|
|
if (!(result = EnumServicesStatusEx(
|
|
ScManagerHandle,
|
|
SC_ENUM_PROCESS_INFO,
|
|
Type,
|
|
State,
|
|
buffer,
|
|
bufferSize,
|
|
&returnLength,
|
|
&servicesReturned,
|
|
NULL,
|
|
NULL
|
|
)))
|
|
{
|
|
if (GetLastError() == ERROR_MORE_DATA)
|
|
{
|
|
PhFree(buffer);
|
|
bufferSize += returnLength;
|
|
buffer = PhAllocate(bufferSize);
|
|
|
|
result = EnumServicesStatusEx(
|
|
ScManagerHandle,
|
|
SC_ENUM_PROCESS_INFO,
|
|
Type,
|
|
State,
|
|
buffer,
|
|
bufferSize,
|
|
&returnLength,
|
|
&servicesReturned,
|
|
NULL,
|
|
NULL
|
|
);
|
|
}
|
|
|
|
if (!result)
|
|
{
|
|
PhFree(buffer);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
if (bufferSize <= 0x20000) initialBufferSize = bufferSize;
|
|
*Count = servicesReturned;
|
|
|
|
return buffer;
|
|
}
|
|
|
|
SC_HANDLE PhOpenService(
|
|
_In_ PWSTR ServiceName,
|
|
_In_ ACCESS_MASK DesiredAccess
|
|
)
|
|
{
|
|
SC_HANDLE scManagerHandle;
|
|
SC_HANDLE serviceHandle;
|
|
|
|
scManagerHandle = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
|
|
|
|
if (!scManagerHandle)
|
|
return NULL;
|
|
|
|
serviceHandle = OpenService(scManagerHandle, ServiceName, DesiredAccess);
|
|
CloseServiceHandle(scManagerHandle);
|
|
|
|
return serviceHandle;
|
|
}
|
|
|
|
PVOID PhGetServiceConfig(
|
|
_In_ SC_HANDLE ServiceHandle
|
|
)
|
|
{
|
|
PVOID buffer;
|
|
ULONG bufferSize = 0x200;
|
|
|
|
buffer = PhAllocate(bufferSize);
|
|
|
|
if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize))
|
|
{
|
|
PhFree(buffer);
|
|
buffer = PhAllocate(bufferSize);
|
|
|
|
if (!QueryServiceConfig(ServiceHandle, buffer, bufferSize, &bufferSize))
|
|
{
|
|
PhFree(buffer);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
PVOID PhQueryServiceVariableSize(
|
|
_In_ SC_HANDLE ServiceHandle,
|
|
_In_ ULONG InfoLevel
|
|
)
|
|
{
|
|
PVOID buffer;
|
|
ULONG bufferSize = 0x100;
|
|
|
|
buffer = PhAllocate(bufferSize);
|
|
|
|
if (!QueryServiceConfig2(
|
|
ServiceHandle,
|
|
InfoLevel,
|
|
(BYTE *)buffer,
|
|
bufferSize,
|
|
&bufferSize
|
|
))
|
|
{
|
|
PhFree(buffer);
|
|
buffer = PhAllocate(bufferSize);
|
|
|
|
if (!QueryServiceConfig2(
|
|
ServiceHandle,
|
|
InfoLevel,
|
|
(BYTE *)buffer,
|
|
bufferSize,
|
|
&bufferSize
|
|
))
|
|
{
|
|
PhFree(buffer);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
PPH_STRING PhGetServiceDescription(
|
|
_In_ SC_HANDLE ServiceHandle
|
|
)
|
|
{
|
|
PPH_STRING description = NULL;
|
|
LPSERVICE_DESCRIPTION serviceDescription;
|
|
|
|
serviceDescription = PhQueryServiceVariableSize(ServiceHandle, SERVICE_CONFIG_DESCRIPTION);
|
|
|
|
if (serviceDescription)
|
|
{
|
|
if (serviceDescription->lpDescription)
|
|
description = PhCreateString(serviceDescription->lpDescription);
|
|
|
|
PhFree(serviceDescription);
|
|
|
|
return description;
|
|
}
|
|
else
|
|
{
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
BOOLEAN PhGetServiceDelayedAutoStart(
|
|
_In_ SC_HANDLE ServiceHandle,
|
|
_Out_ PBOOLEAN DelayedAutoStart
|
|
)
|
|
{
|
|
SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;
|
|
ULONG returnLength;
|
|
|
|
if (QueryServiceConfig2(
|
|
ServiceHandle,
|
|
SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
|
|
(BYTE *)&delayedAutoStartInfo,
|
|
sizeof(SERVICE_DELAYED_AUTO_START_INFO),
|
|
&returnLength
|
|
))
|
|
{
|
|
*DelayedAutoStart = !!delayedAutoStartInfo.fDelayedAutostart;
|
|
return TRUE;
|
|
}
|
|
else
|
|
{
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
BOOLEAN PhSetServiceDelayedAutoStart(
|
|
_In_ SC_HANDLE ServiceHandle,
|
|
_In_ BOOLEAN DelayedAutoStart
|
|
)
|
|
{
|
|
SERVICE_DELAYED_AUTO_START_INFO delayedAutoStartInfo;
|
|
|
|
delayedAutoStartInfo.fDelayedAutostart = DelayedAutoStart;
|
|
|
|
return !!ChangeServiceConfig2(
|
|
ServiceHandle,
|
|
SERVICE_CONFIG_DELAYED_AUTO_START_INFO,
|
|
&delayedAutoStartInfo
|
|
);
|
|
}
|
|
|
|
PWSTR PhGetServiceStateString(
|
|
_In_ ULONG ServiceState
|
|
)
|
|
{
|
|
PWSTR string;
|
|
|
|
if (PhFindStringSiKeyValuePairs(
|
|
PhpServiceStatePairs,
|
|
sizeof(PhpServiceStatePairs),
|
|
ServiceState,
|
|
&string
|
|
))
|
|
return string;
|
|
else
|
|
return L"Unknown";
|
|
}
|
|
|
|
PWSTR PhGetServiceTypeString(
|
|
_In_ ULONG ServiceType
|
|
)
|
|
{
|
|
PWSTR string;
|
|
|
|
if (PhFindStringSiKeyValuePairs(
|
|
PhpServiceTypePairs,
|
|
sizeof(PhpServiceTypePairs),
|
|
ServiceType,
|
|
&string
|
|
))
|
|
return string;
|
|
else
|
|
return L"Unknown";
|
|
}
|
|
|
|
ULONG PhGetServiceTypeInteger(
|
|
_In_ PWSTR ServiceType
|
|
)
|
|
{
|
|
ULONG integer;
|
|
|
|
if (PhFindIntegerSiKeyValuePairs(
|
|
PhpServiceTypePairs,
|
|
sizeof(PhpServiceTypePairs),
|
|
ServiceType,
|
|
&integer
|
|
))
|
|
return integer;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
PWSTR PhGetServiceStartTypeString(
|
|
_In_ ULONG ServiceStartType
|
|
)
|
|
{
|
|
PWSTR string;
|
|
|
|
if (PhFindStringSiKeyValuePairs(
|
|
PhpServiceStartTypePairs,
|
|
sizeof(PhpServiceStartTypePairs),
|
|
ServiceStartType,
|
|
&string
|
|
))
|
|
return string;
|
|
else
|
|
return L"Unknown";
|
|
}
|
|
|
|
ULONG PhGetServiceStartTypeInteger(
|
|
_In_ PWSTR ServiceStartType
|
|
)
|
|
{
|
|
ULONG integer;
|
|
|
|
if (PhFindIntegerSiKeyValuePairs(
|
|
PhpServiceStartTypePairs,
|
|
sizeof(PhpServiceStartTypePairs),
|
|
ServiceStartType,
|
|
&integer
|
|
))
|
|
return integer;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
PWSTR PhGetServiceErrorControlString(
|
|
_In_ ULONG ServiceErrorControl
|
|
)
|
|
{
|
|
PWSTR string;
|
|
|
|
if (PhFindStringSiKeyValuePairs(
|
|
PhpServiceErrorControlPairs,
|
|
sizeof(PhpServiceErrorControlPairs),
|
|
ServiceErrorControl,
|
|
&string
|
|
))
|
|
return string;
|
|
else
|
|
return L"Unknown";
|
|
}
|
|
|
|
ULONG PhGetServiceErrorControlInteger(
|
|
_In_ PWSTR ServiceErrorControl
|
|
)
|
|
{
|
|
ULONG integer;
|
|
|
|
if (PhFindIntegerSiKeyValuePairs(
|
|
PhpServiceErrorControlPairs,
|
|
sizeof(PhpServiceErrorControlPairs),
|
|
ServiceErrorControl,
|
|
&integer
|
|
))
|
|
return integer;
|
|
else
|
|
return -1;
|
|
}
|
|
|
|
PPH_STRING PhGetServiceNameFromTag(
|
|
_In_ HANDLE ProcessId,
|
|
_In_ PVOID ServiceTag
|
|
)
|
|
{
|
|
static PQUERY_TAG_INFORMATION I_QueryTagInformation = NULL;
|
|
PPH_STRING serviceName = NULL;
|
|
TAG_INFO_NAME_FROM_TAG nameFromTag;
|
|
|
|
if (!I_QueryTagInformation)
|
|
{
|
|
I_QueryTagInformation = PhGetModuleProcAddress(L"advapi32.dll", "I_QueryTagInformation");
|
|
|
|
if (!I_QueryTagInformation)
|
|
return NULL;
|
|
}
|
|
|
|
memset(&nameFromTag, 0, sizeof(TAG_INFO_NAME_FROM_TAG));
|
|
nameFromTag.InParams.dwPid = HandleToUlong(ProcessId);
|
|
nameFromTag.InParams.dwTag = PtrToUlong(ServiceTag);
|
|
|
|
I_QueryTagInformation(NULL, eTagInfoLevelNameFromTag, &nameFromTag);
|
|
|
|
if (nameFromTag.OutParams.pszName)
|
|
{
|
|
serviceName = PhCreateString(nameFromTag.OutParams.pszName);
|
|
LocalFree(nameFromTag.OutParams.pszName);
|
|
}
|
|
|
|
return serviceName;
|
|
}
|
|
|
|
NTSTATUS PhGetThreadServiceTag(
|
|
_In_ HANDLE ThreadHandle,
|
|
_In_opt_ HANDLE ProcessHandle,
|
|
_Out_ PVOID *ServiceTag
|
|
)
|
|
{
|
|
NTSTATUS status;
|
|
THREAD_BASIC_INFORMATION basicInfo;
|
|
BOOLEAN openedProcessHandle = FALSE;
|
|
|
|
if (!NT_SUCCESS(status = PhGetThreadBasicInformation(ThreadHandle, &basicInfo)))
|
|
return status;
|
|
|
|
if (!ProcessHandle)
|
|
{
|
|
if (!NT_SUCCESS(status = PhOpenThreadProcess(
|
|
ThreadHandle,
|
|
PROCESS_VM_READ,
|
|
&ProcessHandle
|
|
)))
|
|
return status;
|
|
|
|
openedProcessHandle = TRUE;
|
|
}
|
|
|
|
status = NtReadVirtualMemory(
|
|
ProcessHandle,
|
|
PTR_ADD_OFFSET(basicInfo.TebBaseAddress, FIELD_OFFSET(TEB, SubProcessTag)),
|
|
ServiceTag,
|
|
sizeof(PVOID),
|
|
NULL
|
|
);
|
|
|
|
if (openedProcessHandle)
|
|
NtClose(ProcessHandle);
|
|
|
|
return status;
|
|
}
|
|
|
|
NTSTATUS PhGetServiceDllParameter(
|
|
_In_ PPH_STRINGREF ServiceName,
|
|
_Out_ PPH_STRING *ServiceDll
|
|
)
|
|
{
|
|
static PH_STRINGREF servicesKeyName = PH_STRINGREF_INIT(L"System\\CurrentControlSet\\Services\\");
|
|
static PH_STRINGREF parameters = PH_STRINGREF_INIT(L"\\Parameters");
|
|
|
|
NTSTATUS status;
|
|
HANDLE keyHandle;
|
|
PPH_STRING keyName;
|
|
|
|
keyName = PhConcatStringRef3(&servicesKeyName, ServiceName, ¶meters);
|
|
|
|
if (NT_SUCCESS(status = PhOpenKey(
|
|
&keyHandle,
|
|
KEY_READ,
|
|
PH_KEY_LOCAL_MACHINE,
|
|
&keyName->sr,
|
|
0
|
|
)))
|
|
{
|
|
PPH_STRING serviceDllString;
|
|
|
|
if (serviceDllString = PhQueryRegistryString(keyHandle, L"ServiceDll"))
|
|
{
|
|
PPH_STRING expandedString;
|
|
|
|
if (expandedString = PhExpandEnvironmentStrings(&serviceDllString->sr))
|
|
{
|
|
*ServiceDll = expandedString;
|
|
PhDereferenceObject(serviceDllString);
|
|
}
|
|
else
|
|
{
|
|
*ServiceDll = serviceDllString;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
status = STATUS_NOT_FOUND;
|
|
}
|
|
|
|
NtClose(keyHandle);
|
|
}
|
|
|
|
PhDereferenceObject(keyName);
|
|
|
|
return status;
|
|
}
|