- Added Win32Process which uses JNA to give us access to Windows APIs that give us more control over processes.

- Added killProcess() method to ExecUtil. This method can be used to terminate a process and its children.
This commit is contained in:
Eamonn Saunders 2014-11-05 16:02:47 -05:00
parent f6be031c20
commit 882343a60f
2 changed files with 146 additions and 2 deletions

View File

@ -18,11 +18,13 @@
*/
package org.sleuthkit.autopsy.coreutils;
import com.sun.javafx.PlatformUtil;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Writer;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
@ -108,12 +110,12 @@ public final class ExecUtil {
do {
process.waitFor(timeOut, units);
if (process.isAlive() && terminator.shouldTerminateProcess()) {
process.destroyForcibly();
killProcess(process);
}
} while (process.isAlive());
} catch (InterruptedException ex) {
if (process.isAlive()) {
process.destroyForcibly();
killProcess(process);
}
Logger.getLogger(ExecUtil.class.getName()).log(Level.INFO, "Thread interrupted while running {0}", processBuilder.command().get(0));
Thread.currentThread().interrupt();
@ -121,6 +123,33 @@ public final class ExecUtil {
return process.exitValue();
}
/**
* Kill a process and its children
* @param process The parent process to kill
*/
public static void killProcess(Process process) {
if (process == null)
return;
try {
if (PlatformUtil.isWindows()) {
Win32Process parentProcess = new Win32Process(process);
List<Win32Process> children = parentProcess.getChildren();
children.stream().forEach((child) -> {
child.terminate();
});
parentProcess.terminate();
}
else {
process.destroyForcibly();
}
}
catch (Exception ex) {
logger.log(Level.WARNING, "Error occurred when attempting to kill process: {0}", ex.getMessage()); // NON-NLS
}
}
private static final Logger logger = Logger.getLogger(ExecUtil.class.getName());
private Process proc = null;
private ExecUtil.StreamToStringRedirect errorStringRedirect = null;

View File

@ -0,0 +1,115 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2012-2014 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.coreutils;
import com.sun.jna.Pointer;
import com.sun.jna.platform.win32.Kernel32;
import com.sun.jna.platform.win32.Kernel32Util;
import com.sun.jna.platform.win32.Tlhelp32;
import com.sun.jna.platform.win32.WinDef.DWORD;
import com.sun.jna.platform.win32.WinNT;
import java.io.IOException;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
/**
* Class that represents a Windows process.
* It uses JNA to access the Win32 API.
* This code is based on http://stackoverflow.com/questions/10124299/how-do-i-terminate-a-process-tree-from-java
*/
public class Win32Process {
WinNT.HANDLE handle;
int pid;
/**
* Create a Win32Process object for the given Process object.
* Reflection is used to construct a Windows process handle.
* @param process A Java Process object
* @throws IOException
*/
Win32Process (Process process) throws Exception
{
if (process.getClass().getName().equals("java.lang.Win32Process") || // NON-NLS
process.getClass().getName().equals("java.lang.ProcessImpl")) { // NON-NLS
try {
Field f = process.getClass().getDeclaredField("handle"); // NON-NLS
f.setAccessible(true);
long handleVal = f.getLong(process);
handle = new WinNT.HANDLE(Pointer.createConstant(handleVal));
}
catch (NoSuchFieldException | SecurityException | IllegalArgumentException | IllegalAccessException ex) {
throw new Exception(ex.getMessage()); // NON-NLS
}
}
this.pid = Kernel32.INSTANCE.GetProcessId(handle);
}
/**
* Create a Win32Process object for the given process id.
* @param pid Process Id
* @throws IOException
*/
Win32Process (int pid) throws Exception
{
handle = Kernel32.INSTANCE.OpenProcess (
0x0400| /* PROCESS_QUERY_INFORMATION */
0x0800| /* PROCESS_SUSPEND_RESUME */
0x0001| /* PROCESS_TERMINATE */
0x00100000 /* SYNCHRONIZE */,
false,
pid);
if (handle == null)
throw new Exception (Kernel32Util.formatMessageFromLastErrorCode (Kernel32.INSTANCE.GetLastError ()));
this.pid = Kernel32.INSTANCE.GetProcessId(handle);
}
@Override
protected void finalize () throws Throwable
{
Kernel32.INSTANCE.CloseHandle (handle);
super.finalize();
}
/**
* Kill the process. Note that this does not kill children.
*/
public void terminate ()
{
Kernel32.INSTANCE.TerminateProcess (handle, 0);
}
/**
* Get children of current process object.
* @return list of child processes
* @throws IOException
*/
public List<Win32Process> getChildren () throws Exception
{
ArrayList<Win32Process> result = new ArrayList<> ();
WinNT.HANDLE hSnap = Kernel32.INSTANCE.CreateToolhelp32Snapshot(Tlhelp32.TH32CS_SNAPPROCESS, new DWORD(0));
Tlhelp32.PROCESSENTRY32.ByReference ent = new Tlhelp32.PROCESSENTRY32.ByReference ();
if (!Kernel32.INSTANCE.Process32First (hSnap, ent)) return result;
do {
if (ent.th32ParentProcessID.intValue () == pid) result.add (new Win32Process (ent.th32ProcessID.intValue ()));
} while (Kernel32.INSTANCE.Process32Next (hSnap, ent));
Kernel32.INSTANCE.CloseHandle (hSnap);
return result;
}
}