Solved

System freezes upon execution of this code

Posted on 2006-07-22
7
749 Views
Last Modified: 2012-08-13
Hello Everyone,
I received the code below from an expert here and it works flawlessly when executed by itself. However, when I run it in the application that I'm developing it will spuradically freeze the entire system. No possibility to do anything to recover other than hitting the reset button and rebooting. The service needs to be killed first as it hooks one of the other application that needs to be terminated. I'm guessing that it's the process of killing out one of the other two applications that cause it to freeze. I was hoping someone here might be able to take a look at my code and possibly have a suggestion of how to terminate these other two applications that maybe a bit more stable. Or a method that might work better.
As stated the system freezing is spuradic and there doesn't seem to be any specific pattern I can pick up on that might be causing the system to freeze.

Service Terminate in it's own unit:
 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   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;

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.



End Service Terminate Unit.



Main program Functions used to kill apps and call to kill apps:



function KillTask(ExeFileName: string): Integer;
const
  PROCESS_TERMINATE = $0001;
var
  ContinueLoop: BOOL;
  FSnapshotHandle: THandle;
  FProcessEntry32: TProcessEntry32;
begin
  Result := 0;
  FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
  FProcessEntry32.dwSize := SizeOf(FProcessEntry32);
  ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32);

  while Integer(ContinueLoop) <> 0 do
  begin
    if ((UpperCase(ExtractFileName(FProcessEntry32.szExeFile)) =
      UpperCase(ExeFileName)) or (UpperCase(FProcessEntry32.szExeFile) =
      UpperCase(ExeFileName))) then
      Result := Integer(TerminateProcess(
                        OpenProcess(PROCESS_TERMINATE,
                                    BOOL(0),
                                    FProcessEntry32.th32ProcessID),
                                    0));
     ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32);
  end;
  CloseHandle(FSnapshotHandle);
end;

procedure KillProcess(hWindowHandle: HWND);
var
  hprocessID: INTEGER;
  processHandle: THandle;
  DWResult: DWORD;
begin
  SendMessageTimeout(hWindowHandle, WM_CLOSE, 0, 0,
    SMTO_ABORTIFHUNG or SMTO_NORMAL, 5000, DWResult);

  if isWindow(hWindowHandle) then
  begin
    // PostMessage(hWindowHandle, WM_QUIT, 0, 0);

    GetWindowThreadProcessID(hWindowHandle, @hprocessID);
    if hprocessID <> 0 then
    begin

      processHandle := OpenProcess(PROCESS_TERMINATE or PROCESS_QUERY_INFORMATION, False, hprocessID);
      if processHandle <> 0 then
      begin

        TerminateProcess(processHandle, 0);
        CloseHandle(ProcessHandle);
      end;
    end;
  end;
end;

function FindWindowByTitle(WindowTitle: string): Hwnd;
var
  NextHandle: Hwnd;
  NextTitle: array[0..260] of char;
begin
  NextHandle := GetWindow(Application.Handle, GW_HWNDFIRST);
  while NextHandle > 0 do
  begin
    GetWindowText(NextHandle, NextTitle, 255);
    if Pos(WindowTitle, StrPas(NextTitle)) <> 0 then
    begin
      Result := NextHandle;
      Exit;
    end
    else
      NextHandle := GetWindow(NextHandle, GW_HWNDNEXT);
  end;
  Result := 0;
end;



Call to kill everything:



procedure TForm1.Button4Click(Sender: TObject);
var  dwProcID:      DWORD;
begin
  dwProcID:=ServiceGetProcessID(EmptyStr, 'ServiceToBeKilledName');
  if not(dwProcID = 0) then KillProcessByPID(dwProcID);
  KillProcess(FindWindowByTitle('HookedApptobekilledtitle'));
  KillTask('SecondNonhookedapptobekilled.exe');
  Button1.Enabled:= True;
  Button4.Enabled:= False;
end;
0
Comment
Question by:BigScott_27
  • 3
  • 2
7 Comments
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility

Scott,

In the KillProcessByPID function, what portion of the code ends up terminating the service and app? Is it the NTTerminateProcess or the CreateRemoteThread that injects the call to ExitProcess?

If the NTTerminateProcess is getting called, you might try swicthing the logic around so that the ExitProcess code gets attempted first (the preferred method of terminating the application). NTTerminateProcess is a hard kill, which is what you asked for, but the results can lead to an unstable system if hooks have been set by the process being terminated.

Regards,
Russell



0
 

Author Comment

by:BigScott_27
Comment Utility
Yes, it appears that it is in fact the NTTerminateProcess that is the code that ends up taking out the service. I assume by reversing the logic you mean changng the code around to ressemble something like this?

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
        // 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;
     // Check result
     if (result = False) then
     begin
     // 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;
     end;
  finally
     // Disable the permissions
     ModifySecurity(False);
  end;

end;

I have tried changing the KillprocessbyPID function to the above and will test it now. Will let you know how it works out. If this isn't what you meant by reversing the logic could you give me an example please.
Thanks a million,
Scott
0
 
LVL 26

Expert Comment

by:Russell Libby
Comment Utility
Scott,

Yes, that is exactly what I meant. Figure its worth a shot, as that would be the preferred way to get the process to close (trick it into closing itself). This way things will hopefully get cleaned up, vs using the TerminateProcess  (NTTerminateProcess)

From TerminateProcess:

Remarks

The TerminateProcess function is used to unconditionally cause a process to exit. Use it only in extreme circumstances. The state of global data maintained by dynamic-link libraries (DLLs) may be compromised if TerminateProcess is used rather than ExitProcess.

TerminateProcess causes all threads within a process to terminate, and causes a process to exit, but DLLs attached to the process are not notified that the process is terminating. Terminating a process causes the following:

1.      All of the object handles opened by the process are closed.
2.      All of the threads in the process terminate their execution.
3.      The state of the process object becomes signaled, satisfying any threads that had been waiting for the process to terminate.
4.      The states of all threads of the process become signaled, satisfying any threads that had been waiting for the threads to terminate.
5.      The termination status of the process changes from STILL_ACTIVE to the exit value of the process.


Terminating a process does not cause child processes to be terminated.
Terminating a process does not necessarily remove the process object from the system. A process object is deleted when the last handle to the process is closed.

---

Russell
0
 

Author Comment

by:BigScott_27
Comment Utility
Well unfortunately the reversal of logic in the SvcTerminate unit did not help. Still crashes spuradically while terminating the above service and applications. Not sure what I should try next. Is there anyway to stop a service rather than terminate it even if the stop command has been disabled in the service? I can pause the service but as it's still running then and hooked into all of the other apps and processes it doesn't seem to help at all.
0
 
LVL 26

Accepted Solution

by:
Russell Libby earned 500 total points
Comment Utility

Scott,

Well, that does make it interesting... if the Stop is not enabled for the service, then the service cant/wont acknowledge a stop command. Couple of questions / comments for you:

- Alternatives: why do you need the service stopped /ended? Does it interefere with your software? Does it need to be running at all? If it does not need to be running at all, you could programmaticly disable the service, add your program  to the \RunOnce key of the registry (eg with a command line param of "/Continue" or similar which would let you know you are continuing operation from a reboot), then via code reboot the system. The system would restart, your app would be started, and you could continue whatever operation you were doing.

- What is this service, and what is supposed to be its purpose? Do you have any further info as to what it does, and what hooks it might have set in the system? Have you tried using a program like IceSword (you need winrar):

http://www.xfocus.net/tools/200509/IceSword_en1.12.rar

to determine what normal hooks it might have set? What modules it is using, etc, etc?

- Do any other services have a dependancy to this service? If so, they will need to be shut down / stopped / terminated as well. You mentioned other applications, but did not elaborate further...

- Is there any way for a user to stop this service and or apps? Eg though the use of menus, buttons, etc, any type of user interface? If so, it may be possible to emulate the user input programmaticly.

---

As it currently stands, this service has most likely hooked either the desktop (explorer) or other system processes, which is why the system destabalizes when you terminate it. Without more pieces to this puzzle, it will be hard to safely kill it (btw, disabling the service and restarting IS safe, if that is an option).


Regards,
Russell

0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

The uses clause is one of those things that just tends to grow and grow. Most of the time this is in the main form, as it's from this form that all others are called. If you have a big application (including many forms), the uses clause in the in…
Objective: - This article will help user in how to convert their numeric value become words. How to use 1. You can copy this code in your Unit as function 2. than you can perform your function by type this code The Code   (CODE) The Im…
In this tutorial you'll learn about bandwidth monitoring with flows and packet sniffing with our network monitoring solution PRTG Network Monitor (https://www.paessler.com/prtg). If you're interested in additional methods for monitoring bandwidt…
This demo shows you how to set up the containerized NetScaler CPX with NetScaler Management and Analytics System in a non-routable Mesos/Marathon environment for use with Micro-Services applications.

771 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

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now