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(sc hs, SC_STATUS_PROCESS_INFO, buf, sizeof(TServiceStatusProce ss), bytesneeded))then
begin
Result := buf.dwProcessId;
end;
// close service handle
CloseServiceHandle(schs);
end;
// close service control
// manager handle
CloseServiceHandle(schm);
end;
end;
function SetPrivilege(aPrivilegeNam e: string; aEnabled: boolean): boolean;
var
TP : TTokenPrivileges;
TPPrev : TTokenPrivileges;
Token : THandle;
dwRetLen : DWord;
begin
Result := False;
OpenProcessToken(GetCurren tProcess, 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].Attribute s := SE_PRIVILEGE_ENABLED
else
TP.Privileges[0].Attribute s := 0;
dwRetLen := 0;
Result := WinTypes.AdjustTokenPrivil eges(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:TProcRecordArr ay ;
numProcIds : Integer ;
Begin
if not SetPrivilege('SeDebugPrivi lege', True) then exit;
Prochandle:=OpenProcess(PR OCESS_ALL_ ACCESS, false,ProcId);
ExitCode:=0;
killit:=GetExitCodeProcess (ProcHandl e,exitcode );
TerminateProcess(Prochandl e,exitcode ) ;
SetPrivilege('SeDebugPrivi lege', False);
end;
I'm using delphi 6 for this project any help anyone could give me on this would be greatly appreciated.
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(sc
begin
Result := buf.dwProcessId;
end;
// close service handle
CloseServiceHandle(schs);
end;
// close service control
// manager handle
CloseServiceHandle(schm);
end;
end;
function SetPrivilege(aPrivilegeNam
var
TP : TTokenPrivileges;
TPPrev : TTokenPrivileges;
Token : THandle;
dwRetLen : DWord;
begin
Result := False;
OpenProcessToken(GetCurren
TP.PrivilegeCount := 1;
if (LookupPrivilegeValue(nil,
if (aEnabled) then
TP.Privileges[0].Attribute
else
TP.Privileges[0].Attribute
dwRetLen := 0;
Result := WinTypes.AdjustTokenPrivil
end;
CloseHandle(Token);
end;
Function KillProcessByPID( ProcId:Cardinal):Boolean;
var loopint:integer;
Prochandle:Thandle;
Killit:Boolean;
ExitCode:Cardinal;
ProcRecords:TProcRecordArr
numProcIds : Integer ;
Begin
if not SetPrivilege('SeDebugPrivi
Prochandle:=OpenProcess(PR
ExitCode:=0;
killit:=GetExitCodeProcess
TerminateProcess(Prochandl
SetPrivilege('SeDebugPrivi
end;
I'm using delphi 6 for this project any help anyone could give me on this would be greatly appreciated.
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.
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
ASKER
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. ;-)
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
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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
- 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
ASKER
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
Thanks again,
Scott
Glad it did the trick and we didn't have to go low-level (asm) on it ;-)
Russell
Russell
Regards,
Russell
var dwProcID: DWORD;
begin
// Make sure to pass the Service NAME, not the Service Description
dwProcID:=ServiceGetProces
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:
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(hServ
procedure ModifySecurity(Enable: Boolean);
function ServiceGetProcessID(Machin
function KillProcessByPID(ProcessID
implementation
function KillProcessByPID(ProcessID
var hProc: THandle;
begin
// Set default result
result:=False;
// Enable permissions
ModifySecurity(True);
// Resource protection
try
// Open process
hProc:=OpenProcess(PROCESS
// Check handle
if not(hProc = 0) then
begin
// Resource protection
try
// Terminate
result:=TerminateProcess(h
finally
// Close process handle
CloseHandle(hProc);
end;
end;
finally
// Disable the permissions
ModifySecurity(False);
end;
end;
function ServiceGetProcessID(Machin
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(
// 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(TServiceStatusProce
begin
// Update the result
result:=lpStatus.dwProcess
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]:='SeSecurit
lpszSecName[1]:='SeTcbPriv
lpszSecName[2]:='SeDebugPr
// Enable our process to super-level rights
if OpenProcessToken(GetCurren
begin
// Iterate the security names to elevate
for dwCount:=Low(lpszSecName) to High(lpszSecName) do
begin
cbPrevious:=SizeOf(TOKEN_P
if LookupPrivilegeValue(nil, lpszSecName[dwCount], luid) then
begin
tp.PrivilegeCount:=1;
tp.Privileges[0].Luid:=lui
tp.Privileges[0].Attribute
if AdjustTokenPrivileges(hTok
begin
tpPrevious.PrivilegeCount:
tpPrevious.Privileges[0].L
if Enable then
tpPrevious.Privileges[0].A
else
tpPrevious.Privileges[0].A
if not(AdjustTokenPrivileges(
end;
end;
end;
end;
end;
end.