Link to home
Start Free TrialLog in
Avatar of BigScott_27
BigScott_27

asked on

Need to kill a very stubborn Windows Service

Hello, I have been searching for code to stop a troublesome service. I found the code below on this site which I modified slightly, however when I try using it I get undeclared identifiers for:

TServiceStatusProcess,
QueryServiceStatusEx,
SC_STATUS_PROCESS_INFO, &
TProcRecordArray

I'm guessing its a missing uses that is causing the error, or perhaps this was from an earlier version of Delphi? Not to sure what the problem is to be honest but any help would be appreciated or even a better method to kill this service. No matter what I have tried thus far I get an access denied error.

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Tlhelp32, WinSvc, DateUtils, WinTypes;


function ServiceGetProcessID( sMachine, sService : string ) : DWord;

var
  //
  // service control
  // manager handle
  schm,
  //
  // service handle
  schs   : SC_Handle;
  //
  //
  // current service status
  buf : TServiceStatusProcess;
  handle : THandle;
  bytesneeded : DWord;
begin
  result := 0;

  // connect to the service
  // control manager
  schm := OpenSCManager(
    PChar(sMachine),
    Nil,
    SC_MANAGER_CONNECT);


  // if successful...
  if(schm > 0)then
  begin
    // open a handle to
    // the specified service
    schs := OpenService(
      schm,
      PChar(sService),
      // we want to
      // query service status
      SERVICE_QUERY_STATUS);

    // if successful...
    if(schs > 0)then
    begin
      // retrieve the current status
      // of the specified service
            bytesneeded := 0 ;
      if(QueryServiceStatusEx(schs, SC_STATUS_PROCESS_INFO, buf, sizeof(TServiceStatusProcess), bytesneeded))then
      begin
       Result := buf.dwProcessId;

      end;

      // close service handle
      CloseServiceHandle(schs);
    end;

    // close service control
    // manager handle
    CloseServiceHandle(schm);
  end;
end;

function SetPrivilege(aPrivilegeName: string; aEnabled: boolean): boolean;
var
  TP : TTokenPrivileges;
  TPPrev : TTokenPrivileges;
  Token : THandle;
  dwRetLen : DWord;
begin
  Result := False;
  OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, Token);
  TP.PrivilegeCount := 1;
  if (LookupPrivilegeValue(nil, PChar(aPrivilegeName), TP.Privileges[0].LUID)) then begin
    if (aEnabled) then
      TP.Privileges[0].Attributes := SE_PRIVILEGE_ENABLED
    else
      TP.Privileges[0].Attributes := 0;
    dwRetLen := 0;
    Result := WinTypes.AdjustTokenPrivileges(Token, False, TP, SizeOf(TPPrev), TPPrev, dwRetLen);
  end;
  CloseHandle(Token);
end;

Function KillProcessByPID( ProcId:Cardinal):Boolean;
var loopint:integer;
   Prochandle:Thandle;
   Killit:Boolean;
   ExitCode:Cardinal;
   ProcRecords:TProcRecordArray ;
   numProcIds : Integer ;
Begin
       if not SetPrivilege('SeDebugPrivilege', True) then exit;
       Prochandle:=OpenProcess(PROCESS_ALL_ACCESS, false,ProcId);
       ExitCode:=0;
       killit:=GetExitCodeProcess(ProcHandle,exitcode);
       TerminateProcess(Prochandle,exitcode) ;
       SetPrivilege('SeDebugPrivilege', False);
end;

I'm using delphi 6 for this project any help anyone could give me on this would be greatly appreciated.
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

You could try the following, which should alleviate the dependacy errors. Example usage first, code follows.

Regards,
Russell

var  dwProcID:      DWORD;
begin

  // Make sure to pass the Service NAME, not the Service Description
  dwProcID:=ServiceGetProcessID(EmptyStr, 'YourServiceName');
  if not(dwProcID = 0) then KillProcessByPID(dwProcID);

end;

-------------------------
unit SvcTerminate;

interface

uses
  Windows, WinSvc;

const
  SC_STATUS_PROCESS_INFO        =  0;

type
  _SERVICE_STATUS_PROCESS       =  packed record
     dwServiceType:             DWORD;
     dwCurrentState:            DWORD;
     dwControlsAccepted:        DWORD;
     dwWin32ExitCode:           DWORD;
     dwServiceSpecificExitCode: DWORD;
     dwCheckPoint:              DWORD;
     dwWaitHint:                DWORD;
     dwProcessId:               DWORD;
     dwServiceFlags:            DWORD;
  end;
  SERVICE_STATUS_PROCESS        =  _SERVICE_STATUS_PROCESS;
  TServiceStatusProcess         =  SERVICE_STATUS_PROCESS;
  LPSERVICE_STATUS_PROCESS      =  ^SERVICE_STATUS_PROCESS;
  PServiceStatusProcess         =  ^TServiceStatusProcess;

function   QueryServiceStatusEx(hService: SC_HANDLE; InfoLevel: Integer; lpBuffer: Pointer; cbBufSize: DWORD; pcbBytesNeeded: PDWORD): BOOL; stdcall; external 'advapi32';

procedure  ModifySecurity(Enable: Boolean);
function   ServiceGetProcessID(MachineName, ServiceName: String): DWORD;
function   KillProcessByPID(ProcessID: DWORD): Boolean;

implementation

function KillProcessByPID(ProcessID: DWORD): Boolean;
var  hProc:         THandle;
begin

  // Set default result
  result:=False;

  // Enable permissions
  ModifySecurity(True);

  // Resource protection
  try
     // Open process
     hProc:=OpenProcess(PROCESS_ALL_ACCESS, False, ProcessID);
     // Check handle
     if not(hProc = 0) then
     begin
        // Resource protection
        try
           // Terminate
           result:=TerminateProcess(hProc, 0);
        finally
           // Close process handle
           CloseHandle(hProc);
        end;
     end;
  finally
     // Disable the permissions
     ModifySecurity(False);
  end;

end;

function ServiceGetProcessID(MachineName, ServiceName: String): DWORD;
var  lpStatus:      TServiceStatusProcess;
     hSCM:          SC_HANDLE;
     hSC:           SC_HANDLE;
     dwNeeded:      DWORD;
begin

  // Default result
  result:=0;

  // Connect to the service control manager
  hSCM:=OpenSCManager(PChar(MachineName), nil, SC_MANAGER_CONNECT);

  // Check handle
  if not(hSCM = 0) then
  begin
     // Resource protection
     try
        // Open service
        hSC:=OpenService(hSCM, PChar(ServiceName), SERVICE_QUERY_STATUS);
        // Check handle
        if not(hSC = 0) then
        begin
           // Resource protection
           try
              // Query service
              if QueryServiceStatusEx(hSC, SC_STATUS_PROCESS_INFO, @lpStatus, SizeOf(TServiceStatusProcess), @dwNeeded) then
              begin
                 // Update the result
                 result:=lpStatus.dwProcessId;
              end;
           finally
              // Close handle
              CloseServiceHandle(hSC);
           end;
        end;
     finally
        // Close handle
        CloseServiceHandle(hSCM);
     end;
  end;

end;

procedure ModifySecurity(Enable: Boolean);
var  hToken:        THandle;
     lpszSecName:   Array [0..2] of PChar;
     tp:            TOKEN_PRIVILEGES;
     tpPrevious:    TOKEN_PRIVILEGES;
     luid:          TLargeInteger;
     cbUnused:      DWORD;
     cbPrevious:    DWORD;
     dwCount:       Integer;
begin

  // Set security names
  lpszSecName[0]:='SeSecurityPrivilege';
  lpszSecName[1]:='SeTcbPrivilege';
  lpszSecName[2]:='SeDebugPrivilege';

      // Enable our process to super-level rights
  if OpenProcessToken(GetCurrentProcess, TOKEN_ADJUST_PRIVILEGES or TOKEN_QUERY, hToken) then
  begin
     // Iterate the security names to elevate
     for dwCount:=Low(lpszSecName) to High(lpszSecName) do
     begin
        cbPrevious:=SizeOf(TOKEN_PRIVILEGES);
        if LookupPrivilegeValue(nil, lpszSecName[dwCount], luid) then
        begin
           tp.PrivilegeCount:=1;
           tp.Privileges[0].Luid:=luid;
           tp.Privileges[0].Attributes:=0;
           if AdjustTokenPrivileges(hToken, False, tp, SizeOf(TOKEN_PRIVILEGES), @tpPrevious, cbPrevious) then
           begin
              tpPrevious.PrivilegeCount:=1;
              tpPrevious.Privileges[0].Luid:=luid;
              if Enable then
                 tpPrevious.Privileges[0].Attributes:=SE_PRIVILEGE_ENABLED
              else
                     tpPrevious.Privileges[0].Attributes:=0;
              if not(AdjustTokenPrivileges(hToken, False, tpPrevious, cbPrevious, nil, cbUnused)) then break;
           end;
        end;
     end;
  end;

end;

end.
Avatar of BigScott_27
BigScott_27

ASKER

   Well I tried your code out last night and it compiles with no errors, it does also in fact kill some services. Unfortunately it does not take out the particular service I would like to be able to terminate. I noticed upon testing that it couldn't take out quite a few services actually.

    I am not positive, but I believe that this services uses a system wide api hook on terminate process. I know this service uses hooks to guard certain files that it creates so I'm guessing in order to protect itself it hooks terminate process and possibly other methods that may be used to terminate it. If anyone know of an alternative method to terminate a service that uses these types of security methods I'm willing to try anything.  

If does not hurt to mention this kind of information beforehand...
Anyways, when debugging the code, can you tell me the following:

- Is the correct process id retured.
- Does the OpenProcess call return the process handle

Russell
Sorry for not mentioning that but I'm learning new things about this particular service as I try different methods of closing it. Like I said this is an assumption that it's hooking terminate process and possibly other close calls, it makes sense though. I have a retail stand alone program called task killer that can take it out no problem, however windows task manager, and all DOS based methods of closing it will always return access denied.

As far as I know the PID returned is correct I can tell you I tried it bypassing finding the PID  and plugging the PID in directly from tasklist, and it didn't shut it down with the correct PID. I believe the process handle is returned from OpenProcess, but it was late last night when I tried your code out so I just tested it fairly quickly and didn't check everything out completely. It did work on some other services I tested it on but I can check it out more thoroughly when I get back home later today.

By the way thanks for your help. ;-)
ASKER CERTIFIED SOLUTION
Avatar of Russell Libby
Russell Libby
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Alright I'll give this a shot when I get home later. I appreciate your help on this matter and will certainly let you know how I make out with it.
Sounds good; just a heads up on what I will be asking for if it does NOT work (to save me from asking for it later):

- Need to know if the ServiceGetProcessID is returning the process ID.
- Does this PID match the process in Task Manager.
- Does the OpenProcess call succeed in getting the handle from the ProcessID.
- If the NTTerminateProcess call fails, what is the error code
- If the CreateRemoteThread call fails, what is the error code.

Thanks,
Russell


Thank you so so much Russell!!! The above code did the trick flawlessly the first time I tried it. I would have been going nuts trying to figure this out on my own.
Thanks again,
Scott
Glad it did the trick and we didn't have to go low-level (asm) on it ;-)

Russell