mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2026-05-23 13:16:48 +08:00
Merge remote-tracking branch 'origin/Ghidra_11.1'
This commit is contained in:
@@ -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')
|
||||
|
||||
|
||||
+3
-3
@@ -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()
|
||||
|
||||
+2
@@ -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);
|
||||
|
||||
+41
-7
@@ -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
|
||||
* <html> tag.
|
||||
*
|
||||
* @return text of this label
|
||||
*/
|
||||
public String getOriginalText() {
|
||||
return isHtml ? HTML_TAG + getText() : getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateUI() {
|
||||
super.updateUI();
|
||||
|
||||
+6
-12
@@ -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);
|
||||
}
|
||||
@@ -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/<platform>/</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
@@ -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'
|
||||
}
|
||||
|
||||
/******************************************************************************************
|
||||
|
||||
Reference in New Issue
Block a user