Solved

Need to kill a very stubborn Windows Service

Posted on 2006-07-16
9
1,470 Views
Last Modified: 2008-01-09
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.
0
Comment
Question by:BigScott_27
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 5
  • 4
9 Comments
 
LVL 26

Expert Comment

by:Russell Libby
ID: 17118498
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.
0
 

Author Comment

by:BigScott_27
ID: 17121077
   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.  
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 17121593

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
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 

Author Comment

by:BigScott_27
ID: 17122438
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. ;-)
0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 500 total points
ID: 17122548

If you can get the pid, and can OpenProcess a valid handle, then the following MAY be enough to take it down. I say *may*, because it all depends on what hooks have been set, and at what level. (I do have some expertise in this field). If it has only hooked the kernel calls, then the direct ntdll calls should take it out. If that fails, and you are able to inject a remote thread, then the second handler may work.

Regards,
Russell

---

function   NtTerminateProcess(ProcessHandle: THandle; ExitStatus: Integer): Integer; stdcall; external 'ntdll.dll';
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;
     hThread:       THandle;
     dwThread:      DWORD;
begin

  // Set default result
  result:=False;

  // Enable permissions
  ModifySecurity(True);

  // Resource protection
  try
     // Open process for termination
     hProc:=OpenProcess(PROCESS_TERMINATE, False, ProcessID);
     // Check handle
     if not(hProc = 0) then
     begin
        // Resource protection
        try
           // Terminate
           result:=(NTTerminateProcess(hProc, 0) = ERROR_SUCCESS);
        finally
           // Close process handle
           CloseHandle(hProc);
        end;
     end;
     // Check result
     if (result = False) then
     begin
        // Attempt to open up for thread injection
        hProc:=OpenProcess(PROCESS_ALL_ACCESS, False, ProcessID);
        // Check handle
        if not(hProc = 0) then
        begin
           // Resource protection
           try
              // Create remote thread
              hThread:=CreateRemoteThread(hProc, nil, 0, GetProcAddress(GetModuleHandle('kernel32'), 'ExitProcess'), nil, 0, dwThread);
              // Wait for thread to finish
              if not(hThread = 0) then
              begin
                 // Resource protection
                 try
                    // Wait for the thread to complete
                    WaitForSingleObject(hThread, INFINITE);
                 finally
                    // Close thread handle
                    CloseHandle(hThread);
                 end;
                 // Success
                 result:=True;
              end;
           finally
              // Close process handle
              CloseHandle(hProc);
           end;
        end
     end;
  finally
     // Disable the permissions
     ModifySecurity(False);
  end;

end;
0
 

Author Comment

by:BigScott_27
ID: 17122626
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.
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 17125079
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


0
 

Author Comment

by:BigScott_27
ID: 17127013
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
0
 
LVL 26

Expert Comment

by:Russell Libby
ID: 17127033
Glad it did the trick and we didn't have to go low-level (asm) on it ;-)

Russell
0

Featured Post

[Webinar] How Hackers Steal Your Credentials

Do You Know How Hackers Steal Your Credentials? Join us and Skyport Systems to learn how hackers steal your credentials and why Active Directory must be secure to stop them. Thursday, July 13, 2017 10:00 A.M. PDT

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction Raise your hands if you were as upset with FireMonkey as I was when I discovered that there was no TListview.  I use TListView in almost all of my applications I've written, and I was not going to compromise by resorting to TStringGrid…
In this video, viewers will be given step by step instructions on adjusting mouse, pointer and cursor visibility in Microsoft Windows 10. The video seeks to educate those who are struggling with the new Windows 10 Graphical User Interface. Change Cu…
There's a multitude of different network monitoring solutions out there, and you're probably wondering what makes NetCrunch so special. It's completely agentless, but does let you create an agent, if you desire. It offers powerful scalability …

695 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question