Merge remote-tracking branch 'origin/GP-6148_d-millar_x64dbg_termination'

This commit is contained in:
Ryan Kurtz
2025-11-24 13:55:43 -05:00
5 changed files with 41 additions and 29 deletions
@@ -838,6 +838,8 @@ def ghidra_trace_disassemble(address: Union[str, int]) -> None:
def compute_proc_state(nproc: Optional[int] = None) -> str:
if nproc is None:
return 'TERMINATED'
try:
if util.dbg.client.is_running():
return 'RUNNING'
@@ -873,10 +875,12 @@ def put_processes(running: bool = False) -> None:
def put_state(event_process: int) -> None:
state = compute_proc_state(event_process)
if event_process is None:
event_process = util.last_process
ipath = PROCESS_PATTERN.format(procnum=event_process)
trace = STATE.require_trace()
procobj = trace.create_object(ipath)
state = compute_proc_state(event_process)
procobj.set_value('State', state)
procobj.insert()
tnum = util.selected_thread()
@@ -105,16 +105,14 @@ class ProcessState:
except Exception:
pass
def record_exited(self, description: Optional[str] = None,
def record_exited(self, exit_code: Optional[str] = None,
time: Optional[Schedule] = None) -> None:
# print("RECORD_EXITED")
trace = commands.STATE.require_trace()
if description is not None:
trace.snapshot(description, time=time)
proc = util.selected_process()
ipath = commands.PROCESS_PATTERN.format(procnum=proc)
if exit_code is not None:
trace.snapshot(f"Exited {exit_code}", time=time)
ipath = commands.PROCESS_PATTERN.format(procnum=util.last_process)
procobj = trace.proxy_object_path(ipath)
#procobj.set_value('Exit Code', exit_code)
procobj.set_value('Exit Code', exit_code)
procobj.set_value('State', 'TERMINATED')
@@ -165,13 +163,15 @@ def on_state_changed(*args) -> None:
ev_type = args[0].event_type
# print(ev_type)
proc = util.selected_process()
if proc not in PROC_STATE:
return
PROC_STATE[proc].waiting = False
trace = commands.STATE.require_trace()
with trace.client.batch():
with trace.open_tx("State changed proc {}".format(proc)):
commands.put_state(proc)
if proc not in PROC_STATE:
if ev_type == EventType.EVENT_EXIT_PROCESS:
on_process_deleted(args)
return
PROC_STATE[proc].waiting = False
try:
if ev_type == EventType.EVENT_RESUME_DEBUG:
on_cont()
@@ -219,10 +219,9 @@ def on_process_selected() -> None:
@log_errors
def on_process_deleted(*args) -> None:
# print("ON_PROCESS_DELETED")
exit_code = args[0]
# print("PROCESS_DELETED: args={}".format(args))
proc = util.selected_process()
on_exited(proc)
on_exited(args)
if proc in PROC_STATE:
del PROC_STATE[proc]
trace = commands.STATE.trace
@@ -342,20 +341,17 @@ def on_stop(*args) -> None:
commands.activate()
def on_exited(proc) -> None:
def on_exited(*args) -> None:
# print("ON EXITED")
if proc not in PROC_STATE:
# print("not in state")
return
trace = commands.STATE.trace
if trace is None:
return
state = PROC_STATE[proc]
state = PROC_STATE[util.last_process]
state.visited.clear()
description = "Exited"
with trace.client.batch():
with trace.open_tx("Exited"):
state.record_exited(description)
exit_code = args[0][0].event_data.dwExitCode
state.record_exited(exit_code)
commands.activate()
@@ -394,7 +390,12 @@ def install_hooks() -> None:
dbg.watch_debug_event(EventType.EVENT_STEPPED, lambda x: on_state_changed(x))
dbg.watch_debug_event(EventType.EVENT_PAUSE_DEBUG, lambda x: on_state_changed(x))
dbg.watch_debug_event(EventType.EVENT_RESUME_DEBUG, lambda x: on_state_changed(x))
#dbg.watch_debug_event(EventType.EVENT_DEBUG, lambda x: on_state_changed(x))
dbg.watch_debug_event(EventType.EVENT_ATTACH, lambda x: on_state_changed(x))
dbg.watch_debug_event(EventType.EVENT_DETACH, lambda x: on_state_changed(x))
dbg.watch_debug_event(EventType.EVENT_INIT_DEBUG, lambda x: on_state_changed(x))
dbg.watch_debug_event(EventType.EVENT_STOP_DEBUG, lambda x: on_state_changed(x))
dbg.watch_debug_event(EventType.EVENT_CREATE_PROCESS, lambda x: on_state_changed(x))
dbg.watch_debug_event(EventType.EVENT_EXIT_PROCESS, lambda x: on_state_changed(x))
def remove_hooks() -> None:
@@ -410,6 +411,7 @@ def enable_current_process() -> None:
def disable_current_process() -> None:
# print("Disable current process")
proc = util.selected_process()
if proc in PROC_STATE:
# Silently ignore already disabled
@@ -102,6 +102,7 @@ def compute_dbg_ver() -> DbgVersion:
DBG_VERSION = compute_dbg_ver()
last_process = None
def get_target():
@@ -124,12 +125,14 @@ def get_inst_sz(addr: int) -> int:
def selected_process() -> int:
global last_process
try:
pid = dbg.client.debugee_pid()
if pid is not None:
last_process = pid
return pid
except:
# NB: we're intentionally returning 0 instead of None
return 0
return None
def selected_process_space() -> int:
@@ -202,11 +205,13 @@ def process_list0(running: bool = False) -> Union[
Iterable[Tuple[int, str, int]], Iterable[Tuple[int]]]:
"""Get the list of all processes."""
nproc = selected_process()
proc = psutil.Process(nproc)
sysids = []
names = []
if nproc is None:
return zip(sysids)
try:
proc = psutil.Process(nproc)
sysids.append(nproc)
names.append(proc.name())
return zip(sysids, names)
@@ -71,6 +71,7 @@ public abstract class AbstractX64dbgTraceRmiTest extends AbstractGhidraHeadedDeb
protected static boolean didSetupPython = false;
public static final String NOTEPAD = "C:\\\\Windows\\\\notepad.exe";
public static final String NETSTAT = "C:\\\\Windows\\\\System32\\\\netstat.exe";
public static final String INSTRUMENT_STATE = """
import sys
from ghidraxdbg import commands
@@ -391,7 +391,7 @@ public class X64dbgMethodsTest extends AbstractX64dbgTraceRmiTest {
@Test
public void testRemoveProcess() throws Exception {
try (PythonAndConnection conn = startAndConnectPython()) {
start(conn, "netstat.exe");
start(conn, NETSTAT);
txPut(conn, "processes");
RemoteMethod removeProcess = conn.getMethod("remove_process");
@@ -404,7 +404,7 @@ public class X64dbgMethodsTest extends AbstractX64dbgTraceRmiTest {
String out = conn.executeCapture("print(list(util.process_list0()))");
conn.execute("util.terminate_session()");
assertThat(out, containsString("python.exe"));
assertEquals(out, "[]\n");
}
}
}
@@ -465,7 +465,7 @@ public class X64dbgMethodsTest extends AbstractX64dbgTraceRmiTest {
@Test
public void testDetach() throws Exception {
try (PythonAndConnection conn = startAndConnectPython()) {
start(conn, "netstat.exe");
start(conn, NETSTAT);
txPut(conn, "processes");
RemoteMethod detach = conn.getMethod("detach");
@@ -525,7 +525,7 @@ public class X64dbgMethodsTest extends AbstractX64dbgTraceRmiTest {
String out = conn.executeCapture("print(list(util.process_list0()))");
conn.execute("util.terminate_session()");
assertThat(out, containsString("python.exe"));
assertEquals(out, "[]\n");
}
}
}