H
hsnonr
Guest
Hi,
I want to create an anti-malware service as a protected service under Windows platform. So, I started to develop an ELAM driver. I've created a test driver on top of ELAM driver from the Microsoft's driver samples (Microsoft/Windows-driver-samples). Then I've created a test certificate with Early Launch Anti-Malware Driver EKU and finally followed the instructions to create a protected service (Protecting Anti-Malware Services). I've successfully install my service as protected service. But when I try to start the service with "StartService" function GetLastError returns 1053 error code. If I try to start service with "StartServiceCtrlDispatcher" function, GetLastError returns 1063 error code. How can I fix this issue?
Please kindly guide me.
Regards
Here is service code:
int wmain(int argc, wchar_t *argv[])
{
if ((argc > 1) && ((*argv[1] == L'-' || (*argv[1] == L'/'))))
{
if (_wcsicmp(L"install", argv[1] + 1) == 0)
{
// Install the service when the command is
// "-install" or "/install".
if(!InstallService(
SERVICE_NAME, // Name of service
SERVICE_DISPLAY_NAME, // Name to display
SERVICE_START_TYPE, // Service start type
SERVICE_DEPENDENCIES, // Dependencies
SERVICE_ACCOUNT, // Service running account
SERVICE_PASSWORD // Password of the account
))
{
CSampleService service(SERVICE_NAME);
if (!CServiceBase::Run(service))
{
wprintf(L"Service failed to run w/err %d\n", GetLastError());
}
}
}
}
return 0;
}
bool InstallElamDriver()
{
HANDLE elamHandle = NULL;
elamHandle = CreateFile(L"C:\\Windows\\system32\\drivers\\elamsample.sys",
FILE_READ_DATA,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (InstallELAMCertificateInfo(elamHandle) == FALSE)
{
wprintf(L"InstallElamCertificateInfo failed (%d)\n", GetLastError());
return false;
}
return true;
}
//
// FUNCTION: InstallService
//
// PURPOSE: Install the current application as a service to the local
// service control manager database.
//
// PARAMETERS:
// * pszServiceName - the name of the service to be installed
// * pszDisplayName - the display name of the service
// * dwStartType - the service start option. This parameter can be one of
// the following values: SERVICE_AUTO_START, SERVICE_BOOT_START,
// SERVICE_DEMAND_START, SERVICE_DISABLED, SERVICE_SYSTEM_START.
// * pszDependencies - a pointer to a double null-terminated array of null-
// separated names of services or load ordering groups that the system
// must start before this service.
// * pszAccount - the name of the account under which the service runs.
// * pszPassword - the password to the account name.
//
// NOTE: If the function fails to install the service, it prints the error
// in the standard output stream for users to diagnose the problem.
//
bool InstallService(PWSTR pszServiceName,
PWSTR pszDisplayName,
DWORD dwStartType,
PWSTR pszDependencies,
PWSTR pszAccount,
PWSTR pszPassword)
{
wchar_t szPath[MAX_PATH];
SC_HANDLE schSCManager = NULL;
SC_HANDLE schService = NULL;
bool isServiceRunning = false;
EXPLICIT_ACCESS ea;
SECURITY_DESCRIPTOR sd;
PSECURITY_DESCRIPTOR psd = NULL;
PACL pacl = NULL;
PACL pNewAcl = NULL;
BOOL bDaclPresent = FALSE;
BOOL bDaclDefaulted = FALSE;
DWORD dwError = 0;
DWORD dwSize = 0;
DWORD dwBytesNeeded = 0;
if (!InstallElamDriver())
{
goto Cleanup;
}
if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0)
{
//wprintf(L"GetModuleFileName failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
// Open the local default service control manager database
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT |
SC_MANAGER_CREATE_SERVICE);
if (schSCManager == NULL)
{
//wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
// Install the service into SCM by calling CreateService
schService = CreateService(
schSCManager, // SCManager database
pszServiceName, // Name of service
pszDisplayName, // Name to display
SERVICE_ALL_ACCESS, // Desired access
SERVICE_WIN32_OWN_PROCESS, // Service type
dwStartType, // Service start type
SERVICE_ERROR_NORMAL, // Error control type
szPath, // Service's binary
NULL, // No load ordering group
NULL, // No tag identifier
pszDependencies, // Dependencies
pszAccount, // Service running account
pszPassword // Password of the account
);
if (schService == NULL)
{
wprintf(L"CreateService failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
SERVICE_FAILURE_ACTIONS sfa;
SC_ACTION actions;
actions.Type = SC_ACTION_RESTART;
actions.Delay = 0;// wait 0 milisecond before restarting
sfa.dwResetPeriod = INFINITE;
sfa.lpCommand = NULL;
sfa.lpRebootMsg = NULL;
sfa.cActions = 1;
sfa.lpsaActions = &actions;
if (!ChangeServiceConfig2(schService, SERVICE_CONFIG_FAILURE_ACTIONS, &sfa))
{
wprintf(L"%s is installed but configurations can not execute.%d\n", pszServiceName, GetLastError());
goto Cleanup;
}
if (!QueryServiceObjectSecurity(schService,
DACL_SECURITY_INFORMATION,
&psd, // using NULL does not work on all versions
0,
&dwBytesNeeded))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
dwSize = dwBytesNeeded;
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwSize);
if (psd == NULL)
{
// Note: HeapAlloc does not support GetLastError.
wprintf(L"HeapAlloc failed\n");
goto Cleanup;
}
if (!QueryServiceObjectSecurity(schService,
DACL_SECURITY_INFORMATION, psd, dwSize, &dwBytesNeeded))
{
wprintf(L"QueryServiceObjectSecurity failed (%d)\n", GetLastError());
goto Cleanup;
}
}
else
{
wprintf(L"QueryServiceObjectSecurity failed (%d)\n", GetLastError());
goto Cleanup;
}
}
// Get the DACL.
if (!GetSecurityDescriptorDacl(psd, &bDaclPresent, &pacl,
&bDaclDefaulted))
{
wprintf(L"GetSecurityDescriptorDacl failed(%d)\n", GetLastError());
goto Cleanup;
}
// Build the ACE.
BuildExplicitAccessWithName(&ea, TEXT("GUEST"),
SERVICE_START |READ_CONTROL,
SET_ACCESS, NO_INHERITANCE);
dwError = SetEntriesInAcl(1, &ea, pacl, &pNewAcl);
if (dwError != ERROR_SUCCESS)
{
wprintf(L"SetEntriesInAcl failed(%d)\n", dwError);
goto Cleanup;
}
// Initialize a new security descriptor.
if (!InitializeSecurityDescriptor(&sd,
SECURITY_DESCRIPTOR_REVISION))
{
wprintf(L"InitializeSecurityDescriptor failed(%d)\n", GetLastError());
goto Cleanup;
}
// Set the new DACL in the security descriptor.
if (!SetSecurityDescriptorDacl(&sd, TRUE, pNewAcl, FALSE))
{
wprintf(L"SetSecurityDescriptorDacl failed(%d)\n", GetLastError());
goto Cleanup;
}
// Set the new DACL for the service object.
if (!SetServiceObjectSecurity(schService,
DACL_SECURITY_INFORMATION, &sd))
{
wprintf(L"SetServiceObjectSecurity failed(%d)\n", GetLastError());
goto Cleanup;
}
else {
wprintf(L"Service DACL updated successfully\n");
}
SERVICE_LAUNCH_PROTECTED_INFO Info;
Info.dwLaunchProtected = SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT;
if (ChangeServiceConfig2(schService,
SERVICE_CONFIG_LAUNCH_PROTECTED,
&Info) == FALSE)
{
wprintf(L"SERVICE_CONFIG_LAUNCH_PROTECTED error: %d\n", GetLastError());
}
if (!StartService(schService,0,nullptr))
{
wprintf(L"StartService error: %d\n", GetLastError());
}else
{
isServiceRunning = true;
}
wprintf(L"%s is installed.\n", pszServiceName);
Cleanup:
// Centralized cleanup for all allocated resources.
if (schSCManager)
{
CloseServiceHandle(schSCManager);
schSCManager = NULL;
}
if (schService)
{
CloseServiceHandle(schService);
schService = NULL;
}
return isServiceRunning;
}
BOOL CServiceBase::Run(CServiceBase &service)
{
wprintf(L"Enter CServiceBase::Run \n");
s_service = &service;
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ service.m_name, ServiceMain },
{ NULL, NULL }
};
// Connects the main thread of a service process to the service control
// manager, which causes the thread to be the service control dispatcher
// thread for the calling process. This call returns when the service has
// stopped. The process should simply terminate when the call returns.
BOOL isServiceStarted = StartServiceCtrlDispatcher(serviceTable);
if (!isServiceStarted)
{
wprintf(L"StartServiceCtrlDispatcher w/err %d\n", GetLastError());
}
return isServiceStarted;
}
//
// FUNCTION: CServiceBase::ServiceMain(DWORD, PWSTR *)
//
// PURPOSE: Entry point for the service. It registers the handler function
// for the service and starts the service.
//
// PARAMETERS:
// * dwArgc - number of command line arguments
// * lpszArgv - array of command line arguments
//
void WINAPI CServiceBase::ServiceMain(DWORD dwArgc, PWSTR *pszArgv)
{
wprintf(L"Enter CServiceBase::ServiceMain \n");
assert(s_service != NULL);
// Register the handler function for the service
s_service->m_statusHandle = RegisterServiceCtrlHandler(
s_service->m_name, ServiceCtrlHandler);
if (s_service->m_statusHandle == NULL)
{
throw GetLastError();
}
// Start the service.
s_service->Start(dwArgc, pszArgv);
}
Continue reading...
I want to create an anti-malware service as a protected service under Windows platform. So, I started to develop an ELAM driver. I've created a test driver on top of ELAM driver from the Microsoft's driver samples (Microsoft/Windows-driver-samples). Then I've created a test certificate with Early Launch Anti-Malware Driver EKU and finally followed the instructions to create a protected service (Protecting Anti-Malware Services). I've successfully install my service as protected service. But when I try to start the service with "StartService" function GetLastError returns 1053 error code. If I try to start service with "StartServiceCtrlDispatcher" function, GetLastError returns 1063 error code. How can I fix this issue?
Please kindly guide me.
Regards
Here is service code:
int wmain(int argc, wchar_t *argv[])
{
if ((argc > 1) && ((*argv[1] == L'-' || (*argv[1] == L'/'))))
{
if (_wcsicmp(L"install", argv[1] + 1) == 0)
{
// Install the service when the command is
// "-install" or "/install".
if(!InstallService(
SERVICE_NAME, // Name of service
SERVICE_DISPLAY_NAME, // Name to display
SERVICE_START_TYPE, // Service start type
SERVICE_DEPENDENCIES, // Dependencies
SERVICE_ACCOUNT, // Service running account
SERVICE_PASSWORD // Password of the account
))
{
CSampleService service(SERVICE_NAME);
if (!CServiceBase::Run(service))
{
wprintf(L"Service failed to run w/err %d\n", GetLastError());
}
}
}
}
return 0;
}
bool InstallElamDriver()
{
HANDLE elamHandle = NULL;
elamHandle = CreateFile(L"C:\\Windows\\system32\\drivers\\elamsample.sys",
FILE_READ_DATA,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL
);
if (InstallELAMCertificateInfo(elamHandle) == FALSE)
{
wprintf(L"InstallElamCertificateInfo failed (%d)\n", GetLastError());
return false;
}
return true;
}
//
// FUNCTION: InstallService
//
// PURPOSE: Install the current application as a service to the local
// service control manager database.
//
// PARAMETERS:
// * pszServiceName - the name of the service to be installed
// * pszDisplayName - the display name of the service
// * dwStartType - the service start option. This parameter can be one of
// the following values: SERVICE_AUTO_START, SERVICE_BOOT_START,
// SERVICE_DEMAND_START, SERVICE_DISABLED, SERVICE_SYSTEM_START.
// * pszDependencies - a pointer to a double null-terminated array of null-
// separated names of services or load ordering groups that the system
// must start before this service.
// * pszAccount - the name of the account under which the service runs.
// * pszPassword - the password to the account name.
//
// NOTE: If the function fails to install the service, it prints the error
// in the standard output stream for users to diagnose the problem.
//
bool InstallService(PWSTR pszServiceName,
PWSTR pszDisplayName,
DWORD dwStartType,
PWSTR pszDependencies,
PWSTR pszAccount,
PWSTR pszPassword)
{
wchar_t szPath[MAX_PATH];
SC_HANDLE schSCManager = NULL;
SC_HANDLE schService = NULL;
bool isServiceRunning = false;
EXPLICIT_ACCESS ea;
SECURITY_DESCRIPTOR sd;
PSECURITY_DESCRIPTOR psd = NULL;
PACL pacl = NULL;
PACL pNewAcl = NULL;
BOOL bDaclPresent = FALSE;
BOOL bDaclDefaulted = FALSE;
DWORD dwError = 0;
DWORD dwSize = 0;
DWORD dwBytesNeeded = 0;
if (!InstallElamDriver())
{
goto Cleanup;
}
if (GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)) == 0)
{
//wprintf(L"GetModuleFileName failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
// Open the local default service control manager database
schSCManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT |
SC_MANAGER_CREATE_SERVICE);
if (schSCManager == NULL)
{
//wprintf(L"OpenSCManager failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
// Install the service into SCM by calling CreateService
schService = CreateService(
schSCManager, // SCManager database
pszServiceName, // Name of service
pszDisplayName, // Name to display
SERVICE_ALL_ACCESS, // Desired access
SERVICE_WIN32_OWN_PROCESS, // Service type
dwStartType, // Service start type
SERVICE_ERROR_NORMAL, // Error control type
szPath, // Service's binary
NULL, // No load ordering group
NULL, // No tag identifier
pszDependencies, // Dependencies
pszAccount, // Service running account
pszPassword // Password of the account
);
if (schService == NULL)
{
wprintf(L"CreateService failed w/err 0x%08lx\n", GetLastError());
goto Cleanup;
}
SERVICE_FAILURE_ACTIONS sfa;
SC_ACTION actions;
actions.Type = SC_ACTION_RESTART;
actions.Delay = 0;// wait 0 milisecond before restarting
sfa.dwResetPeriod = INFINITE;
sfa.lpCommand = NULL;
sfa.lpRebootMsg = NULL;
sfa.cActions = 1;
sfa.lpsaActions = &actions;
if (!ChangeServiceConfig2(schService, SERVICE_CONFIG_FAILURE_ACTIONS, &sfa))
{
wprintf(L"%s is installed but configurations can not execute.%d\n", pszServiceName, GetLastError());
goto Cleanup;
}
if (!QueryServiceObjectSecurity(schService,
DACL_SECURITY_INFORMATION,
&psd, // using NULL does not work on all versions
0,
&dwBytesNeeded))
{
if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
{
dwSize = dwBytesNeeded;
psd = (PSECURITY_DESCRIPTOR)HeapAlloc(GetProcessHeap(),
HEAP_ZERO_MEMORY, dwSize);
if (psd == NULL)
{
// Note: HeapAlloc does not support GetLastError.
wprintf(L"HeapAlloc failed\n");
goto Cleanup;
}
if (!QueryServiceObjectSecurity(schService,
DACL_SECURITY_INFORMATION, psd, dwSize, &dwBytesNeeded))
{
wprintf(L"QueryServiceObjectSecurity failed (%d)\n", GetLastError());
goto Cleanup;
}
}
else
{
wprintf(L"QueryServiceObjectSecurity failed (%d)\n", GetLastError());
goto Cleanup;
}
}
// Get the DACL.
if (!GetSecurityDescriptorDacl(psd, &bDaclPresent, &pacl,
&bDaclDefaulted))
{
wprintf(L"GetSecurityDescriptorDacl failed(%d)\n", GetLastError());
goto Cleanup;
}
// Build the ACE.
BuildExplicitAccessWithName(&ea, TEXT("GUEST"),
SERVICE_START |READ_CONTROL,
SET_ACCESS, NO_INHERITANCE);
dwError = SetEntriesInAcl(1, &ea, pacl, &pNewAcl);
if (dwError != ERROR_SUCCESS)
{
wprintf(L"SetEntriesInAcl failed(%d)\n", dwError);
goto Cleanup;
}
// Initialize a new security descriptor.
if (!InitializeSecurityDescriptor(&sd,
SECURITY_DESCRIPTOR_REVISION))
{
wprintf(L"InitializeSecurityDescriptor failed(%d)\n", GetLastError());
goto Cleanup;
}
// Set the new DACL in the security descriptor.
if (!SetSecurityDescriptorDacl(&sd, TRUE, pNewAcl, FALSE))
{
wprintf(L"SetSecurityDescriptorDacl failed(%d)\n", GetLastError());
goto Cleanup;
}
// Set the new DACL for the service object.
if (!SetServiceObjectSecurity(schService,
DACL_SECURITY_INFORMATION, &sd))
{
wprintf(L"SetServiceObjectSecurity failed(%d)\n", GetLastError());
goto Cleanup;
}
else {
wprintf(L"Service DACL updated successfully\n");
}
SERVICE_LAUNCH_PROTECTED_INFO Info;
Info.dwLaunchProtected = SERVICE_LAUNCH_PROTECTED_ANTIMALWARE_LIGHT;
if (ChangeServiceConfig2(schService,
SERVICE_CONFIG_LAUNCH_PROTECTED,
&Info) == FALSE)
{
wprintf(L"SERVICE_CONFIG_LAUNCH_PROTECTED error: %d\n", GetLastError());
}
if (!StartService(schService,0,nullptr))
{
wprintf(L"StartService error: %d\n", GetLastError());
}else
{
isServiceRunning = true;
}
wprintf(L"%s is installed.\n", pszServiceName);
Cleanup:
// Centralized cleanup for all allocated resources.
if (schSCManager)
{
CloseServiceHandle(schSCManager);
schSCManager = NULL;
}
if (schService)
{
CloseServiceHandle(schService);
schService = NULL;
}
return isServiceRunning;
}
BOOL CServiceBase::Run(CServiceBase &service)
{
wprintf(L"Enter CServiceBase::Run \n");
s_service = &service;
SERVICE_TABLE_ENTRY serviceTable[] =
{
{ service.m_name, ServiceMain },
{ NULL, NULL }
};
// Connects the main thread of a service process to the service control
// manager, which causes the thread to be the service control dispatcher
// thread for the calling process. This call returns when the service has
// stopped. The process should simply terminate when the call returns.
BOOL isServiceStarted = StartServiceCtrlDispatcher(serviceTable);
if (!isServiceStarted)
{
wprintf(L"StartServiceCtrlDispatcher w/err %d\n", GetLastError());
}
return isServiceStarted;
}
//
// FUNCTION: CServiceBase::ServiceMain(DWORD, PWSTR *)
//
// PURPOSE: Entry point for the service. It registers the handler function
// for the service and starts the service.
//
// PARAMETERS:
// * dwArgc - number of command line arguments
// * lpszArgv - array of command line arguments
//
void WINAPI CServiceBase::ServiceMain(DWORD dwArgc, PWSTR *pszArgv)
{
wprintf(L"Enter CServiceBase::ServiceMain \n");
assert(s_service != NULL);
// Register the handler function for the service
s_service->m_statusHandle = RegisterServiceCtrlHandler(
s_service->m_name, ServiceCtrlHandler);
if (s_service->m_statusHandle == NULL)
{
throw GetLastError();
}
// Start the service.
s_service->Start(dwArgc, pszArgv);
}
Continue reading...