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
The Debugger now uses Python to connect to the host platform's native debuggers. This requires -Python 3.9 or later and some additional packages. These packages are included in the distribution, +Python3 (3.7 to 3.12) and some additional packages. These packages are included in the distribution, but you may still install them from PyPI if you prefer: