From c8d90c104394b22d478a748d8fc59215bfdf674d Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Tue, 21 May 2024 09:16:04 -0400 Subject: [PATCH 01/10] GP-0: Fix DebuggerBreakpointsPlugin dependency --- .../core/debug/gui/breakpoint/DebuggerBreakpointsPlugin.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPlugin.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPlugin.java index 4ae640a4b4..04d0331921 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPlugin.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/breakpoint/DebuggerBreakpointsPlugin.java @@ -20,6 +20,7 @@ import ghidra.app.plugin.core.debug.AbstractDebuggerPlugin; import ghidra.app.plugin.core.debug.DebuggerPluginPackage; import ghidra.app.plugin.core.debug.event.*; import ghidra.app.services.DebuggerLogicalBreakpointService; +import ghidra.app.services.DebuggerTraceManagerService; import ghidra.framework.plugintool.*; import ghidra.framework.plugintool.util.PluginStatus; @@ -31,6 +32,7 @@ import ghidra.framework.plugintool.util.PluginStatus; status = PluginStatus.RELEASED, servicesRequired = { DebuggerLogicalBreakpointService.class, + DebuggerTraceManagerService.class, }, eventsConsumed = { TraceOpenedPluginEvent.class, From b78357889a788d87102e944534c90f0edcb03fbb Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Tue, 21 May 2024 11:40:46 -0400 Subject: [PATCH 02/10] GP-4618: Fix NPE/timing issue seen in ThreadsPanel --- .../core/debug/gui/action/RegisterLocationTrackingSpec.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java index 3ac0d6b524..512f857679 100644 --- a/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java +++ b/Ghidra/Debug/Debugger/src/main/java/ghidra/app/plugin/core/debug/gui/action/RegisterLocationTrackingSpec.java @@ -22,8 +22,7 @@ import ghidra.program.model.address.*; import ghidra.program.model.lang.Register; import ghidra.program.model.lang.RegisterValue; import ghidra.program.util.ProgramLocation; -import ghidra.trace.model.Trace; -import ghidra.trace.model.TraceAddressSnapRange; +import ghidra.trace.model.*; import ghidra.trace.model.guest.TracePlatform; import ghidra.trace.model.memory.TraceMemorySpace; import ghidra.trace.model.memory.TraceMemoryState; @@ -65,7 +64,8 @@ public interface RegisterLocationTrackingSpec extends LocationTrackingSpec, Loca if (reg == null) { return null; } - if (!thread.getLifespan().contains(snap)) { + Lifespan lifespan = thread.getLifespan(); + if (lifespan == null || !lifespan.contains(snap)) { return null; } TraceMemorySpace regs = reg.getAddressSpace().isRegisterSpace() From b66983787b8ecfdd0f08e41dc582b7e19fb1c634 Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Tue, 21 May 2024 14:27:13 +0000 Subject: [PATCH 03/10] GP-4612: Implement Windows Job control --- .../LocalWindowsNativeProcessPtySession.java | 18 ++++------ .../java/ghidra/pty/windows/ConPtyChild.java | 14 ++++++-- .../ghidra/pty/windows/jna/JobApiNative.java | 34 +++++++++++++++++++ 3 files changed, 52 insertions(+), 14 deletions(-) create mode 100644 Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/jna/JobApiNative.java diff --git a/Ghidra/Framework/Pty/src/main/java/ghidra/pty/local/LocalWindowsNativeProcessPtySession.java b/Ghidra/Framework/Pty/src/main/java/ghidra/pty/local/LocalWindowsNativeProcessPtySession.java index 5b6a71208d..4df5657b76 100644 --- a/Ghidra/Framework/Pty/src/main/java/ghidra/pty/local/LocalWindowsNativeProcessPtySession.java +++ b/Ghidra/Framework/Pty/src/main/java/ghidra/pty/local/LocalWindowsNativeProcessPtySession.java @@ -25,6 +25,7 @@ import com.sun.jna.ptr.IntByReference; import ghidra.pty.PtySession; import ghidra.pty.windows.Handle; +import ghidra.pty.windows.jna.JobApiNative; import ghidra.util.Msg; public class LocalWindowsNativeProcessPtySession implements PtySession { @@ -33,14 +34,16 @@ public class LocalWindowsNativeProcessPtySession implements PtySession { private final Handle processHandle; //private final Handle threadHandle; private final String ptyName; + private final Handle jobHandle; public LocalWindowsNativeProcessPtySession(int pid, int tid, Handle processHandle, - Handle threadHandle, String ptyName) { + Handle threadHandle, String ptyName, Handle jobHandle) { this.pid = pid; //this.tid = tid; this.processHandle = processHandle; //this.threadHandle = threadHandle; this.ptyName = ptyName; + this.jobHandle = jobHandle; Msg.info(this, "local Windows Pty session. PID = " + pid); } @@ -84,17 +87,8 @@ public class LocalWindowsNativeProcessPtySession implements PtySession { @Override public void destroyForcibly() { - if (!Kernel32.INSTANCE.TerminateProcess(processHandle.getNative(), 1)) { - int error = Kernel32.INSTANCE.GetLastError(); - switch (error) { - case Kernel32.ERROR_ACCESS_DENIED: - /** - * This indicates the process has already terminated. It's unclear to me whether - * or not that is the only possible cause of this error. - */ - return; - } - throw new LastErrorException(error); + if (!JobApiNative.INSTANCE.TerminateJobObject(jobHandle.getNative(), 1).booleanValue()) { + throw new LastErrorException(Kernel32.INSTANCE.GetLastError()); } } diff --git a/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/ConPtyChild.java b/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/ConPtyChild.java index 952ec903ce..7c7cd83404 100644 --- a/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/ConPtyChild.java +++ b/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/ConPtyChild.java @@ -31,6 +31,7 @@ import ghidra.pty.PtyChild; import ghidra.pty.local.LocalWindowsNativeProcessPtySession; import ghidra.pty.windows.jna.ConsoleApiNative; import ghidra.pty.windows.jna.ConsoleApiNative.STARTUPINFOEX; +import ghidra.pty.windows.jna.JobApiNative; public class ConPtyChild extends ConPtyEndpoint implements PtyChild { @@ -83,6 +84,11 @@ public class ConPtyChild extends ConPtyEndpoint implements PtyChild { * TODO: How to control local echo? */ + HANDLE hJob = JobApiNative.INSTANCE.CreateJobObjectW(null, null); + if (hJob == null) { + throw new LastErrorException(Kernel32.INSTANCE.GetLastError()); + } + STARTUPINFOEX si = prepareStartupInfo(); PROCESS_INFORMATION pi = new PROCESS_INFORMATION(); @@ -102,9 +108,13 @@ public class ConPtyChild extends ConPtyEndpoint implements PtyChild { throw new LastErrorException(Kernel32.INSTANCE.GetLastError()); } + if (!JobApiNative.INSTANCE.AssignProcessToJobObject(hJob, pi.hProcess).booleanValue()) { + throw new LastErrorException(Kernel32.INSTANCE.GetLastError()); + } + return new LocalWindowsNativeProcessPtySession(pi.dwProcessId.intValue(), - pi.dwThreadId.intValue(), - new Handle(pi.hProcess), new Handle(pi.hThread), "ConPTY"); + pi.dwThreadId.intValue(), new Handle(pi.hProcess), new Handle(pi.hThread), "ConPTY", + new Handle(hJob)); } @Override diff --git a/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/jna/JobApiNative.java b/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/jna/JobApiNative.java new file mode 100644 index 0000000000..38d7638c81 --- /dev/null +++ b/Ghidra/Framework/Pty/src/main/java/ghidra/pty/windows/jna/JobApiNative.java @@ -0,0 +1,34 @@ +/* ### + * IP: GHIDRA + * + * 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 ghidra.pty.windows.jna; + +import com.sun.jna.Native; +import com.sun.jna.WString; +import com.sun.jna.platform.win32.WinDef.BOOL; +import com.sun.jna.platform.win32.WinNT.HANDLE; +import com.sun.jna.win32.StdCallLibrary; + +import ghidra.pty.windows.jna.ConsoleApiNative.SECURITY_ATTRIBUTES; + +public interface JobApiNative extends StdCallLibrary { + JobApiNative INSTANCE = Native.load("kernel32.dll", JobApiNative.class); + + HANDLE CreateJobObjectW(SECURITY_ATTRIBUTES.ByReference lpJobAttributes, WString lpName); + + BOOL AssignProcessToJobObject(HANDLE hJob, HANDLE hProcess); + + BOOL TerminateJobObject(HANDLE hJob, int uExitCode); +} From 121608aeea68b90d275e28febea84fa96b8da939 Mon Sep 17 00:00:00 2001 From: Dan <46821332+nsadeveloper789@users.noreply.github.com> Date: Tue, 21 May 2024 17:34:44 +0000 Subject: [PATCH 04/10] GP-4620: Fix process termination (esp., on kill) --- .../Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py | 4 ++++ .../src/main/py/src/ghidradbg/commands.py | 4 ++++ .../Debugger-agent-dbgeng/src/main/py/src/ghidradbg/hooks.py | 3 ++- 3 files changed, 10 insertions(+), 1 deletion(-) diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py index d6dd89a392..2cf4492cba 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/data/support/local-dbgeng.py @@ -41,6 +41,10 @@ def main(): from ghidradbg import commands as cmd from ghidradbg.util import dbg + # So that the user can re-enter by typing repl() + global repl + repl = cmd.repl + cmd.ghidra_trace_connect(os.getenv('GHIDRA_TRACE_RMI_ADDR')) args = os.getenv('OPT_TARGET_ARGS') if args: diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/commands.py b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/commands.py index 09b4bbddfc..5648efa218 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/commands.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/commands.py @@ -27,6 +27,7 @@ from ghidratrace.client import Client, Address, AddressRange, TraceObject from pybag import pydbg, userdbg, kerneldbg from pybag.dbgeng import core as DbgEng from pybag.dbgeng import exception +from pybag.dbgeng.win32.kernel32 import STILL_ACTIVE from . import util, arch, methods, hooks from .dbgmodel.imodelobject import ModelObjectKind @@ -841,6 +842,9 @@ def ghidra_trace_disassemble(address): @util.dbg.eng_thread def compute_proc_state(nproc=None): + exit_code = util.GetExitCode() + if exit_code is not None and exit_code != STILL_ACTIVE: + return 'TERMINATED' status = util.dbg._base._control.GetExecutionStatus() if status == DbgEng.DEBUG_STATUS_BREAK: return 'STOPPED' diff --git a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/hooks.py b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/hooks.py index 31fa11d9ad..8877dfdba8 100644 --- a/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/hooks.py +++ b/Ghidra/Debug/Debugger-agent-dbgeng/src/main/py/src/ghidradbg/hooks.py @@ -268,7 +268,8 @@ def on_process_selected(): @log_errors def on_process_deleted(*args): # print("ON_PROCESS_DELETED") - proc = args[0] + exit_code = args[0] + proc = util.selected_process() on_exited(proc) if proc in PROC_STATE: del PROC_STATE[proc] From 573d60b036d9ec06f4decc172e6b87e5b0d6f49a Mon Sep 17 00:00:00 2001 From: dev747368 <48332326+dev747368@users.noreply.github.com> Date: Wed, 22 May 2024 15:54:25 +0000 Subject: [PATCH 05/10] GP-4621 fix tooltip hover of dialog status message when html --- .../main/java/docking/DialogComponentProvider.java | 13 ++++--------- .../docking/widgets/label/AbstractHtmlLabel.java | 12 ++++++++++++ 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java index 77a3affa58..c9dc664a81 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/DialogComponentProvider.java @@ -800,15 +800,10 @@ public class DialogComponentProvider * If the status message fits then there is no tool tip. */ private void updateStatusToolTip() { - String text = statusLabel.getText(); - // Get the width of the message. - FontMetrics fm = statusLabel.getFontMetrics(statusLabel.getFont()); - int messageWidth = 0; - if ((fm != null) && (text != null)) { - messageWidth = fm.stringWidth(text); - } - if (messageWidth > statusLabel.getWidth()) { - statusLabel.setToolTipText(text); + Dimension preferredSize = statusLabel.getPreferredSize(); + Dimension size = statusLabel.getSize(); + if (preferredSize.width > size.width || preferredSize.height > size.height) { + statusLabel.setToolTipText(statusLabel.getOriginalText()); } else { statusLabel.setToolTipText(null); diff --git a/Ghidra/Framework/Docking/src/main/java/docking/widgets/label/AbstractHtmlLabel.java b/Ghidra/Framework/Docking/src/main/java/docking/widgets/label/AbstractHtmlLabel.java index 5eb65d6fc9..373621dfa9 100644 --- a/Ghidra/Framework/Docking/src/main/java/docking/widgets/label/AbstractHtmlLabel.java +++ b/Ghidra/Framework/Docking/src/main/java/docking/widgets/label/AbstractHtmlLabel.java @@ -76,6 +76,18 @@ public abstract class AbstractHtmlLabel extends JLabel updateHtmlView(); } + /** + * Returns the original text of the label. + *

+ * The {@link #getText()} method for this class can return a value that is missing the leading + * <html> tag. + * + * @return text of this label + */ + public String getOriginalText() { + return isHtml ? HTML_TAG + getText() : getText(); + } + @Override public void updateUI() { super.updateUI(); From 884428daa69ac20d9035568e4fdf3a43fc7379b6 Mon Sep 17 00:00:00 2001 From: James <49045138+ghidracadabra@users.noreply.github.com> Date: Wed, 22 May 2024 15:10:33 -0400 Subject: [PATCH 06/10] GP-4062 corrected path issues in bsim h2 script --- .../AddProgramToH2BSimDatabaseScript.java | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/Ghidra/Features/BSim/ghidra_scripts/AddProgramToH2BSimDatabaseScript.java b/Ghidra/Features/BSim/ghidra_scripts/AddProgramToH2BSimDatabaseScript.java index 91ca083fc4..648768ce7c 100644 --- a/Ghidra/Features/BSim/ghidra_scripts/AddProgramToH2BSimDatabaseScript.java +++ b/Ghidra/Features/BSim/ghidra_scripts/AddProgramToH2BSimDatabaseScript.java @@ -33,7 +33,7 @@ import ghidra.features.bsim.query.description.DescriptionManager; import ghidra.features.bsim.query.file.BSimH2FileDBConnectionManager; import ghidra.features.bsim.query.file.BSimH2FileDBConnectionManager.BSimH2FileDataSource; import ghidra.features.bsim.query.protocol.*; -import ghidra.framework.model.DomainFolder; +import ghidra.framework.model.DomainFile; import ghidra.framework.protocol.ghidra.GhidraURL; import ghidra.program.model.listing.Function; import ghidra.program.model.listing.FunctionManager; @@ -100,14 +100,23 @@ public class AddProgramToH2BSimDatabaseScript extends GhidraScript { gensig.addFunctionTags(dbInfo.functionTags); gensig.addDateColumnName(dbInfo.dateColumnName); - DomainFolder df = currentProgram.getDomainFile().getParent(); - URL folderURL = df.getSharedProjectURL(); - if (folderURL == null) { - folderURL = df.getLocalProjectURL(); + DomainFile dFile = currentProgram.getDomainFile(); + URL fileURL = dFile.getSharedProjectURL(null); + if (fileURL == null) { + fileURL = dFile.getLocalProjectURL(null); + } + if (fileURL == null) { + popup("Cannot add signatures for program which has never been saved"); + return; } - String path = GhidraURL.getProjectPathname(folderURL); - URL normalizedProjectURL = GhidraURL.getProjectURL(folderURL); + String path = GhidraURL.getProjectPathname(fileURL); + //bsim adds the program name to the path so we need to remove the program + //name here + int lastSlash = path.lastIndexOf('/'); + path = lastSlash == 0 ? "/" : path.substring(0, lastSlash); + + URL normalizedProjectURL = GhidraURL.getProjectURL(fileURL); String repo = normalizedProjectURL.toExternalForm(); gensig.openProgram(this.currentProgram, null, null, null, repo, path); From 7b428f71731f7edf3c544c69121ed72d2109bb51 Mon Sep 17 00:00:00 2001 From: emteere <47253321+emteere@users.noreply.github.com> Date: Wed, 22 May 2024 15:40:00 -0400 Subject: [PATCH 07/10] GP-4506 Check external entry points are not internal local function symbols before creating a function at the entry point. --- .../ExternalEntryFunctionAnalyzer.java | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/ExternalEntryFunctionAnalyzer.java b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/ExternalEntryFunctionAnalyzer.java index 7495d36eaa..27cf96a020 100644 --- a/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/ExternalEntryFunctionAnalyzer.java +++ b/Ghidra/Features/Base/src/main/java/ghidra/app/plugin/core/function/ExternalEntryFunctionAnalyzer.java @@ -1,6 +1,5 @@ /* ### * IP: GHIDRA - * REVIEWED: YES * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,8 +19,7 @@ import ghidra.app.plugin.core.analysis.AutoAnalysisManager; import ghidra.app.services.*; import ghidra.app.util.importer.MessageLog; import ghidra.program.model.address.*; -import ghidra.program.model.listing.Listing; -import ghidra.program.model.listing.Program; +import ghidra.program.model.listing.*; import ghidra.program.model.symbol.*; import ghidra.util.task.TaskMonitor; @@ -42,8 +40,6 @@ public class ExternalEntryFunctionAnalyzer extends AbstractAnalyzer { */ public boolean added(Program program, AddressSetView set, TaskMonitor monitor, MessageLog log) { - Listing listing = program.getListing(); - AddressSet funcStarts = new AddressSet(); monitor.setMessage("Finding External Entry Functions"); @@ -53,9 +49,17 @@ public class ExternalEntryFunctionAnalyzer extends AbstractAnalyzer { AddressIterator entryIter = program.getSymbolTable().getExternalEntryPointIterator(); while (entryIter.hasNext() && !monitor.isCancelled()) { Address entry = entryIter.next(); - if (set.contains(entry) && listing.getInstructionAt(entry) != null) { - funcStarts.addRange(entry, entry); + if (!set.contains(entry)) { + continue; } + + // check for any indicators this is a good start of a function + // must have an instruction at the entry, and not be part of another function + if (!isGoodFunctionStart(program, entry)) { + continue; + } + + funcStarts.addRange(entry, entry); } // remove any addresses that are already functions @@ -76,5 +80,35 @@ public class ExternalEntryFunctionAnalyzer extends AbstractAnalyzer { return true; } + + /** + * Check if address is a good function start. + * Instruction exists at the location. + * No instruction falls through to this one. + * + * @param program the program + * @param addr address to check if is a good function start + * @return true if would be a good function start, false otherwise + */ + public static boolean isGoodFunctionStart(Program program, Address addr) { + // check location starts with an instruction + if (program.getListing().getInstructionAt(addr) == null) { + return false; + } + Address addrBefore = addr.previous(); + if (addrBefore == null) { + return true; + } + + // check if instruction before, falls into this one. + // other code is responsible for creating functions from references + Instruction instr = program.getListing().getInstructionContaining(addrBefore); + if (instr != null && addr.equals(instr.getFallThrough())) { + return false; + } + + // didn't find anything that would indicate is a bad function start + return true; + } } From 13e321ae419420922bf76616f1fb81811b79f74a Mon Sep 17 00:00:00 2001 From: ghidra1 Date: Wed, 22 May 2024 17:40:21 -0400 Subject: [PATCH 08/10] GP-0 Reverted python3 minimum version requirement to 3.7 --- GhidraDocs/InstallationGuide.html | 4 ++-- build.gradle | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/GhidraDocs/InstallationGuide.html b/GhidraDocs/InstallationGuide.html index ee24ebdbe2..22bcd35509 100644 --- a/GhidraDocs/InstallationGuide.html +++ b/GhidraDocs/InstallationGuide.html @@ -98,7 +98,7 @@ Ghidra team if you have a specific need.

-
  • Python3 (3.9 to 3.12; for Debugger support)
  • +
  • Python3 (3.7 to 3.12; for Debugger support)