Все вышеперечисленные методы ненадежны. Идентификатор сеанса не обязательно равен 0 (по крайней мере, в предыдущих версиях Windows), Window Station имеет значение только WinSta0 , если «если служба работает в учетной записи LocalSystem и взаимодействует с рабочим столом».
Подробнее см. KB171890 .
Один из способов определения того, выполняется ли процесс как служба, заключается в следующем:
Обратите внимание: С помощью этого метода будут обнаружены только службы, установленные в базе данных служб, но не дочерние процессы, запущенные процессом службы, которые не зарегистрированы в базе данных. В этом случае это также не будет системная служба. * 1.
bool IsRunningAsService(unsigned int Pid) {
bool Result = false;
SC_HANDLE hScm = OpenSCManager(
0,
SERVICES_ACTIVE_DATABASE,
SC_MANAGER_ENUMERATE_SERVICE
);
if (hScm == 0) {
return Result;
}
DWORD ServicesBufferRequired = 0;
DWORD ResumeHandle = 0;
DWORD ServicesBufferSize = 0;
DWORD ServicesCount = 0;
ENUM_SERVICE_STATUS_PROCESS* ServicesBuffer = 0;
EnumServicesStatusEx(hScm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,
SERVICE_ACTIVE, 0, 0, &ServicesBufferRequired, &ServicesCount, &ResumeHandle, 0);
// Todo: Error handling (GetLastError() results are currently bogus?)
ServicesBuffer = (ENUM_SERVICE_STATUS_PROCESS*) new
char[ServicesBufferRequired];
ServicesBufferSize = ServicesBufferRequired;
EnumServicesStatusEx(hScm, SC_ENUM_PROCESS_INFO, SERVICE_WIN32,
SERVICE_ACTIVE, (LPBYTE) ServicesBuffer, ServicesBufferSize,
&ServicesBufferRequired, &ServicesCount, &ResumeHandle, 0);
ENUM_SERVICE_STATUS_PROCESS* ServicesBufferPtr = ServicesBuffer;
while (ServicesCount--) {
if (ServicesBufferPtr->ServiceStatusProcess.dwProcessId == Pid) {
Result = true;
break;
}
ServicesBufferPtr++;
}
delete [] ServicesBuffer;
CloseServiceHandle(hScm);
return Result;
}
Обратите внимание, что приведенный выше код должен содержать дополнительную обработку ошибок, особенно он должен вызываться в цикле, пока EnumServicesStatusEx не вернет ненулевое значение. Но, к сожалению, как я выяснил, GetLastError()
всегда возвращает 1 (ERROR_INVALID_FUNCTION) даже если буфер правильно заполнен данными.
* 1: Тестирование, если процесс был запущен службой: в этом случае вы можете использовать комбинацию других решений. Можно проверить, есть ли у процесса родительский (дедушкин ...) процесс, зарегистрированный как сервис. Вы можете использовать CreateToolhelp32Snapshot
API для этой цели. Однако, если родительский процесс уже убит, все становится сложнее. Я уверен, что есть какие-либо недокументированные настройки, которые могут определить, работает ли процесс как служба, кроме обычных подозреваемых, таких как SessionId = 0, WindowStation = 0, WSF_VISIBLE, Нет членства в интерактивной группе ...