How to block 'psexec' command for kill process and stop service?

RVR

New Member
Hi All,
We are having a Windows Service developed with Visual C++ (VS 2012), and we applied 'Protection' for this service (Aim is to prevent Kill process/Stop service from any other method). For applying protection into our service, we are editing the 'EXPLICIT_ACCESS' and 'SECURITY_DESCRIPTOR'.
But we can kill process/stop service using 'psexec' command even if the protection is enabled. So kindly help me to solve this issue, here is the sample code we used for applying protection:
----------------------------------------
BOOL SetServicePrivilege(long lUser, long lProtectService)
{
SECURITY_DESCRIPTOR sd;
LPTSTR lpszUser;
EXPLICIT_ACCESS eaPowUser;
PSID pAdminSID = NULL;
DWORD dwAccessPermissions = 0,dwError = 0,dwSize = 0;
PACL pacl = NULL,pNewAcl = NULL;
SC_HANDLE schManager = NULL,schService = NULL;
PSECURITY_DESCRIPTOR psd = NULL;
BOOL bDaclPresent = FALSE,bDaclDefaulted = FALSE,bSuccess = FALSE,bRelease = FALSE;
////////////////////////////////////////////////////////////////////////////////////
try
{
if(lUser == 1)
{
lpszUser = "Power Users";
if(lProtectService == 0)
{
dwAccessPermissions = SERVICE_ENUMERATE_DEPENDENTS | SERVICE_INTERROGATE |
SERVICE_PAUSE_CONTINUE | SERVICE_QUERY_CONFIG |
SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP |
SERVICE_USER_DEFINED_CONTROL | READ_CONTROL;
}
else
{
dwAccessPermissions = SERVICE_START | READ_CONTROL | DELETE;
}
}
else if(lUser == 2)
{
lpszUser = "Administrators";
if(lProtectService == 0)
{
dwAccessPermissions = SERVICE_CHANGE_CONFIG | SERVICE_ENUMERATE_DEPENDENTS |
SERVICE_INTERROGATE | SERVICE_PAUSE_CONTINUE |
SERVICE_QUERY_CONFIG | SERVICE_QUERY_STATUS | SERVICE_START |
SERVICE_STOP | SERVICE_USER_DEFINED_CONTROL | READ_CONTROL |
WRITE_OWNER | WRITE_DAC | DELETE ;
}
else
{
dwAccessPermissions = SERVICE_START | READ_CONTROL | DELETE;
}
}
else
{
goto cleanup;
}
schManager = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);// Obtain a handle to the Service Controller.
if(schManager == NULL)
{
goto cleanup;
}
schService = OpenService(schManager, "TestService", READ_CONTROL | WRITE_DAC);// Obtain a handle to the service.
if(schService == NULL)
{
goto cleanup;
}
psd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, SECURITY_DESCRIPTOR_MIN_LENGTH);
if(!QueryServiceObjectSecurity(schService, DACL_SECURITY_INFORMATION, psd, 0, &dwSize))// Get the current security descriptor.
{
long lError = GetLastError();
if(lError == ERROR_INSUFFICIENT_BUFFER)
{
psd = (PSECURITY_DESCRIPTOR) LocalAlloc(LPTR, dwSize);
if(psd == NULL)
{
goto cleanup;
}
else
{
bRelease = TRUE;
}
///////////////////
if(!QueryServiceObjectSecurity(schService, DACL_SECURITY_INFORMATION, psd, dwSize, &dwSize))
{
goto cleanup;
}
}
else
{
goto cleanup;
}
}
if(!GetSecurityDescriptorDacl(psd, &bDaclPresent, &pacl, &bDaclDefaulted))// Get the DACL.
{
goto cleanup;
}
SID_IDENTIFIER_AUTHORITY SIDAuthNT = SECURITY_NT_AUTHORITY;
if(!AllocateAndInitializeSid(&SIDAuthNT, 2,SECURITY_BUILTIN_DOMAIN_RID,DOMAIN_ALIAS_RID_ADMINS,0, 0, 0, 0, 0, 0,&pAdminSID))
{
goto cleanup;
}
///////////////////
EXPLICIT_ACCESS ea;
ZeroMemory(&ea, sizeof(EXPLICIT_ACCESS));
if(lProtectService == 0)
ea.grfAccessPermissions = KEY_ALL_ACCESS;
else
ea.grfAccessPermissions = SERVICE_START | READ_CONTROL | DELETE;
ea.grfAccessMode = SET_ACCESS;
ea.grfInheritance= NO_INHERITANCE;
ea.Trustee.TrusteeForm = TRUSTEE_IS_SID;
ea.Trustee.TrusteeType = TRUSTEE_IS_GROUP;
ea.Trustee.ptstrName = (LPTSTR) pAdminSID;
////////////////////////////////////////////
dwError = SetEntriesInAcl(1, &ea, pacl, &pNewAcl);
if(dwError != ERROR_SUCCESS)
{
goto cleanup;
}
if(!InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION))// Initialize a NEW Security Descriptor.
{
goto cleanup;
}
if(!SetSecurityDescriptorDacl(&sd, TRUE, pNewAcl, FALSE))// Set the new DACL in the Security Descriptor.
{
goto cleanup;
}
if(!SetServiceObjectSecurity(schService, DACL_SECURITY_INFORMATION, &sd))// Set the new DACL for the service object.
{
goto cleanup;
}
bSuccess = TRUE;

cleanup:
if(pNewAcl)
LocalFree((HLOCAL)pNewAcl);
if(bRelease)
{
if(psd)
{
LocalFree(psd);
}
}
if(schService)
CloseServiceHandle(schService);
if(schManager)
CloseServiceHandle(schManager);
}
catch(...)
{
return bSuccess;
}
return bSuccess;
}

Here are the steps for using 'psexec' command:

1. Download PSEXEC and unzip to some folder.
2. Open an elevated CMD prompt as an administrator.
3. Navigate to the folder where you unzipped PSEXEC.EXE
4. Run: PSEXEC -i -s -d CMD
5. You will have a new CMD prompt open, as though by magic.
6. In the new CMD prompt, prove who you are: WHOAMI/USER
7. Run the command: sc stop TestService
Here is the download link: PsExec - Windows Sysinternals

Thanks,
RVR
 
Out of curiosity. what kind of service are you creating? I believe psexec uses the SYSTEM user to execute code. You can also find programs similar to psexec with available source code if you search..
 
OUr service (TestService) is a Windows Service, and the TestService.exe is also running on SYSTEM account.

If we try the same (psexec command) for 'RpcSs (Remote Procedure Call)' service, then we can't stop this service. The error message is '[SC] ControlService FAILED 1052: The requested control is not valid for this service'.

So how can I prevent this 'psexec' command from Stopping our Service/Kill Process? Please help.
 
OUr service (TestService) is a Windows Service, and the TestService.exe is also running on SYSTEM account.

If we try the same (psexec command) for 'RpcSs (Remote Procedure Call)' service, then we can't stop this service. The error message is '[SC] ControlService FAILED 1052: The requested control is not valid for this service'.

So how can I prevent this 'psexec' command from Stopping our Service/Kill Process? Please help.

I'm guessing that service simply does not implement the stop function? Its been a few years since I've wrote a service myself, not sure if you can just programmatically ignore, or not respond to a stop request.
 
Yeah psexec executes with a service so it can run as SYSTEM. You'd need to remove the Stop method completely and add some other mechanism to stop the service which is what some AV products do. For the kill signal I believe you'd need to hook into the messaging system and intercept the messages for your service process.
 
Even if we remove all the methods related to Service Stop, then also the 'psexec' command (call the same command for two times) is stopping our service. Kindly help to overcome this issue.
 
Back
Top