Merge remote-tracking branch 'origin/Ghidra_11.1'

This commit is contained in:
ghidra1
2024-05-22 18:32:41 -04:00
16 changed files with 152 additions and 50 deletions
@@ -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:
@@ -51,7 +55,10 @@ def main():
cmd.ghidra_trace_sync_enable()
# TODO: HACK
dbg.wait()
try:
dbg.wait()
except KeyboardInterrupt as ki:
dbg.interrupt()
cmd.repl()
@@ -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'
@@ -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]
@@ -84,7 +84,7 @@ class ProcessState(object):
except BaseException as e:
print(f"Couldn't record page with SP: {e}")
self.visited.add(hashable_frame)
if first or self.regions or self.threads or self.modules:
if first or self.regions or self.modules:
# Sections, memory syscalls, or stack allocations
commands.put_regions()
self.regions = False
@@ -153,7 +153,7 @@ def process_event(self, listener, event):
print(f"Ignoring {desc} because target is invalid")
return
event_process = util.get_process()
if event_process.IsValid() and event_process not in PROC_STATE:
if event_process.IsValid() and event_process.GetProcessID() not in PROC_STATE:
PROC_STATE[event_process.GetProcessID()] = ProcessState()
rc = event_process.GetBroadcaster().AddListener(listener, ALL_EVENTS)
if not rc:
@@ -657,7 +657,7 @@ def read_mem(process: sch.Schema('Process'), range: AddressRange):
f'ghidra trace putmem 0x{offset_start:x} {range.length()}', result)
if result.Succeeded():
return
print(f"Could not read 0x{offset_start:x}: {result}")
#print(f"Could not read 0x{offset_start:x}: {result}")
exec_convert_errors(
f'ghidra trace putmem-state 0x{offset_start:x} {range.length()} error')
@@ -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()
@@ -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,
@@ -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);
@@ -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;
}
}
@@ -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);
@@ -76,6 +76,18 @@ public abstract class AbstractHtmlLabel extends JLabel
updateHtmlView();
}
/**
* Returns the original text of the label.
* <p>
* The {@link #getText()} method for this class can return a value that is missing the leading
* &lt;html&gt; tag.
*
* @return text of this label
*/
public String getOriginalText() {
return isHtml ? HTML_TAG + getText() : getText();
}
@Override
public void updateUI() {
super.updateUI();
@@ -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());
}
}
@@ -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
@@ -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);
}
+2 -2
View File
@@ -98,7 +98,7 @@ Ghidra team if you have a specific need.</p></blockquote>
</li>
</ul>
</ul>
<li>Python3 (3.9 to 3.12; for Debugger support)</li>
<li>Python3 (3.7 to 3.12; for Debugger support)</li>
<ul>
<li>This is available from <a href="https://python.org">Python.org</a> or most operating system's
app stores or software repositories. For Linux it is recommended that the system's package
@@ -371,7 +371,7 @@ existing pre-built native binaries in the <i>os/&lt;platform&gt;/</i> subdirecto
<h2><a name="DebuggerPython"></a>Installing the Debugger's Python Dependencies</h2>
<p>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:</p>
<ul>
<li>psutil</li>
+3 -3
View File
@@ -48,7 +48,7 @@ if ("32".equals(System.getProperty("sun.arch.data.model"))) {
/***************************************************************************************
* Identify supported Python command
***************************************************************************************/
project.ext.SUPPORTED_PY_VERSIONS = ['3.12', '3.11', '3.10', '3.9']
project.ext.SUPPORTED_PY_VERSIONS = ['3.12', '3.11', '3.10', '3.9', '3.8', '3.7']
project.ext.PYTHON3 = findPython3()
/*********************************************************************************
@@ -213,10 +213,10 @@ def findPython3() {
}
}
// Don't fail until task execution. Just let "python3" fail.
// Force use of non-existent python3.9 instead of unsupported python version
// Force use of non-existent python3.7 instead of unsupported python version
// which should fail if a python build is performed.
println("Warning: Python3 command not found (required for build)")
return 'python3.9'
return 'python3.7'
}
/******************************************************************************************