Renaming Pyhidra to PyGhidra

This commit is contained in:
Ryan Kurtz 2024-09-05 10:35:28 -04:00 committed by DC3-TSD
parent 92d0f1dacf
commit 5b81139197
78 changed files with 370 additions and 629 deletions

View File

@ -65,7 +65,7 @@ public class VSCodeProjectScript extends GhidraScript {
writeSettings(installDir, projectDir, classpathSourceMap);
writeLaunch(installDir, projectDir, classpathSourceMap);
writeSampleScriptJava(projectDir);
writeSampleScriptPyhidra(projectDir);
writeSampleScriptPyGhidra(projectDir);
writeSampleModule(installDir, projectDir);
println("Successfully created VSCode project directory at: " + projectDir);
@ -228,13 +228,13 @@ public class VSCodeProjectScript extends GhidraScript {
FileUtils.writeStringToFile(scriptFile, sampleScript, StandardCharsets.UTF_8);
}
private void writeSampleScriptPyhidra(File projectDir) throws IOException {
private void writeSampleScriptPyGhidra(File projectDir) throws IOException {
File scriptsDir = new File(projectDir, "ghidra_scripts");
File scriptFile = new File(scriptsDir, "sample_script.py");
String sampleScript = """
# Sample Pyhidra GhidraScript
# Sample PyGhidra GhidraScript
# @category Examples
# @runtime Pyhidra
# @runtime PyGhidra
from java.util import LinkedList
java_list = LinkedList([1,2,3])

View File

@ -2,7 +2,7 @@
<launchConfiguration type="org.eclipse.jdt.launching.remoteJavaApplication">
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/Features Pyhidra"/>
<listEntry value="/Features PyGhidra"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="4"/>
@ -12,6 +12,6 @@
<mapEntry key="hostname" value="localhost"/>
<mapEntry key="port" value="18001"/>
</mapAttribute>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Features Pyhidra"/>
<stringAttribute key="org.eclipse.jdt.launching.PROJECT_ATTR" value="Features PyGhidra"/>
<stringAttribute key="org.eclipse.jdt.launching.VM_CONNECTOR_ID" value="org.eclipse.jdt.launching.socketAttachConnector"/>
</launchConfiguration>

View File

@ -5,7 +5,7 @@
<booleanAttribute key="org.eclipse.debug.core.launchGroup.0.adoptIfRunning" value="false"/>
<booleanAttribute key="org.eclipse.debug.core.launchGroup.0.enabled" value="true"/>
<stringAttribute key="org.eclipse.debug.core.launchGroup.0.mode" value="debug"/>
<stringAttribute key="org.eclipse.debug.core.launchGroup.0.name" value="_Pyhidra GUI Debug"/>
<stringAttribute key="org.eclipse.debug.core.launchGroup.0.name" value="_PyGhidra GUI Debug"/>
<stringAttribute key="org.eclipse.debug.core.launchGroup.1.action" value="NONE"/>
<booleanAttribute key="org.eclipse.debug.core.launchGroup.1.adoptIfRunning" value="true"/>
<booleanAttribute key="org.eclipse.debug.core.launchGroup.1.enabled" value="true"/>

View File

@ -2,7 +2,7 @@
<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/Features Pyhidra/src/main/py/src/pyhidra"/>
<listEntry value="/Features PyGhidra/src/main/py/src/pyghidra"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="2"/>
@ -14,11 +14,11 @@
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-v&#13;&#10;-g"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="Features Pyhidra"/>
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="Features PyGhidra"/>
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>
</launchConfiguration>

View File

@ -5,7 +5,7 @@
<booleanAttribute key="org.eclipse.debug.core.launchGroup.0.adoptIfRunning" value="false"/>
<booleanAttribute key="org.eclipse.debug.core.launchGroup.0.enabled" value="true"/>
<stringAttribute key="org.eclipse.debug.core.launchGroup.0.mode" value="debug"/>
<stringAttribute key="org.eclipse.debug.core.launchGroup.0.name" value="_Pyhidra Interpreter Debug"/>
<stringAttribute key="org.eclipse.debug.core.launchGroup.0.name" value="_PyGhidra Interpreter Debug"/>
<stringAttribute key="org.eclipse.debug.core.launchGroup.1.action" value="NONE"/>
<booleanAttribute key="org.eclipse.debug.core.launchGroup.1.adoptIfRunning" value="true"/>
<booleanAttribute key="org.eclipse.debug.core.launchGroup.1.enabled" value="true"/>

View File

@ -2,7 +2,7 @@
<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/Features Pyhidra/src/main/py/src/pyhidra"/>
<listEntry value="/Features PyGhidra/src/main/py/src/pyghidra"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="2"/>
@ -14,11 +14,11 @@
<listAttribute key="org.eclipse.debug.ui.favoriteGroups">
<listEntry value="org.eclipse.debug.ui.launchGroup.run"/>
</listAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-v"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="Features Pyhidra"/>
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="Features PyGhidra"/>
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>
</launchConfiguration>

View File

@ -2,7 +2,7 @@
<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/Features Pyhidra/src/main/py/src/pyhidra"/>
<listEntry value="/Features PyGhidra/src/main/py/src/pyghidra"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="2"/>
@ -10,13 +10,13 @@
<mapAttribute key="org.eclipse.debug.core.environmentVariables">
<mapEntry key="GHIDRA_INSTALL_DIR" value="${project_loc:/___root}"/>
<mapEntry key="JAVA_HOME_OVERRIDE" value="${ee_home:JavaSE-21}"/>
<mapEntry key="PYHIDRA_DEBUG" value="1"/>
<mapEntry key="PYGHIDRA_DEBUG" value="1"/>
</mapAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-v&#13;&#10;-g"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="Features Pyhidra"/>
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="Features PyGhidra"/>
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>
</launchConfiguration>

View File

@ -2,7 +2,7 @@
<launchConfiguration type="org.python.pydev.debug.regularLaunchConfigurationType">
<booleanAttribute key="org.eclipse.debug.core.ATTR_FORCE_SYSTEM_CONSOLE_ENCODING" value="false"/>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_PATHS">
<listEntry value="/Features Pyhidra/src/main/py/src/pyhidra"/>
<listEntry value="/Features PyGhidra/src/main/py/src/pyghidra"/>
</listAttribute>
<listAttribute key="org.eclipse.debug.core.MAPPED_RESOURCE_TYPES">
<listEntry value="2"/>
@ -10,13 +10,13 @@
<mapAttribute key="org.eclipse.debug.core.environmentVariables">
<mapEntry key="GHIDRA_INSTALL_DIR" value="${project_loc:/___root}"/>
<mapEntry key="JAVA_HOME_OVERRIDE" value="${ee_home:JavaSE-21}"/>
<mapEntry key="PYHIDRA_DEBUG" value="1"/>
<mapEntry key="PYGHIDRA_DEBUG" value="1"/>
</mapAttribute>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_LOCATION" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_OTHER_WORKING_DIRECTORY" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_TOOL_ARGUMENTS" value="-v"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:Features Pyhidra/src/main/py/src/pyhidra}"/>
<stringAttribute key="org.eclipse.ui.externaltools.ATTR_WORKING_DIRECTORY" value="${workspace_loc:Features PyGhidra/src/main/py/src/pyghidra}"/>
<stringAttribute key="org.python.pydev.debug.ATTR_INTERPRETER" value="__default"/>
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="Features Pyhidra"/>
<stringAttribute key="org.python.pydev.debug.ATTR_PROJECT" value="Features PyGhidra"/>
<stringAttribute key="process_factory_id" value="org.python.pydev.debug.processfactory.PyProcessFactory"/>
</launchConfiguration>

View File

@ -22,7 +22,7 @@ apply from: "$rootProject.projectDir/gradle/javadoc.gradle"
apply from: "${rootProject.projectDir}/gradle/hasPythonPackage.gradle"
apply plugin: 'eclipse'
eclipse.project.name = 'Features Pyhidra'
eclipse.project.name = 'Features PyGhidra'
dependencies {
@ -53,28 +53,28 @@ distributePyDep("setuptools-68.0.0-py3-none-any.whl")
task installJPype(type: Exec) {
dependsOn(":createPythonVirtualEnvironment")
File depsDir = file("${DEPS_DIR}/Pyhidra")
File binRepoDir = file("${BIN_REPO}/Ghidra/Features/Pyhidra")
File depsDir = file("${DEPS_DIR}/PyGhidra")
File binRepoDir = file("${BIN_REPO}/Ghidra/Features/PyGhidra")
def dir = depsDir.exists() ? depsDir : binRepoDir
commandLine "$PYTHON3_VENV", "-m", "pip", "install", "--no-index", "-f", "$dir", "JPype1"
}
// Install Pyhidra in editable mode to the development virtual environment
task installEditablePyhidra(type: Exec) {
// Install PyGhidra in editable mode to the development virtual environment
task installEditablePyGhidra(type: Exec) {
dependsOn("installJPype")
commandLine "$PYTHON3_VENV", "-m", "pip", "install", "-e", "src/main/py"
}
rootProject.prepDev.dependsOn installEditablePyhidra
rootProject.prepDev.dependsOn installEditablePyGhidra
// Add pyhidraLauncher.py to the release
// Add pyghidra_launcher.py to the release
rootProject.assembleDistribution {
dependsOn(buildPyPackage)
def p = this.project
def zipPath = getZipPath(p)
from (this.project.projectDir.toString()) {
include "pyhidraLauncher.py"
include "pyghidra_launcher.py"
into { zipPath }
}
}

View File

@ -3,5 +3,5 @@
Module.manifest||GHIDRA||||END|
data/python.theme.properties||GHIDRA||||END|
src/main/help/help/TOC_Source.xml||GHIDRA||||END|
src/main/help/help/topics/Pyhidra/interpreter.html||GHIDRA||||END|
src/main/help/help/topics/PyGhidra/interpreter.html||GHIDRA||||END|
src/main/resources/images/python.png||GHIDRA||||END|

View File

@ -1,6 +1,6 @@
# Examples of Pyhidra-specific functionality
# Examples of PyGhidra-specific functionality
# @category: Examples.Python
# @runtime Pyhidra
# @runtime PyGhidra
# we can import java libraries just as if they were python libraries

View File

@ -6,16 +6,16 @@ from pathlib import Path
from typing import List
from sys import stderr
def upgrade(pip_args: List[str], dist_dir: Path, current_pyhidra_version: str) -> bool:
from packaging.version import Version # if pyhidra imported, we know we have packaging
included_pyhidra: Path = next(dist_dir.glob('pyhidra-*.whl'), None)
if included_pyhidra is None:
print('Warning: included pyhidra wheel was not found', file=sys.stderr)
def upgrade(pip_args: List[str], dist_dir: Path, current_pyghidra_version: str) -> bool:
from packaging.version import Version # if pyghidra imported, we know we have packaging
included_pyghidra: Path = next(dist_dir.glob('pyghidra-*.whl'), None)
if included_pyghidra is None:
print('Warning: included pyghidra wheel was not found', file=sys.stderr)
return
included_version: Version = Version(included_pyhidra.name.split('-')[1])
current_version: Version = Version(current_pyhidra_version)
included_version: Version = Version(included_pyghidra.name.split('-')[1])
current_version: Version = Version(current_pyghidra_version)
if included_version > current_version:
choice: str = input(f'Do you wish to upgrade Pyhidra {current_version} to {included_version} (y/n)? ')
choice: str = input(f'Do you wish to upgrade PyGhidra {current_version} to {included_version} (y/n)? ')
if choice.lower() in ('y', 'yes'):
pip_args.append('-U')
subprocess.check_call(pip_args)
@ -25,7 +25,7 @@ def upgrade(pip_args: List[str], dist_dir: Path, current_pyhidra_version: str) -
return False
def install(pip_args: List[str], dist_dir: Path) -> bool:
choice: str = input('Do you wish to install Pyhidra (y/n)? ')
choice: str = input('Do you wish to install PyGhidra (y/n)? ')
if choice.lower() in ('y', 'yes'):
subprocess.check_call(pip_args)
return True
@ -48,16 +48,16 @@ def main() -> None:
python_cmd: str = sys.executable
install_dir: Path = Path(args.install_dir)
venv_dir: Path = install_dir / 'build' / 'venv'
pyhidra_dir: Path = install_dir / 'Ghidra' / 'Features' / 'Pyhidra'
src_dir: Path = pyhidra_dir / 'src' / 'main' / 'py'
dist_dir: Path = pyhidra_dir / 'pypkg' / 'dist'
pyghidra_dir: Path = install_dir / 'Ghidra' / 'Features' / 'PyGhidra'
src_dir: Path = pyghidra_dir / 'src' / 'main' / 'py'
dist_dir: Path = pyghidra_dir / 'pypkg' / 'dist'
# If headless, force console mode
if args.headless:
args.console = True
if args.dev:
# If in dev mode, launch pyhidra from the source tree using the development virtual environment
# If in dev mode, launch PyGhidra from the source tree using the development virtual environment
if not venv_dir.is_dir():
print('Virtual environment not found!')
print('Run "gradle prepdev" and try again.')
@ -66,17 +66,17 @@ def main() -> None:
linux_python_cmd = str(venv_dir / 'bin' / 'python3')
python_cmd = win_python_cmd if os.name == 'nt' else linux_python_cmd
else:
# If in release mode, offer to install or upgrade pyhidra before launching from user-controlled environment
pip_args: List[str] = [python_cmd, '-m', 'pip', 'install', '--no-index', '-f', str(dist_dir), 'pyhidra']
# If in release mode, offer to install or upgrade PyGhidra before launching from user-controlled environment
pip_args: List[str] = [python_cmd, '-m', 'pip', 'install', '--no-index', '-f', str(dist_dir), 'pyghidra']
try:
import pyhidra
upgrade(pip_args, dist_dir, pyhidra.__version__)
import pyghidra
upgrade(pip_args, dist_dir, pyghidra.__version__)
except ImportError:
if not install(pip_args, dist_dir):
return
# Launch Pyhidra
py_args: List[str] = [python_cmd, '-m', 'pyhidra.ghidra_launch', '--install-dir', str(install_dir)]
# Launch PyGhidra
py_args: List[str] = [python_cmd, '-m', 'pyghidra.ghidra_launch', '--install-dir', str(install_dir)]
if args.headless:
py_args += ['ghidra.app.util.headless.AnalyzeHeadless']
else:

View File

@ -3,7 +3,7 @@
<tocroot>
<tocref id="Ghidra Functionality">
<tocref id="Scripting">
<tocdef id="Pyhidra Interpreter" sortgroup="z" text="Pyhidra Interpreter" target="help/topics/Pyhidra/interpreter.html" />
<tocdef id="PyGhidra Interpreter" sortgroup="z" text="PyGhidra Interpreter" target="help/topics/PyGhidra/interpreter.html" />
</tocref>
</tocref>
</tocroot>

View File

@ -2,15 +2,15 @@
<HTML>
<HEAD>
<TITLE>Pyhidra Interpreter</TITLE>
<TITLE>PyGhidra Interpreter</TITLE>
<LINK rel="stylesheet" type="text/css" href="help/shared/DefaultStyle.css">
</HEAD>
<BODY lang="EN-US">
<H1><A name="Pyhidra"></A>Pyhidra Interpreter</H1>
<H1><A name="PyGhidra"></A>PyGhidra Interpreter</H1>
<P>
The Ghidra <I>Pyhidra Interpreter</I> provides a full general-purpose Python interactive shell
The Ghidra <I>PyGhidra Interpreter</I> provides a full general-purpose Python interactive shell
and allows you to interact with your current Ghidra session by exposing Ghidra's powerful Java
API through the magic of Jpype.
</P>
@ -18,7 +18,7 @@
<H2>Environment</H2>
<BLOCKQUOTE>
<P>
The Ghidra <I>Pyhidra Interpreter</I> is configured to run in a similar context as a Ghidra
The Ghidra <I>PyGhidra Interpreter</I> is configured to run in a similar context as a Ghidra
script. Therefore, you immediately have access to variables such as <TT>currentProgram</TT>,
<TT>currentSelection</TT>, <TT>currentAddress</TT>, etc without needing to import them.
These variables exist as Java objects behind the scenes, but Jpype allows you to interact with
@ -78,7 +78,7 @@
<H2>Keybindings</H2>
<BLOCKQUOTE>
<P>
The Ghidra <I>Pyhidra Interpreter</I> supports the following hard-coded keybindings:
The Ghidra <I>PyGhidra Interpreter</I> supports the following hard-coded keybindings:
<UL>
<LI><B>(up):</B>&nbsp;&nbsp;Move backward in command stack</LI>
<LI><B>(down):</B>&nbsp;&nbsp;Move forward in command stack</LI>
@ -100,7 +100,7 @@
<H2>Copy/Paste</H2>
<BLOCKQUOTE>
<P>
Copy and paste from within the Ghidra <I>Pyhidra Interpreter</I> should work as expected for
Copy and paste from within the Ghidra <I>PyGhidra Interpreter</I> should work as expected for
your given environment:
<UL>
<LI><B>Windows:</B>&nbsp;&nbsp;CTRL+C / CTRL+V</LI>
@ -113,7 +113,7 @@
<H2>API Documentation</H2>
<BLOCKQUOTE>
<P>
The built-in <TT>help()</TT> Python function has been altered by the Ghidra <I>Pyhidra Interpreter</I>
The built-in <TT>help()</TT> Python function has been altered by the Ghidra <I>PyGhidra Interpreter</I>
to add support for displaying Ghidra's Javadoc (where available) for a given Ghidra class, method,
or variable. For example, to see Ghidra's Javadoc on the <TT>state</TT> variable, simply do:
<PRE>
@ -156,7 +156,7 @@
</P>
</BLOCKQUOTE>
<P align="left" class="providedbyplugin">Provided by: <I>PyhidraPlugin</I></P>
<P align="left" class="providedbyplugin">Provided by: <I>PyGhidraPlugin</I></P>
<P>&nbsp;</P>
<BR>

View File

@ -1,11 +1,11 @@
package ghidra.pyhidra;
package ghidra.pyghidra;
import java.util.function.Consumer;
import ghidra.app.CorePluginPackage;
import ghidra.app.plugin.PluginCategoryNames;
import ghidra.app.plugin.ProgramPlugin;
import ghidra.app.plugin.core.interpreter.*;
import ghidra.app.plugin.core.interpreter.InterpreterPanelService;
import ghidra.app.script.GhidraState;
import ghidra.framework.plugintool.PluginInfo;
import ghidra.framework.plugintool.PluginTool;
@ -13,8 +13,8 @@ import ghidra.framework.plugintool.util.PluginStatus;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.pyhidra.interpreter.InterpreterGhidraScript;
import ghidra.pyhidra.interpreter.PyhidraInterpreter;
import ghidra.pyghidra.interpreter.InterpreterGhidraScript;
import ghidra.pyghidra.interpreter.PyGhidraInterpreter;
import ghidra.util.exception.AssertException;
/**
@ -25,20 +25,20 @@ import ghidra.util.exception.AssertException;
status = PluginStatus.RELEASED,
packageName = CorePluginPackage.NAME,
category = PluginCategoryNames.COMMON,
shortDescription = "Pyhidra Interpreter",
shortDescription = "PyGhidra Interpreter",
description = "Provides an interactive Python Interpreter that is tightly integrated with a loaded Ghidra program.",
servicesRequired = { InterpreterPanelService.class }
)
//@formatter:on
public class PyhidraPlugin extends ProgramPlugin {
public class PyGhidraPlugin extends ProgramPlugin {
public static final String TITLE = "Pyhidra";
private static Consumer<PyhidraPlugin> initializer = null;
public static final String TITLE = "PyGhidra";
private static Consumer<PyGhidraPlugin> initializer = null;
public final InterpreterGhidraScript script = new InterpreterGhidraScript();
public PyhidraInterpreter interpreter;
public PyGhidraInterpreter interpreter;
public PyhidraPlugin(PluginTool tool) {
public PyGhidraPlugin(PluginTool tool) {
super(tool);
GhidraState state = new GhidraState(tool, tool.getProject(), null, null, null, null);
// use the copy constructor so this state doesn't fire plugin events
@ -54,16 +54,16 @@ public class PyhidraPlugin extends ProgramPlugin {
* @param initializer the Python side initializer
* @throws AssertException if the code completer has already been set
*/
public static void setInitializer(Consumer<PyhidraPlugin> initializer) {
if (PyhidraPlugin.initializer != null) {
throw new AssertException("PyhidraPlugin initializer has already been set");
public static void setInitializer(Consumer<PyGhidraPlugin> initializer) {
if (PyGhidraPlugin.initializer != null) {
throw new AssertException("PyGhidraPlugin initializer has already been set");
}
PyhidraPlugin.initializer = initializer;
PyGhidraPlugin.initializer = initializer;
}
@Override
public void init() {
interpreter = new PyhidraInterpreter(this, PyhidraPlugin.initializer != null);
interpreter = new PyGhidraInterpreter(this, PyGhidraPlugin.initializer != null);
if (initializer != null) {
initializer.accept(this);
}

View File

@ -1,6 +1,6 @@
package ghidra.pyhidra;
package ghidra.pyghidra;
import java.io.*;
import java.io.PrintWriter;
import java.lang.invoke.MethodHandles;
import java.util.List;
import java.util.function.Consumer;
@ -12,15 +12,15 @@ import ghidra.program.model.address.Address;
import ghidra.program.model.listing.Program;
import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
import ghidra.pyhidra.PythonFieldExposer.ExposedFields;
import ghidra.util.exception.AssertException;
import ghidra.pyghidra.PythonFieldExposer.ExposedFields;
import ghidra.util.SystemUtilities;
import ghidra.util.exception.AssertException;
import ghidra.util.task.TaskMonitor;
/**
* {@link GhidraScript} provider for native python3 scripts
*/
public final class PyhidraScriptProvider extends AbstractPythonScriptProvider {
public final class PyGhidraScriptProvider extends AbstractPythonScriptProvider {
private static Consumer<GhidraScript> scriptRunner = null;
@ -34,37 +34,37 @@ public final class PyhidraScriptProvider extends AbstractPythonScriptProvider {
* @throws AssertException if the script runner has already been set
*/
public static void setScriptRunner(Consumer<GhidraScript> scriptRunner) {
if (PyhidraScriptProvider.scriptRunner != null) {
if (PyGhidraScriptProvider.scriptRunner != null) {
throw new AssertException("scriptRunner has already been set");
}
PyhidraScriptProvider.scriptRunner = scriptRunner;
PyGhidraScriptProvider.scriptRunner = scriptRunner;
}
@Override
public String getDescription() {
return PyhidraPlugin.TITLE;
return PyGhidraPlugin.TITLE;
}
@Override
public String getRuntimeEnvironmentName() {
return PyhidraPlugin.TITLE;
return PyGhidraPlugin.TITLE;
}
@Override
public GhidraScript getScriptInstance(ResourceFile sourceFile, PrintWriter writer)
throws GhidraScriptLoadException {
if (scriptRunner == null) {
String msg = "Ghidra was not started with pyhidra. Python is not available";
String msg = "Ghidra was not started with PyGhidra. Python is not available";
throw new GhidraScriptLoadException(msg);
}
GhidraScript script = SystemUtilities.isInHeadlessMode() ? new PyhidraHeadlessScript()
: new PyhidraGhidraScript();
GhidraScript script = SystemUtilities.isInHeadlessMode() ? new PyGhidraHeadlessScript()
: new PyGhidraGhidraScript();
script.setSourceFile(sourceFile);
return script;
}
@ExposedFields(
exposer = PyhidraGhidraScript.ExposedField.class,
exposer = PyGhidraGhidraScript.ExposedField.class,
names = {
"currentAddress", "currentLocation", "currentSelection",
"currentHighlight", "currentProgram", "monitor",
@ -78,7 +78,7 @@ public final class PyhidraScriptProvider extends AbstractPythonScriptProvider {
ResourceFile.class, GhidraState.class, PrintWriter.class
}
)
final static class PyhidraGhidraScript extends GhidraScript
final static class PyGhidraGhidraScript extends GhidraScript
implements PythonFieldExposer {
@Override
@ -92,13 +92,13 @@ public final class PyhidraScriptProvider extends AbstractPythonScriptProvider {
*/
private static class ExposedField extends PythonFieldExposer.ExposedField {
public ExposedField(String name, Class<?> type) {
super(MethodHandles.lookup().in(PyhidraGhidraScript.class), name, type);
super(MethodHandles.lookup().in(PyGhidraGhidraScript.class), name, type);
}
}
}
@ExposedFields(
exposer = PyhidraHeadlessScript.ExposedField.class,
exposer = PyGhidraHeadlessScript.ExposedField.class,
names = {
"currentAddress", "currentLocation", "currentSelection",
"currentHighlight", "currentProgram", "monitor",
@ -112,7 +112,7 @@ public final class PyhidraScriptProvider extends AbstractPythonScriptProvider {
ResourceFile.class, GhidraState.class, PrintWriter.class
}
)
final static class PyhidraHeadlessScript extends HeadlessScript
final static class PyGhidraHeadlessScript extends HeadlessScript
implements PythonFieldExposer {
@Override
@ -126,7 +126,7 @@ public final class PyhidraScriptProvider extends AbstractPythonScriptProvider {
*/
private static class ExposedField extends PythonFieldExposer.ExposedField {
public ExposedField(String name, Class<?> type) {
super(MethodHandles.lookup().in(PyhidraHeadlessScript.class), name, type);
super(MethodHandles.lookup().in(PyGhidraHeadlessScript.class), name, type);
}
}
}

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra;
package ghidra.pyghidra;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@ -21,8 +21,8 @@ import ghidra.util.exception.AssertException;
* This interface is for <b>internal use only</b> and is only public so it can be
* visible to Python to apply the Jpype class customizations.
*/
public sealed interface PythonFieldExposer permits PyhidraScriptProvider.PyhidraGhidraScript,
PyhidraScriptProvider.PyhidraHeadlessScript {
public sealed interface PythonFieldExposer permits PyGhidraScriptProvider.PyGhidraGhidraScript,
PyGhidraScriptProvider.PyGhidraHeadlessScript {
/**
* Gets a mapping of all the explicitly exposed fields of a class.

View File

@ -1,13 +1,13 @@
package ghidra.pyhidra.interpreter;
package ghidra.pyghidra.interpreter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import ghidra.pyhidra.PyhidraPlugin;
import docking.ActionContext;
import docking.action.KeyBindingData;
import docking.action.DockingAction;
import docking.action.ToolBarData;
import ghidra.pyghidra.PyGhidraPlugin;
import ghidra.util.HelpLocation;
import resources.ResourceManager;
@ -15,10 +15,10 @@ import static docking.DockingUtils.CONTROL_KEY_MODIFIER_MASK;
final class CancelAction extends DockingAction {
private final PyhidraConsole console;
private final PyGhidraConsole console;
CancelAction(PyhidraConsole console) {
super("Cancel", PyhidraPlugin.class.getSimpleName());
CancelAction(PyGhidraConsole console) {
super("Cancel", PyGhidraPlugin.class.getSimpleName());
this.console = console;
setDescription("Interrupt the interpreter");
ImageIcon image = ResourceManager.loadImage("images/dialog-cancel.png");
@ -26,7 +26,7 @@ final class CancelAction extends DockingAction {
setEnabled(true);
KeyBindingData key = new KeyBindingData(KeyEvent.VK_I, CONTROL_KEY_MODIFIER_MASK);
setKeyBindingData(key);
setHelpLocation(new HelpLocation(PyhidraPlugin.TITLE, "Interrupt_Interpreter"));
setHelpLocation(new HelpLocation(PyGhidraPlugin.TITLE, "Interrupt_Interpreter"));
}
@Override

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.interpreter;
package ghidra.pyghidra.interpreter;
import java.io.PrintWriter;
@ -10,11 +10,11 @@ import ghidra.program.util.ProgramLocation;
import ghidra.program.util.ProgramSelection;
/**
* Custom {@link GhidraScript} only for use with the pyhidra interpreter console
* Custom {@link GhidraScript} only for use with the PyGhidra interpreter console
*/
public final class InterpreterGhidraScript extends GhidraScript {
// public default constructor for use by PyhidraPlugin
// public default constructor for use by PyGhidraPlugin
// the default constructor for FlatProgramAPI has protected visibility
public InterpreterGhidraScript() {
}

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.interpreter;
package ghidra.pyghidra.interpreter;
import java.io.PrintWriter;
@ -14,6 +14,6 @@ final class InterpreterTaskMonitor extends TaskMonitorAdapter {
@Override
public void setMessage(String message) {
output.println("<pyhidra-interactive>: " + message);
output.println("<pyghidra-interactive>: " + message);
}
}

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.interpreter;
package ghidra.pyghidra.interpreter;
import java.util.List;
@ -12,10 +12,10 @@ import ghidra.util.Disposable;
* This interface is for <b>internal use only</b> and is only public so it can be
* implemented in Python.
*/
public interface PyhidraConsole extends Disposable {
public interface PyGhidraConsole extends Disposable {
/**
* Generates code completions for the pyhidra interpreter
* Generates code completions for the PyGhidra interpreter
*
* @param cmd The command to get code completions for
* @param caretPos The position of the caret in the input string 'cmd'.
@ -26,12 +26,12 @@ public interface PyhidraConsole extends Disposable {
List<CodeCompletion> getCompletions(String cmd, int caretPos);
/**
* Restarts the pyhidra console
* Restarts the PyGhidra console
*/
void restart();
/**
* Interrupts the code running in the pyhidra console
* Interrupts the code running in the PyGhidra console
*/
void interrupt();
}

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.interpreter;
package ghidra.pyghidra.interpreter;
import java.io.PrintWriter;
import java.util.List;
@ -8,20 +8,20 @@ import ghidra.app.plugin.core.console.CodeCompletion;
import ghidra.app.plugin.core.interpreter.InterpreterConnection;
import ghidra.app.plugin.core.interpreter.InterpreterConsole;
import ghidra.app.plugin.core.interpreter.InterpreterPanelService;
import ghidra.pyhidra.PyhidraPlugin;
import ghidra.pyghidra.PyGhidraPlugin;
import ghidra.util.Disposable;
import ghidra.util.exception.AssertException;
import resources.ResourceManager;
/**
* The pyhidra interpreter connection
* The PyGhidra interpreter connection
*/
public final class PyhidraInterpreter implements Disposable, InterpreterConnection {
public final class PyGhidraInterpreter implements Disposable, InterpreterConnection {
private PyhidraConsole pyhidraConsole = null;
private PyGhidraConsole pyghidraConsole = null;
public final InterpreterConsole console;
public PyhidraInterpreter(PyhidraPlugin plugin, boolean isPythonAvailable) {
public PyGhidraInterpreter(PyGhidraPlugin plugin, boolean isPythonAvailable) {
InterpreterPanelService service =
plugin.getTool().getService(InterpreterPanelService.class);
console = service.createInterpreterPanel(this, false);
@ -32,8 +32,8 @@ public final class PyhidraInterpreter implements Disposable, InterpreterConnecti
@Override
public void dispose() {
if (pyhidraConsole != null) {
pyhidraConsole.dispose();
if (pyghidraConsole != null) {
pyghidraConsole.dispose();
}
console.dispose();
}
@ -45,7 +45,7 @@ public final class PyhidraInterpreter implements Disposable, InterpreterConnecti
@Override
public String getTitle() {
return PyhidraPlugin.TITLE;
return PyGhidraPlugin.TITLE;
}
@Override
@ -55,20 +55,20 @@ public final class PyhidraInterpreter implements Disposable, InterpreterConnecti
@Override
public List<CodeCompletion> getCompletions(String cmd, int caretPos) {
if (pyhidraConsole == null) {
if (pyghidraConsole == null) {
return List.of();
}
return pyhidraConsole.getCompletions(cmd, caretPos);
return pyghidraConsole.getCompletions(cmd, caretPos);
}
private void unavailableCallback() {
console.setInputPermitted(false);
PrintWriter out = console.getOutWriter();
out.println("Ghidra was not started with pyhidra. Python is not available.");
out.println("Ghidra was not started with PyGhidra. Python is not available.");
}
/**
* Initializes the interpreter with the provided PyhidraConsole.
* Initializes the interpreter with the provided PyGhidraConsole.
*
* This method is for <b>internal use only</b> and is only public so it can be
* called from Python.
@ -76,13 +76,13 @@ public final class PyhidraInterpreter implements Disposable, InterpreterConnecti
* @param pythonSideConsole the python side console
* @throws AssertException if the interpreter has already been initialized
*/
public void init(PyhidraConsole pythonSideConsole) {
if (pyhidraConsole != null) {
public void init(PyGhidraConsole pythonSideConsole) {
if (pyghidraConsole != null) {
throw new AssertException("the interpreter has already been initialized");
}
pyhidraConsole = pythonSideConsole;
console.addFirstActivationCallback(pyhidraConsole::restart);
console.addAction(new CancelAction(pyhidraConsole));
console.addAction(new ResetAction(pyhidraConsole));
pyghidraConsole = pythonSideConsole;
console.addFirstActivationCallback(pyghidraConsole::restart);
console.addAction(new CancelAction(pyghidraConsole));
console.addAction(new ResetAction(pyghidraConsole));
}
}

View File

@ -1,9 +1,9 @@
package ghidra.pyhidra.interpreter;
package ghidra.pyghidra.interpreter;
import java.awt.event.KeyEvent;
import javax.swing.ImageIcon;
import ghidra.pyhidra.PyhidraPlugin;
import ghidra.pyghidra.PyGhidraPlugin;
import ghidra.util.HelpLocation;
import docking.ActionContext;
import docking.action.DockingAction;
@ -15,10 +15,10 @@ import static docking.DockingUtils.CONTROL_KEY_MODIFIER_MASK;
final class ResetAction extends DockingAction {
private final PyhidraConsole console;
private final PyGhidraConsole console;
ResetAction(PyhidraConsole console) {
super("Reset", PyhidraPlugin.class.getSimpleName());
ResetAction(PyGhidraConsole console) {
super("Reset", PyGhidraPlugin.class.getSimpleName());
this.console = console;
setDescription("Reset the interpreter");
ImageIcon image = ResourceManager.loadImage("images/reload3.png");
@ -26,7 +26,7 @@ final class ResetAction extends DockingAction {
setEnabled(true);
KeyBindingData key = new KeyBindingData(KeyEvent.VK_D, CONTROL_KEY_MODIFIER_MASK);
setKeyBindingData(key);
setHelpLocation(new HelpLocation(PyhidraPlugin.TITLE, "Reset_Interpreter"));
setHelpLocation(new HelpLocation(PyGhidraPlugin.TITLE, "Reset_Interpreter"));
}
@Override

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;
@ -16,7 +16,7 @@ import java.lang.invoke.MethodHandle;
* }
* }
*
* The pyhidra internals expects every {@link JavaProperty} to be an instance of this class.
* The PyGhidra internals expects every {@link JavaProperty} to be an instance of this class.
* No checking is required or performed since the {@link JavaProperty} interface and this
* class are sealed.
*/

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
/**
* Property interface for creating a Python property for getters and setters.

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.property;
package ghidra.pyghidra.property;
import java.lang.invoke.MethodHandle;

View File

@ -1,9 +1,9 @@
# pyhidra
# PyGhidra
Pyhidra is a Python library that provides direct access to the Ghidra API within a native CPython interpreter using [jpype](https://jpype.readthedocs.io/en/latest). As well, Pyhidra contains some conveniences for setting up analysis on a given sample and running a Ghidra script locally. It also contains a Ghidra plugin to allow the use of CPython from the Ghidra user interface.
PyGhidra is a Python library that provides direct access to the Ghidra API within a native CPython interpreter using [jpype](https://jpype.readthedocs.io/en/latest). As well, PyGhidra contains some conveniences for setting up analysis on a given sample and running a Ghidra script locally. It also contains a Ghidra plugin to allow the use of CPython from the Ghidra user interface.
Pyhidra was initially developed for use with Dragodis and is designed to be installable without requiring Java or Ghidra. This allows other Python projects
have pyhidra as a dependency and provide optional Ghidra functionality without requiring all users to install Java and Ghidra. It is recommended to recommend that users set the `GHIDRA_INSTALL_DIR` environment variable to simplify locating Ghidra.
PyGhidra was initially developed for use with Dragodis and is designed to be installable without requiring Java or Ghidra. This allows other Python projects
have PyGhidra as a dependency and provide optional Ghidra functionality without requiring all users to install Java and Ghidra. It is recommended to recommend that users set the `GHIDRA_INSTALL_DIR` environment variable to simplify locating Ghidra.
## Usage
@ -18,8 +18,8 @@ which will allow you to directly import `ghidra` and `java`.
*NOTE: No projects or programs get setup in this mode.*
```python
import pyhidra
pyhidra.start()
import pyghidra
pyghidra.start()
import ghidra
from ghidra.app.util.headless import HeadlessAnalyzer
@ -32,12 +32,12 @@ from java.lang import String
### Customizing Java and Ghidra initialization
JVM configuration for the classpath and vmargs may be done through a `PyhidraLauncher`.
JVM configuration for the classpath and vmargs may be done through a `PyGhidraLauncher`.
```python
from pyhidra.launcher import HeadlessPyhidraLauncher
from pyghidra.launcher import HeadlessPyGhidraLauncher
launcher = HeadlessPyhidraLauncher()
launcher = HeadlessPyGhidraLauncher()
launcher.add_classpaths("log4j-core-2.17.1.jar", "log4j-api-2.17.1.jar")
launcher.add_vmargs("-Dlog4j2.formatMsgNoLookups=true")
launcher.start()
@ -45,10 +45,10 @@ launcher.start()
### Registering an Entry Point
The `PyhidraLauncher` can also be configured through the use of a registered entry point on your own python project.
This is useful for installing your own Ghidra plugin which uses pyhidra and self-compiles.
The `PyGhidraLauncher` can also be configured through the use of a registered entry point on your own python project.
This is useful for installing your own Ghidra plugin which uses PyGhidra and self-compiles.
First create an [entry_point](https://setuptools.pypa.io/en/latest/userguide/entry_point.html) for `pyhidra.setup`
First create an [entry_point](https://setuptools.pypa.io/en/latest/userguide/entry_point.html) for `pyghidra.setup`
pointing to a single argument function which accepts the launcher instance.
```python
@ -58,7 +58,7 @@ from setuptools import setup
setup(
# ...,
entry_points={
'pyhidra.setup': [
'pyghidra.setup': [
'acme_plugin = acme.ghidra_plugin.install:setup',
]
}
@ -67,25 +67,25 @@ setup(
Then we create the target function.
This function will be called every time a user starts a pyhidra launcher.
In the same fashion, another entry point `pyhidra.pre_launch` may be registered and will be called after Ghidra and all
This function will be called every time a user starts a PyGhidra launcher.
In the same fashion, another entry point `pyghidra.pre_launch` may be registered and will be called after Ghidra and all
plugins have been loaded.
```python
# acme/ghidra_plugin/install.py
from pathlib import Path
import pyhidra
import pyghidra
def setup(launcher):
"""
Run by pyhidra launcher to install our plugin.
Run by PyGhidra launcher to install our plugin.
"""
launcher.add_classpaths("log4j-core-2.17.1.jar", "log4j-api-2.17.1.jar")
launcher.add_vmargs("-Dlog4j2.formatMsgNoLookups=true")
# Install our plugin.
source_path = Path(__file__).parent / "java" / "plugin" # path to uncompiled .java code
details = pyhidra.ExtensionDetails(
details = pyghidra.ExtensionDetails(
name="acme_plugin",
description="My Cool Plugin",
author="acme",
@ -97,15 +97,15 @@ def setup(launcher):
### Analyze a File
To have pyhidra setup a binary file for you, use the `open_program()` function.
To have PyGhidra setup a binary file for you, use the `open_program()` function.
This will setup a Ghidra project and import the given binary file as a program for you.
Again, this will also allow you to import `ghidra` and `java` to perform more advanced processing.
```python
import pyhidra
import pyghidra
with pyhidra.open_program("binary_file.exe") as flat_api:
with pyghidra.open_program("binary_file.exe") as flat_api:
program = flat_api.getCurrentProgram()
listing = program.getListing()
print(listing.getCodeUnitAt(flat_api.toAddr(0x1234)))
@ -117,12 +117,12 @@ with pyhidra.open_program("binary_file.exe") as flat_api:
decomp_api.dispose()
```
By default, pyhidra will run analysis for you. If you would like to do this yourself, set `analyze` to `False`.
By default, PyGhidra will run analysis for you. If you would like to do this yourself, set `analyze` to `False`.
```python
import pyhidra
import pyghidra
with pyhidra.open_program("binary_file.exe", analyze=False) as flat_api:
with pyghidra.open_program("binary_file.exe", analyze=False) as flat_api:
from ghidra.program.util import GhidraProgramUtilities
program = flat_api.getCurrentProgram()
@ -135,16 +135,16 @@ The `open_program()` function can also accept optional arguments to control the
(Helpful for opening up a sample in an already existing project.)
```python
import pyhidra
import pyghidra
with pyhidra.open_program("binary_file.exe", project_name="EXAM_231", project_location=r"C:\exams\231") as flat_api:
with pyghidra.open_program("binary_file.exe", project_name="EXAM_231", project_location=r"C:\exams\231") as flat_api:
...
```
### Run a Script
Pyhidra can also be used to run an existing Ghidra Python script directly in your native python interpreter
PyGhidra can also be used to run an existing Ghidra Python script directly in your native python interpreter
using the `run_script()` command.
However, while you can technically run an existing Ghidra script unmodified, you may
run into issues due to differences between Jython 2 and CPython 3.
@ -152,21 +152,21 @@ Therefore, some modification to the script may be needed.
```python
import pyhidra
import pyghidra
pyhidra.run_script(r"C:\input.exe", r"C:\some_ghidra_script.py")
pyghidra.run_script(r"C:\input.exe", r"C:\some_ghidra_script.py")
```
This can also be done on the command line using `pyhidra`.
This can also be done on the command line using `pyghidra`.
```console
> pyhidra C:\input.exe C:\some_ghidra_script.py <CLI ARGS PASSED TO SCRIPT>
> pyghidra C:\input.exe C:\some_ghidra_script.py <CLI ARGS PASSED TO SCRIPT>
```
### Handling Package Name Conflicts
There may be some Python modules and Java packages with the same import path. When this occurs the Python module takes precedence.
While jpype has its own mechanism for handling this situation, pyhidra automatically makes the Java package accessible by allowing
While jpype has its own mechanism for handling this situation, PyGhidra automatically makes the Java package accessible by allowing
it to be imported with an underscore appended to the package name.
```python

View File

@ -3,7 +3,7 @@ requires = ["setuptools", "wheel"]
build-backend = "setuptools.build_meta"
[project]
name = "pyhidra"
name = "pyghidra"
dynamic = ["version", "readme"]
description = "Native CPython for Ghidra"
license = {text = "Apache-2.0"}
@ -39,16 +39,16 @@ testing = [
]
[project.scripts]
pyhidra = "pyhidra.__main__:main"
pyghidra = "pyghidra.__main__:main"
[project.gui-scripts]
pyhidraw = "pyhidra.gui:_gui"
pyghidraw = "pyghidra.gui:_gui"
[project.urls]
Repository = "https://github.com/NationalSecurityAgency/ghidra"
[tool.setuptools.dynamic]
version = {attr = "pyhidra.__version__"}
version = {attr = "pyghidra.__version__"}
readme = {file = ["README.md"], content-type = "text/markdown"}
[tool.pytest.ini_options]

View File

@ -41,13 +41,13 @@ debug_callback = _debug_callback
# Expose API
from .core import run_script, start, started, open_program
from .launcher import DeferredPyhidraLauncher, GuiPyhidraLauncher, HeadlessPyhidraLauncher
from .launcher import DeferredPyGhidraLauncher, GuiPyGhidraLauncher, HeadlessPyGhidraLauncher
from .script import get_current_interpreter
from .version import ApplicationInfo, ExtensionDetails
__all__ = [
"debug_callback", "get_current_interpreter", "open_program", "run_script", "start",
"started", "ApplicationInfo", "DeferredPyhidraLauncher", "ExtensionDetails",
"GuiPyhidraLauncher", "HeadlessPyhidraLauncher"
"started", "ApplicationInfo", "DeferredPyGhidraLauncher", "ExtensionDetails",
"GuiPyGhidraLauncher", "HeadlessPyGhidraLauncher"
]

View File

@ -5,13 +5,13 @@ import logging
import sys
from pathlib import Path
import pyhidra
import pyhidra.core
import pyhidra.gui
import pyghidra
import pyghidra.core
import pyghidra.gui
# NOTE: this must be "pyhidra" and not __name__
logger = logging.getLogger("pyhidra")
# NOTE: this must be "pyghidra" and not __name__
logger = logging.getLogger("pyghidra")
def _interpreter(interpreter_globals: dict):
@ -24,7 +24,7 @@ def _interpreter(interpreter_globals: dict):
# pylint: disable=too-few-public-methods
class PyhidraArgs(argparse.Namespace):
class PyGhidraArgs(argparse.Namespace):
"""
Custom namespace for holding the command line arguments
"""
@ -60,18 +60,18 @@ class PyhidraArgs(argparse.Namespace):
vmargs = self.jvm_args
if self.gui:
pyhidra.gui.gui(self.install_dir, vmargs)
pyghidra.gui.gui(self.install_dir, vmargs)
return
# not in gui mode so it is easier to start Ghidra now
launcher = pyhidra.HeadlessPyhidraLauncher(
launcher = pyghidra.HeadlessPyGhidraLauncher(
verbose=self.verbose, install_dir=self.install_dir)
launcher.vm_args = vmargs + launcher.vm_args
launcher.start()
if self.script_path is not None:
try:
pyhidra.run_script(
pyghidra.run_script(
self.binary_path,
self.script_path,
project_location=self.project_path,
@ -92,7 +92,7 @@ class PyhidraArgs(argparse.Namespace):
self.verbose,
not self.skip_analysis
)
with pyhidra.core._flat_api(*args, install_dir=self.install_dir) as api:
with pyghidra.core._flat_api(*args, install_dir=self.install_dir) as api:
_interpreter(api)
else:
_interpreter(globals())
@ -129,7 +129,7 @@ class PathAction(argparse.Action):
self.nargs = '*'
self.type = str
def __call__(self, parser, namespace: PyhidraArgs, values, option_string=None):
def __call__(self, parser, namespace: PyGhidraArgs, values, option_string=None):
if not values:
return
@ -168,7 +168,7 @@ class PathAction(argparse.Action):
def _get_parser():
parser = argparse.ArgumentParser(prog="pyhidra")
parser = argparse.ArgumentParser(prog="pyghidra")
parser.add_argument(
"-v",
"--verbose",
@ -215,7 +215,7 @@ def _get_parser():
action=PathAction,
help=(
"Headless script path. The script must have a .py extension. "
"If a script is not provided, pyhidra will drop into a repl."
"If a script is not provided, pyghidra will drop into a repl."
)
)
parser.add_argument(
@ -258,7 +258,7 @@ def _get_parser():
def main():
"""
pyhidra module main function
pyghidra module main function
"""
handler = logging.StreamHandler()
formatter = logging.Formatter("%(filename)s:%(lineno)d %(message)s")
@ -266,7 +266,7 @@ def main():
logger.addHandler(handler)
parser = _get_parser()
parser.parse_args(namespace=PyhidraArgs(parser)).func()
parser.parse_args(namespace=PyGhidraArgs(parser)).func()
if __name__ == "__main__":

View File

@ -2,18 +2,18 @@ import contextlib
from pathlib import Path
from typing import Union, TYPE_CHECKING, Tuple, ContextManager, List, Optional
from pyhidra.converters import * # pylint: disable=wildcard-import, unused-wildcard-import
from pyghidra.converters import * # pylint: disable=wildcard-import, unused-wildcard-import
if TYPE_CHECKING:
from pyhidra.launcher import PyhidraLauncher
from pyghidra.launcher import PyGhidraLauncher
from ghidra.base.project import GhidraProject
from ghidra.program.flatapi import FlatProgramAPI
from ghidra.program.model.lang import CompilerSpec, Language, LanguageService
from ghidra.program.model.listing import Program
def start(verbose=False, *, install_dir: Path = None) -> "PyhidraLauncher":
def start(verbose=False, *, install_dir: Path = None) -> "PyGhidraLauncher":
"""
Starts the JVM and fully initializes Ghidra in Headless mode.
@ -22,18 +22,18 @@ def start(verbose=False, *, install_dir: Path = None) -> "PyhidraLauncher":
(Defaults to the GHIDRA_INSTALL_DIR environment variable)
:return: The PhyidraLauncher used to start the JVM
"""
from pyhidra.launcher import HeadlessPyhidraLauncher
launcher = HeadlessPyhidraLauncher(verbose=verbose, install_dir=install_dir)
from pyghidra.launcher import HeadlessPyGhidraLauncher
launcher = HeadlessPyGhidraLauncher(verbose=verbose, install_dir=install_dir)
launcher.start()
return launcher
def started() -> bool:
"""
Whether the PyhidraLauncher has already started.
Whether the PyGhidraLauncher has already started.
"""
from pyhidra.launcher import PyhidraLauncher
return PyhidraLauncher.has_launched()
from pyghidra.launcher import PyGhidraLauncher
return PyGhidraLauncher.has_launched()
def _get_language(id: str) -> "Language":
@ -137,7 +137,7 @@ def _setup_project(
def _setup_script(project: "GhidraProject", program: "Program"):
from pyhidra.script import PyGhidraScript
from pyghidra.script import PyGhidraScript
from ghidra.app.script import GhidraState
from ghidra.program.util import ProgramLocation
from ghidra.util.task import TaskMonitor
@ -205,10 +205,10 @@ def open_program(
:raises TypeError: If the provided loader does not implement `ghidra.app.util.opinion.Loader`.
"""
from pyhidra.launcher import PyhidraLauncher, HeadlessPyhidraLauncher
from pyghidra.launcher import PyGhidraLauncher, HeadlessPyGhidraLauncher
if not PyhidraLauncher.has_launched():
HeadlessPyhidraLauncher().start()
if not PyGhidraLauncher.has_launched():
HeadlessPyGhidraLauncher().start()
from ghidra.app.script import GhidraScriptUtil
from ghidra.program.flatapi import FlatProgramAPI
@ -273,10 +273,10 @@ def _flat_api(
:raises ValueError: If the provided language, compiler or loader is invalid.
:raises TypeError: If the provided loader does not implement `ghidra.app.util.opinion.Loader`.
"""
from pyhidra.launcher import PyhidraLauncher, HeadlessPyhidraLauncher
from pyghidra.launcher import PyGhidraLauncher, HeadlessPyGhidraLauncher
if not PyhidraLauncher.has_launched():
HeadlessPyhidraLauncher(verbose=verbose, install_dir=install_dir).start()
if not PyGhidraLauncher.has_launched():
HeadlessPyGhidraLauncher(verbose=verbose, install_dir=install_dir).start()
project, program = None, None
if binary_path or project_location:

View File

@ -4,10 +4,10 @@ from pathlib import Path
import sys
import threading
from .launcher import PyhidraLauncher, _run_mac_app
from .launcher import PyGhidraLauncher, _run_mac_app
class GhidraLauncher(PyhidraLauncher):
class GhidraLauncher(PyGhidraLauncher):
def __init__(self, verbose=False, class_name=str, gui=False, *, install_dir: Path = None):
super().__init__(verbose=verbose, install_dir=install_dir)

View File

@ -50,14 +50,14 @@ class _Helper:
self.msg += " # Perform headless processing\n"
self.msg += " headless.processLocal(...)\n\n"
else:
# PyhidraPlugin scenario
# PyGhidraPlugin scenario
self.msg = "Press 'F1' for usage instructions"
def __call__(self, param=None):
def get_class_and_method(param):
if param is None and not SystemUtilities.isInHeadlessMode():
# Enable help() in PyhidraPlugin scenario to show help for GhidraScript
# Enable help() in PyGhidraPlugin scenario to show help for GhidraScript
return "ghidra.app.script.GhidraScript", None
class_name = None
method_name = None

View File

@ -8,7 +8,7 @@ import traceback
from typing import List, NoReturn
import warnings
import pyhidra
import pyghidra
class _GuiOutput(io.StringIO):
@ -44,7 +44,7 @@ def _gui_mac() -> NoReturn:
path = Path(sys.base_exec_prefix) / "Resources/Python.app/Contents/MacOS/Python"
if path.exists():
# the python launcher app will correctly start the venv if sys.executable is in a venv
argv = [sys.executable, "-m", "pyhidra", "-g"]
argv = [sys.executable, "-m", "pyghidra", "-g"]
if install_dir is not None:
argv += ["--install-dir", str(install_dir)]
actions = ((os.POSIX_SPAWN_CLOSE, 0), (os.POSIX_SPAWN_CLOSE, 1), (os.POSIX_SPAWN_CLOSE, 2))
@ -55,7 +55,7 @@ def _gui_mac() -> NoReturn:
def _parse_args():
parser = _GuiArgumentParser(prog="pyhidraw")
parser = _GuiArgumentParser(prog="pyghidraw")
parser.add_argument(
"--install-dir",
type=Path,
@ -133,7 +133,7 @@ def gui(install_dir: Path = None, vm_args: List[str] = None):
(Defaults to the GHIDRA_INSTALL_DIR environment variable)
:param vm_args: Additional vm arguments to be passed ot the JVM.
"""
launcher = pyhidra.GuiPyhidraLauncher(install_dir=install_dir)
launcher = pyghidra.GuiPyGhidraLauncher(install_dir=install_dir)
if vm_args:
launcher.vm_args += vm_args
launcher.start()
@ -141,8 +141,8 @@ def gui(install_dir: Path = None, vm_args: List[str] = None):
def get_current_interpreter():
warnings.warn(
"get_current_interpreter has been moved. Please use pyhidra.get_current_interpreter",
"get_current_interpreter has been moved. Please use pyghidra.get_current_interpreter",
DeprecationWarning
)
return pyhidra.get_current_interpreter()
return pyghidra.get_current_interpreter()

View File

@ -9,8 +9,8 @@ import types
from code import InteractiveConsole
from ghidra.framework import Application
from ghidra.pyhidra import PyhidraScriptProvider, PyhidraPlugin
from ghidra.pyhidra.interpreter import PyhidraConsole
from ghidra.pyghidra import PyGhidraScriptProvider, PyGhidraPlugin
from ghidra.pyghidra.interpreter import PyGhidraConsole
from java.io import BufferedReader, InputStreamReader
from java.lang import String
from java.lang import Thread as JThread
@ -18,8 +18,8 @@ from java.util import Collections
from java.util.function import Consumer
from jpype import JClass, JImplements, JOverride
from pyhidra.internal.plugin.completions import PythonCodeCompleter
from pyhidra.script import PyGhidraScript
from pyghidra.internal.plugin.completions import PythonCodeCompleter
from pyghidra.script import PyGhidraScript
logger = logging.getLogger(__name__)
@ -125,15 +125,15 @@ class ConsoleState(enum.Enum):
RESET = enum.auto()
@JImplements(PyhidraConsole)
@JImplements(PyGhidraConsole)
class PyConsole(InteractiveConsole):
"""
Pyhidra Interactive Console
PyGhidra Interactive Console
"""
_WORD_PATTERN = re.compile(r".*?([\w\.]+)\Z") # get the last word, including '.', from the right
def __init__(self, py_plugin: PyhidraPlugin):
def __init__(self, py_plugin: PyGhidraPlugin):
super().__init__(locals=PyGhidraScript(py_plugin.script))
appVersion = Application.getApplicationVersion()
appName = Application.getApplicationReleaseName()
@ -314,11 +314,11 @@ class PyConsole(InteractiveConsole):
return Collections.emptyList()
def _init_plugin(plugin: PyhidraPlugin):
def _init_plugin(plugin: PyGhidraPlugin):
console = PyConsole(plugin)
plugin.interpreter.init(console)
def setup_plugin():
PyhidraPlugin.setInitializer(Consumer @ _init_plugin)
PyhidraScriptProvider.setScriptRunner(Consumer @ _run_script)
PyGhidraPlugin.setInitializer(Consumer @ _init_plugin)
PyGhidraScriptProvider.setScriptRunner(Consumer @ _run_script)

View File

@ -76,7 +76,7 @@ def _load_entry_points(group: str, *args):
logger.error(f"Failed to run {group} entry point {name} with error: {e}")
class _PyhidraImportLoader:
class _PyGhidraImportLoader:
""" (internal) Finder hook for importlib to handle Python mod conflicts. """
def find_spec(self, name, path, target=None):
@ -101,7 +101,7 @@ def _plugin_lock():
File lock for processing plugins
"""
from java.io import RandomAccessFile
path = Path(tempfile.gettempdir()) / "pyhidra_plugin_lock"
path = Path(tempfile.gettempdir()) / "pyghidra_plugin_lock"
try:
# Python doesn't have a file lock except for unix systems
# so use the one available in Java instead of adding on
@ -117,19 +117,19 @@ def _plugin_lock():
path.unlink()
except:
# if it fails it's ok
# another pyhidra process has the lock
# another pyghidra process has the lock
# it will be removed by said process when done
pass
class PyhidraLauncher:
class PyGhidraLauncher:
"""
Base pyhidra launcher
Base pyghidra launcher
"""
def __init__(self, verbose=False, *, install_dir: Path = None):
"""
Initializes a new `PyhidraLauncher`.
Initializes a new `PyGhidraLauncher`.
:param verbose: True to enable verbose output when starting Ghidra.
:param install_dir: Ghidra installation directory.
@ -296,10 +296,10 @@ class PyhidraLauncher:
# dev mode
return install_dir
path = install_dir / "Ghidra" / "Features" / "Pyhidra" / "lib" / "Pyhidra.jar"
path = install_dir / "Ghidra" / "Features" / "PyGhidra" / "lib" / "PyGhidra.jar"
if not path.exists():
msg = "The Ghidra installation does not contain the Pyhidra module\n" + \
msg = "The Ghidra installation does not contain the PyGhidra module\n" + \
f"{path} does not exist"
cls._report_fatal_error("Incorrect Ghidra installation directory", msg, ValueError(msg))
@ -344,12 +344,12 @@ class PyhidraLauncher:
Run setup entry points, start the JVM and prepare ghidra imports
"""
# Before starting up, give launcher to installed entry points so they can do their thing.
_load_entry_points("pyhidra.setup", self)
_load_entry_points("pyghidra.setup", self)
# Merge classpath
jpype_kwargs['classpath'] = self.class_path + jpype_kwargs.get('classpath', [])
# force convert strings (required by pyhidra)
# force convert strings (required by pyghidra)
jpype_kwargs['convertStrings'] = True
# set the JAVA_HOME environment variable to the correct one so jpype uses it
@ -357,7 +357,7 @@ class PyhidraLauncher:
jpype_kwargs['ignoreUnrecognized'] = True
if os.getenv("PYHIDRA_DEBUG"):
if os.getenv("PYGHIDRA_DEBUG"):
debug = "-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=127.0.0.1:18001"
self.vm_args.insert(0, debug)
@ -368,7 +368,7 @@ class PyhidraLauncher:
)
# Install hook into python importlib
sys.meta_path.append(_PyhidraImportLoader())
sys.meta_path.append(_PyGhidraImportLoader())
imports.registerDomain("ghidra")
@ -384,11 +384,11 @@ class PyhidraLauncher:
# remove any installed pyhidra extension
# remove any old installed pyhidra extension
# if left in place Ghidra will fail to start with a confusing
# and unrelated error about the InterpreterConsole class not being found
# this is only needed for those using a DEV build of Ghidra
# who also have pyhidra installed.
# who also have and old version of pyhidra installed.
# however, this took an unnecessary amount of time to debug
self.uninstall_plugin("pyhidra")
@ -404,7 +404,7 @@ class PyhidraLauncher:
self._layout = GhidraLauncher.initializeGhidraEnvironment()
# import it at the end so interfaces in our java code may be implemented
from pyhidra.internal.plugin.plugin import setup_plugin
from pyghidra.internal.plugin.plugin import setup_plugin
setup_plugin()
# Add extra class paths
@ -432,7 +432,7 @@ class PyhidraLauncher:
# import properties to register the property customizer
from . import properties as _
_load_entry_points("pyhidra.pre_launch")
_load_entry_points("pyghidra.pre_launch")
def start(self, **jpype_kwargs):
"""
@ -548,9 +548,9 @@ class PyhidraLauncher:
return Application.isInitialized()
class DeferredPyhidraLauncher(PyhidraLauncher):
class DeferredPyGhidraLauncher(PyGhidraLauncher):
"""
PyhidraLauncher which allows full Ghidra initialization to be deferred.
PyGhidraLauncher which allows full Ghidra initialization to be deferred.
initialize_ghidra must be called before all Ghidra classes are fully available.
"""
@ -571,9 +571,9 @@ class DeferredPyhidraLauncher(PyhidraLauncher):
GhidraRun().launch(self._layout, self.args)
class HeadlessPyhidraLauncher(PyhidraLauncher):
class HeadlessPyGhidraLauncher(PyGhidraLauncher):
"""
Headless pyhidra launcher
Headless pyghidra launcher
"""
def _launch(self):
@ -583,7 +583,7 @@ class HeadlessPyhidraLauncher(PyhidraLauncher):
Application.initializeApplication(self._layout, config)
class _PyhidraStdOut:
class _PyGhidraStdOut:
def __init__(self, stream):
self._stream = stream
@ -615,9 +615,9 @@ class _PyhidraStdOut:
return self._stream.write(s)
class GuiPyhidraLauncher(PyhidraLauncher):
class GuiPyGhidraLauncher(PyGhidraLauncher):
"""
GUI pyhidra launcher
GUI pyghidra launcher
"""
@classmethod
@ -647,8 +647,8 @@ class GuiPyhidraLauncher(PyhidraLauncher):
appid = ctypes.c_wchar_p(self.app_info.name)
ctypes.windll.shell32.SetCurrentProcessExplicitAppUserModelID(appid)
stdout = _PyhidraStdOut(sys.stdout)
stderr = _PyhidraStdOut(sys.stderr)
stdout = _PyGhidraStdOut(sys.stdout)
stderr = _PyGhidraStdOut(sys.stderr)
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
Thread(lambda: Ghidra.main(["ghidra.GhidraRun", *self.args])).start()
is_exiting = threading.Event()

View File

@ -14,10 +14,10 @@ class _JavaObject:
if isinstance(self, jpype.JException):
# don't process any exceptions
return
exposer = jpype.JClass("ghidra.pyhidra.PythonFieldExposer")
exposer = jpype.JClass("ghidra.pyghidra.PythonFieldExposer")
if exposer.class_.isAssignableFrom(self.class_):
return
utils = jpype.JClass("ghidra.pyhidra.property.PropertyUtils")
utils = jpype.JClass("ghidra.pyghidra.property.PropertyUtils")
for prop in utils.getProperties(self.class_):
field = prop.field
if keyword.iskeyword(field):

View File

@ -12,7 +12,7 @@ from jpype import JClass, JImplementationFor
from typing import List
from pyhidra import debug_callback
from pyghidra import debug_callback
_NO_ATTRIBUTE = object()
@ -70,12 +70,12 @@ class _JavaProperty(property):
#pylint: disable=too-few-public-methods
@JImplementationFor("ghidra.pyhidra.PythonFieldExposer")
@JImplementationFor("ghidra.pyghidra.PythonFieldExposer")
class _PythonFieldExposer:
#pylint: disable=no-member
def __jclass_init__(self):
exposer = JClass("ghidra.pyhidra.PythonFieldExposer")
exposer = JClass("ghidra.pyghidra.PythonFieldExposer")
if self.class_ == exposer:
return
try:
@ -135,8 +135,8 @@ class PyGhidraScript(dict):
def __init__(self, jobj=None):
super().__init__()
if jobj is None:
from ghidra.pyhidra import PyhidraScriptProvider
jobj = PyhidraScriptProvider().getScriptInstance(None, None)
from ghidra.pyghidra import PyGhidraScriptProvider
jobj = PyGhidraScriptProvider().getScriptInstance(None, None)
self._script = jobj
global _headless_interpreter
@ -258,7 +258,7 @@ class PyGhidraScript(dict):
def get_current_interpreter():
"""
Gets the underlying GhidraScript for the focused Pyhidra InteractiveConsole.
Gets the underlying GhidraScript for the focused PyGhidra InteractiveConsole.
This will always return None unless it is being access from a function
called from within the interactive console.
@ -274,8 +274,8 @@ def get_current_interpreter():
if SystemUtilities.isInHeadlessMode():
if _headless_interpreter is None:
# one hasn't been created yet so make one now
PyhidraScriptProvider = JClass("ghidra.pyhidra.PyhidraScriptProvider")
_headless_interpreter = PyhidraScriptProvider.PyhidraHeadlessScript()
PyGhidraScriptProvider = JClass("ghidra.pyghidra.PyGhidraScriptProvider")
_headless_interpreter = PyGhidraScriptProvider.PyGhidraHeadlessScript()
return _headless_interpreter
project = AppInfo.getActiveProject()
@ -293,7 +293,7 @@ def get_current_interpreter():
return None
for plugin in tool.getManagedPlugins():
if plugin.name == 'PyhidraPlugin':
if plugin.name == 'PyGhidraPlugin':
return plugin.script
except ImportError:

View File

@ -1,4 +1,4 @@
package ghidra.pyhidra.test;
package ghidra.pyghidra.test;
/**
* This is a bad class that will fail to compile.

View File

@ -1,9 +1,9 @@
package ghidra.pyhidra.test;
package ghidra.pyghidra.test;
import ghidra.app.util.recognizer.Recognizer;
/**
* Simple ExtensionPoint class for pyhidra plugin test.
* Simple ExtensionPoint class for PyGhidra plugin test.
*
* This can be any ExtensionPoint. Recognizer was chosen here
* because it has a small number of methods and hasn't changed in a long time.

View File

@ -2,9 +2,9 @@ from pathlib import Path
from typing import List, Tuple
import pytest
from pyhidra.__main__ import _get_parser, PyhidraArgs
from pyhidra.ghidra_launch import ParsedArgs
from pyhidra.ghidra_launch import get_parser as get_ghidra_launcher_parser
from pyghidra.__main__ import _get_parser, PyGhidraArgs
from pyghidra.ghidra_launch import ParsedArgs
from pyghidra.ghidra_launch import get_parser as get_ghidra_launcher_parser
PROJECT_NAME = "stub_name"
@ -20,9 +20,9 @@ def exe_file(shared_datadir: Path):
class TestArgParser:
def parse(self, *args) -> PyhidraArgs:
def parse(self, *args) -> PyGhidraArgs:
parser = _get_parser()
parser_args = PyhidraArgs(parser)
parser_args = PyGhidraArgs(parser)
args = [str(arg) for arg in args]
parser.parse_args(args, namespace=parser_args)
return parser_args

View File

@ -4,7 +4,7 @@ import textwrap
import importlib
import sys
import jpype
import pyhidra
import pyghidra
import pytest
EXE_NAME = "strings.exe"
@ -23,7 +23,7 @@ def class_file(shared_datadir: Path):
def test_invalid_jpype_keyword_arg():
assert not jpype.isJVMStarted()
launcher = pyhidra.launcher.HeadlessPyhidraLauncher()
launcher = pyghidra.launcher.HeadlessPyGhidraLauncher()
with pytest.raises(TypeError) as ex:
launcher.start(someBogusKeywordArg=True)
assert "startJVM() got an unexpected keyword argument 'someBogusKeywordArg'" in str(ex.value)
@ -32,7 +32,7 @@ def test_invalid_jpype_keyword_arg():
def test_invalid_vm_arg_succeed():
assert not jpype.isJVMStarted()
launcher = pyhidra.launcher.HeadlessPyhidraLauncher()
launcher = pyghidra.launcher.HeadlessPyGhidraLauncher()
launcher.add_vmargs('-XX:SomeBogusJvmArg')
launcher.start(ignoreUnrecognized=True)
@ -40,7 +40,7 @@ def test_invalid_vm_arg_succeed():
def test_run_script(capsys, shared_datadir: Path):
strings_exe = shared_datadir / EXE_NAME
script_path = shared_datadir / "example_script.py"
pyhidra.run_script(strings_exe, script_path, script_args=["my", "--commands"], analyze=False)
pyghidra.run_script(strings_exe, script_path, script_args=["my", "--commands"], analyze=False)
captured = capsys.readouterr()
assert captured.err == ""
@ -56,7 +56,7 @@ def test_run_script(capsys, shared_datadir: Path):
def test_open_program(shared_datadir: Path):
strings_exe = shared_datadir / EXE_NAME
with pyhidra.open_program(strings_exe, analyze=False, language=TEST_LANGUAGE, compiler=TEST_COMPILER) as flat_api:
with pyghidra.open_program(strings_exe, analyze=False, language=TEST_LANGUAGE, compiler=TEST_COMPILER) as flat_api:
assert flat_api.currentProgram.name == strings_exe.name
assert flat_api.getCurrentProgram().listing
assert flat_api.getCurrentProgram().changeable
@ -65,7 +65,7 @@ def test_open_program(shared_datadir: Path):
def test_bad_language(shared_datadir: Path):
strings_exe = shared_datadir / EXE_NAME
with pytest.raises(ValueError):
with pyhidra.open_program(
with pyghidra.open_program(
strings_exe,
analyze=False,
language="invalid"
@ -76,7 +76,7 @@ def test_bad_language(shared_datadir: Path):
def test_bad_compiler(shared_datadir: Path):
strings_exe = shared_datadir / EXE_NAME
with pytest.raises(ValueError):
with pyhidra.open_program(
with pyghidra.open_program(
strings_exe,
analyze=False,
language=TEST_LANGUAGE,
@ -87,19 +87,19 @@ def test_bad_compiler(shared_datadir: Path):
def test_no_compiler(shared_datadir: Path):
strings_exe = shared_datadir / EXE_NAME
with pyhidra.open_program(strings_exe, analyze=False, language=TEST_LANGUAGE) as flat_api:
with pyghidra.open_program(strings_exe, analyze=False, language=TEST_LANGUAGE) as flat_api:
pass
def test_no_language_with_compiler(shared_datadir: Path):
strings_exe = shared_datadir / EXE_NAME
with pyhidra.open_program(strings_exe, analyze=False, compiler=TEST_COMPILER) as flat_api:
with pyghidra.open_program(strings_exe, analyze=False, compiler=TEST_COMPILER) as flat_api:
pass
def test_loader(shared_datadir: Path):
strings_exe = shared_datadir / EXE_NAME
with pyhidra.open_program(
with pyghidra.open_program(
strings_exe,
analyze=False,
language="DATA:LE:64:default",
@ -112,7 +112,7 @@ def test_loader(shared_datadir: Path):
def test_invalid_loader(shared_datadir: Path):
strings_exe = shared_datadir / EXE_NAME
with pytest.raises(ValueError):
with pyhidra.open_program(
with pyghidra.open_program(
strings_exe,
analyze=False,
language="DATA:LE:64:default",
@ -125,7 +125,7 @@ def test_invalid_loader(shared_datadir: Path):
def test_invalid_loader_type(shared_datadir: Path):
strings_exe = shared_datadir / EXE_NAME
with pytest.raises(TypeError):
with pyhidra.open_program(
with pyghidra.open_program(
strings_exe,
analyze=False,
language="DATA:LE:64:default",
@ -136,7 +136,7 @@ def test_invalid_loader_type(shared_datadir: Path):
def test_no_project(capsys, shared_datadir: Path):
pyhidra.run_script(None, shared_datadir / "projectless_script.py")
pyghidra.run_script(None, shared_datadir / "projectless_script.py")
captured = capsys.readouterr()
assert captured.out.rstrip() == "projectless_script executed successfully"
@ -145,14 +145,14 @@ def test_no_program(capsys, shared_datadir: Path):
script_path = shared_datadir / "programless_script.py"
project_path = shared_datadir / "programless_ghidra"
pyhidra.run_script(None, script_path, project_path, "programless")
pyghidra.run_script(None, script_path, project_path, "programless")
captured = capsys.readouterr()
assert captured.out.rstrip() == "programless_script executed successfully"
def test_import_script(capsys, shared_datadir: Path):
script_path = shared_datadir / "import_test_script.py"
pyhidra.run_script(None, script_path)
pyghidra.run_script(None, script_path)
captured = capsys.readouterr()
assert captured.out.rstrip() == "imported successfully"
@ -176,16 +176,16 @@ def test_import_ghidra_base_java_packages():
def wrap_mod(mod):
return mod + '_'
launcher = pyhidra.start()
launcher = pyghidra.start()
# Test to ensure _PyhidraImportLoader is last loader
assert isinstance(sys.meta_path[-1], pyhidra.launcher._PyhidraImportLoader)
# Test to ensure _PyGhidraImportLoader is last loader
assert isinstance(sys.meta_path[-1], pyghidra.launcher._PyGhidraImportLoader)
packages = get_runtime_top_level_java_packages(launcher)
assert len(packages) > 0
# Test full coverage for Java base packages (_JImportLoader or _PyhidraImportLoader)
# Test full coverage for Java base packages (_JImportLoader or _PyGhidraImportLoader)
for mod in packages:
# check spec using standard import machinery "import mod"
spec = importlib.util.find_spec(mod)
@ -195,13 +195,13 @@ def test_import_ghidra_base_java_packages():
assert spec is not None
assert isinstance(spec.loader, jpype.imports._JImportLoader) or isinstance(
spec.loader, pyhidra.launcher._PyhidraImportLoader)
spec.loader, pyghidra.launcher._PyGhidraImportLoader)
# Test all Java base packages are available with '_'
for mod in packages:
spec_ = importlib.util.find_spec(wrap_mod(mod))
assert spec_ is not None
assert isinstance(spec_.loader, pyhidra.launcher._PyhidraImportLoader)
assert isinstance(spec_.loader, pyghidra.launcher._PyGhidraImportLoader)
# Test standard import
import ghidra
@ -209,7 +209,7 @@ def test_import_ghidra_base_java_packages():
# Test import with conflict
import pdb_
assert isinstance(pdb_.__loader__, pyhidra.launcher._PyhidraImportLoader)
assert isinstance(pdb_.__loader__, pyghidra.launcher._PyGhidraImportLoader)
# Test "from" import with conflict
from pdb_ import PdbPlugin

View File

@ -5,7 +5,7 @@ from pathlib import Path
import typing
import jpype
import pyhidra
import pyghidra
import pytest
@ -13,8 +13,8 @@ import pytest
pytestmark = pytest.mark.plugin
SETUP_KEY = "pyhidra.setup"
PRE_LAUNCH_KEY = "pyhidra.pre_launch"
SETUP_KEY = "pyghidra.setup"
PRE_LAUNCH_KEY = "pyghidra.pre_launch"
NAME_KEY = "names"
@ -30,10 +30,10 @@ class PluginTest:
ran_setup = False
ran_prelaunch = False
details: pyhidra.ExtensionDetails = None
details: pyghidra.ExtensionDetails = None
def __init_subclass__(cls) -> None:
cls.details = pyhidra.ExtensionDetails(
cls.details = pyghidra.ExtensionDetails(
name=cls.__name__,
description="Test Plugin",
author=""
@ -43,7 +43,7 @@ class PluginTest:
_prelaunch = cls.prelaunch
@functools.wraps(_setup)
def setup(launcher: pyhidra.HeadlessPyhidraLauncher):
def setup(launcher: pyghidra.HeadlessPyGhidraLauncher):
_setup(launcher)
cls.ran_setup = True
@ -62,7 +62,7 @@ class PluginTest:
@classmethod
@abc.abstractmethod
def setup(cls, launcher: pyhidra.HeadlessPyhidraLauncher):
def setup(cls, launcher: pyghidra.HeadlessPyGhidraLauncher):
...
@classmethod
@ -110,7 +110,7 @@ def with_ghidra():
"""
_monkey_patch_entry_points()
try:
launcher = pyhidra.HeadlessPyhidraLauncher()
launcher = pyghidra.HeadlessPyGhidraLauncher()
launcher.start()
yield # can't yield None
finally:
@ -128,29 +128,29 @@ def with_ghidra():
class TestValidPlugin(PluginTest):
@classmethod
def setup(cls, launcher: pyhidra.HeadlessPyhidraLauncher):
def setup(cls, launcher: pyghidra.HeadlessPyGhidraLauncher):
source_path = Path(__file__).parent / "data" / "good_plugin"
launcher.install_plugin(source_path, cls.details)
@classmethod
def prelaunch(cls):
DummyTestRecognizer = jpype.JClass("ghidra.pyhidra.test.DummyTestRecognizer")
DummyTestRecognizer = jpype.JClass("ghidra.pyghidra.test.DummyTestRecognizer")
DummyTestRecognizer.preLaunchInitialized = True
@classmethod
def test_extension_point(cls):
from ghidra.app.util.recognizer import Recognizer
from ghidra.util.classfinder import ClassSearcher
DummyTestRecognizer = jpype.JClass("ghidra.pyhidra.test.DummyTestRecognizer")
DummyTestRecognizer = jpype.JClass("ghidra.pyghidra.test.DummyTestRecognizer")
assert DummyTestRecognizer in ClassSearcher.getClasses(Recognizer)
class TestBadPlugin(PluginTest):
launcher: pyhidra.HeadlessPyhidraLauncher = None
launcher: pyghidra.HeadlessPyGhidraLauncher = None
@classmethod
def setup(cls, launcher: pyhidra.HeadlessPyhidraLauncher):
def setup(cls, launcher: pyghidra.HeadlessPyGhidraLauncher):
source_path = Path(__file__).parent / "data" / "bad_plugin"
launcher.install_plugin(source_path, cls.details)
cls.launcher = launcher

View File

@ -13,11 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.pyhidra;
package ghidra.pyghidra;
import static org.junit.Assert.*;
import org.junit.*;
import org.junit.After;
import org.junit.Before;
import ghidra.app.plugin.core.osgi.BundleHost;
import ghidra.app.script.GhidraScriptUtil;
@ -28,7 +27,7 @@ import ghidra.test.TestEnv;
/**
* Tests the Python Plugin functionality.
*/
public class PyhidraPluginTest extends AbstractGhidraHeadedIntegrationTest {
public class PyGhidraPluginTest extends AbstractGhidraHeadedIntegrationTest {
private TestEnv env;
@ -37,8 +36,8 @@ public class PyhidraPluginTest extends AbstractGhidraHeadedIntegrationTest {
env = new TestEnv();
PluginTool tool = env.getTool();
GhidraScriptUtil.initialize(new BundleHost(), null);
tool.addPlugin(PyhidraPlugin.class.getName());
env.getPlugin(PyhidraPlugin.class);
tool.addPlugin(PyGhidraPlugin.class.getName());
env.getPlugin(PyGhidraPlugin.class);
}
@After

View File

@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package ghidra.pyhidra;
package ghidra.pyghidra;
import static org.junit.Assert.*;

View File

@ -1,18 +0,0 @@
package ghidra.pyhidra;
import org.junit.Test;
import ghidra.pyhidra.PythonFieldExposer.ExposedField;
import static org.junit.Assert.assertTrue;
import java.util.Map;;
public class PythonFieldExposerTest {
@Test
public void test() {
Map<String, ExposedField> fields = PythonFieldExposer.getProperties(PyhidraScriptProvider.PyhidraGhidraScript.class);
assertTrue(fields.containsKey("currentProgram"));
}
}

View File

@ -1,240 +0,0 @@
package ghidra.pyhidra.property;
import java.lang.annotation.ElementType;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
import static org.junit.Assert.assertArrayEquals;
@RunWith(Parameterized.class)
public class PropertyUtilsTest {
@Parameters(name = "{0}")
public static List<Object[]> data() {
return convertData(PropertyUtilsTest.class.getNestMembers());
}
private final Class<?> cls;
public PropertyUtilsTest(String name, Class<?> cls) {
this.cls = cls;
}
private TestResult[] getExpected() {
return Arrays.stream(cls.getAnnotationsByType(ExpectedResult.class))
.map(TestResult::new)
.toArray(TestResult[]::new);
}
@Test
public void test() {
TestResult[] expected = getExpected();
TestResult[] properties = getProperties(cls);
assertArrayEquals(expected, properties);
}
private static TestResult[] getProperties(Class<?> cls) {
return Arrays.stream(PropertyUtils.getProperties(cls))
.map(AbstractJavaProperty.class::cast)
.map(TestResult::new)
.toArray(TestResult[]::new);
}
private static List<Object[]> convertData(Class<?>[] classes) {
List<Object[]> result = new ArrayList<>(classes.length);
for (Class<?> cls : classes) {
if (cls.isRecord() || cls.isAnnotation()) {
continue;
}
result.add(new Object[] { cls.getSimpleName(), cls });
}
return result;
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Repeatable(ExpectedResults.class)
private static @interface ExpectedResult {
String field();
boolean getter();
boolean setter();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
private static @interface ExpectedResults {
ExpectedResult[] value();
}
private static record TestResult(String field, boolean getter, boolean setter) {
TestResult(AbstractJavaProperty<?> property) {
this(property.field, property.hasGetter(), property.hasValidSetter());
}
TestResult(ExpectedResult result) {
this(result.field(), result.getter(), result.setter());
}
}
@ExpectedResult(field = "length", getter = true, setter = false)
public static class TestGetter {
public int getLength() {
return 0;
}
}
@ExpectedResult(field = "length", getter = false, setter = true)
public static class TestSetter {
public void setLength(int i) {
}
}
@ExpectedResult(field = "length", getter = true, setter = true)
public static class TestProperty {
public int getLength() {
return 0;
}
public void setLength(int i) {
}
}
@ExpectedResult(field = "length", getter = true, setter = true)
public static class TestMultiSetter {
public int getLength() {
return 0;
}
public void setLength(int i) {
}
public void setLength(short s) {
}
}
@ExpectedResult(field = "length", getter = true, setter = true)
public static class TestBoxedMultiSetter {
public int getLength() {
return 0;
}
public void setLength(int i) {
}
public void setLength(Integer i) {
}
}
public static class TestMultiSetterNoGetter {
public void setLength(int i) {
}
public void setLength(short s) {
}
}
@ExpectedResult(field = "valid", getter = true, setter = false)
public static class TestIsGetter {
public boolean isValid() {
return true;
}
}
@ExpectedResult(field = "valid", getter = true, setter = true)
public static class TestIsProperty {
public boolean isValid() {
return true;
}
public void setValid(boolean valid) {
}
}
@ExpectedResult(field = "valid", getter = true, setter = false)
public static class TestIsBoxedGetter {
public Boolean isValid() {
return true;
}
}
@ExpectedResult(field = "valid", getter = true, setter = true)
public static class TestIsBoxedProperty {
public Boolean isValid() {
return true;
}
public void setValid(boolean valid) {
}
}
public static class TestBadIsGetter {
public int isValid() {
return 1;
}
}
public static class TestIsGetterName {
public boolean isvalid() {
return true;
}
}
public static class TestBadGetterName {
public int getlength() {
return 0;
}
}
public static class TestBadSetterName {
public void setlength(int i) {
}
}
public static class TestBadIsTooShortName {
public boolean i() {
return true;
}
}
public static class TestBadGetTooShortName {
public int ge() {
return 0;
}
}
public static class TestBadSetTooShortName {
public int se() {
return 0;
}
}
public static class TestBadIsNoName {
public boolean is() {
return true;
}
}
public static class TestBadGetNoName {
public int get() {
return 0;
}
}
public static class TestBadSetNoName {
public int set() {
return 0;
}
}
}

View File

@ -1,7 +1,7 @@
#!/usr/bin/env bash
#----------------------------------------
# Pyhidra launch
# PyGhidra launch
#----------------------------------------
# Resolve symbolic link if present and get the directory this script lives in.
@ -28,6 +28,6 @@ if [ ! -d "${INSTALL_DIR}/Ghidra" ]; then
INSTALL_DIR="${SCRIPT_DIR}/../../../.."
fi
PYHIDRA_LAUNCHER="${INSTALL_DIR}/Ghidra/Features/Pyhidra/pyhidraLauncher.py"
PYGHIDRA_LAUNCHER="${INSTALL_DIR}/Ghidra/Features/PyGhidra/pyghidra_launcher.py"
python3 "${PYHIDRA_LAUNCHER}" "${INSTALL_DIR}" ${DEV_ARG} ${VMARG_LIST} "$@"
python3 "${PYGHIDRA_LAUNCHER}" "${INSTALL_DIR}" ${DEV_ARG} ${VMARG_LIST} "$@"

View File

@ -1,4 +1,4 @@
:: Pyhidra launch
:: PyGhidra launch
@echo off
setlocal enabledelayedexpansion
@ -32,9 +32,9 @@ if not exist "%INSTALL_DIR%\Ghidra" (
set "INSTALL_DIR=%SCRIPT_DIR%\..\..\..\.."
)
set "PYHIDRA_LAUNCHER=%INSTALL_DIR%\Ghidra\Features\Pyhidra\pyhidraLauncher.py
set "PYGHIDRA_LAUNCHER=%INSTALL_DIR%\Ghidra\Features\PyGhidra\pyghidra_launcher.py
%PYTHON% "%PYHIDRA_LAUNCHER%" "%INSTALL_DIR%" %DEV_ARG% %VMARG_LIST% %*
%PYTHON% "%PYGHIDRA_LAUNCHER%" "%INSTALL_DIR%" %DEV_ARG% %VMARG_LIST% %*
:exit1
if not %ERRORLEVEL% == 0 (

View File

@ -53,8 +53,8 @@ final class PythonTypeStubMethod extends PythonTypeStubElement<ExecutableElement
Map.entry("java.math.BigDecimal", "decimal.Decimal")));
// FIXME: list and set aren't automatically converted to java.util.List and java.util.Set :(
// if wanted they could be setup to be converted automatically by pyhidra
// however, when passed as a parameter and modified, the original underlyng python container
// if wanted they could be setup to be converted automatically by PyGhidra
// however, when passed as a parameter and modified, the original underlying python container
// wouldn't be modified. To make it work as expected, a python implementation for
// java.util.List and java.util.Set would need to be created using jpype.JImplements,
// that would wrap the list/set before passing it to Java instead of copying the contents

View File

@ -40,7 +40,7 @@ future releases.
<li><a href="#RunServer">Ghidra Server</a></li>
<li><a href="#RunHeadless">Headless (Batch) Mode</a></li>
<li><a href="#RunJar">Single Jar Mode</a></li>
<li><a href="#RunPyhidra">Pyhidra</a></li>
<li><a href="#RunPyGhidra">PyGhidra</a></li>
</ul>
<li><a href="#Extensions">Extensions</a></li>
<ul>
@ -102,7 +102,7 @@ Ghidra team if you have a specific need.</p></blockquote>
<li>Python3 (3.9 to 3.12)</li>
<ul>
<li>Python 3.7 to 3.12 for <a href="#DebuggerPython">Debugger support</a></li>
<li>Python 3.9 to 3.12 for <a href="#RunPyhidra">Pyhidra support</a></li>
<li>Python 3.9 to 3.12 for <a href="#RunPyGhidra">PyGhidra support</a></li>
<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
repository be used to install a suitable version of Python.</li>
@ -445,8 +445,8 @@ another Java application.</p>
<p>A single ghidra.jar file can be created using the
<i>&lt;GhidraInstallDir&gt;</i>/support/buildGhidraJar script.</p>
<h3><a name="RunPyhidra"></a>Pyhidra Mode</h3>
<p>Ghidra has integrated the the popular Pyhidra extension to enable native CPython 3 support out of
<h3><a name="RunPyGhidra"></a>PyGhidra Mode</h3>
<p>Ghidra has integrated the the popular PyGhidra extension to enable native CPython 3 support out of
the box. To enable this support, Ghidra must be launched from a Python environment using special
launch scripts.</p>
<ol>
@ -454,20 +454,20 @@ launch scripts.</p>
Navigate to <i>&lt;GhidraInstallDir&gt;</i>/support/
</li>
<li>
<p>Run <i>pyhidraRun.bat</i> (Windows) or <i>pyhidraRun</i> (Linux or macOS)</p>
<p>If the <b>pyhidra</b> Python module has not yet been installed, the script will offer to
<p>Run <i>pyghidraRun.bat</i> (Windows) or <i>pyghidraRun</i> (Linux or macOS)</p>
<p>If the <b>pyghidra</b> Python module has not yet been installed, the script will offer to
install it for you, along with its dependencies. If you prefer to install it manually, execute:
<pre>python3 -m pip install --no-index -f <i>&lt;GhidraInstallDir&gt;</i>/Ghidra/Features/Pyhidra/pypkg/dist pyhidra</pre>
<b>NOTE: </b>You may also install and run Pyhidra from within a
<pre>python3 -m pip install --no-index -f <i>&lt;GhidraInstallDir&gt;</i>/Ghidra/Features/PyGhidra/pypkg/dist pyghidra</pre>
<b>NOTE: </b>You may also install and run PyGhidra from within a
<a href="https://docs.python.org/3/tutorial/venv.html">virtual environment</a> if you desire.
<p>If Ghidra failed to launch, see the <a href="#Troubleshooting">Troubleshooting</a> section.
</p>
</li>
</ol>
<p>Once Pyhidra has been installed, you are free to use it like any other Python module. You may
import it from other Python scripts, or launch Pyhidra using the <i>pyhidra</i> or <i>pyhidraw</i>
commands. For more information on using Pyhidra, see the
<i>&lt;GhidraInstallDir&gt;</i>/Ghidra/Features/Pyhidra/Pyhidra_README.html file.</p>
<p>Once PyGhidra has been installed, you are free to use it like any other Python module. You may
import it from other Python scripts, or launch PyGhidra using the <i>pyghidra</i> or <i>pyghidraw</i>
commands. For more information on using PyGhidra, see the
<i>&lt;GhidraInstallDir&gt;</i>/Ghidra/Features/PyGhidra/PyGhidra_README.html file.</p>
<p>(<a href="#top">Back to Top</a>)</p>

View File

@ -182,7 +182,7 @@ ext.deps = [
name: "setuptools-68.0.0-py3-none-any.whl",
url: "https://files.pythonhosted.org/packages/c7/42/be1c7bbdd83e1bfb160c94b9cafd8e25efc7400346cf7ccdbdb452c467fa/setuptools-68.0.0-py3-none-any.whl",
sha256: "11e52c67415a381d10d6b462ced9cfb97066179f0e871399e006c4ab101fc85f",
destination: [file("${DEPS_DIR}/Debugger-rmi-trace/"), file("${DEPS_DIR}/Pyhidra/")]
destination: [file("${DEPS_DIR}/Debugger-rmi-trace/"), file("${DEPS_DIR}/PyGhidra/")]
],
[
name: "wheel-0.37.1-py2.py3-none-any.whl",
@ -218,79 +218,79 @@ ext.deps = [
name: "JPype1-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
url: "https://files.pythonhosted.org/packages/5d/cf/7b89469bcede4b2fd69c2db7d1d61e8759393cfeec46f7b0c84f5006a691/JPype1-1.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
sha256: "f7aa1469d75f9b310f709b61bb2faa4cef4cbd4d670531ad1d1bb53e29cfda05",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0-cp39-cp39-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/b9/fd/d38a8e401b089adce04c48021ddcb366891d1932db2f7653054feb470ae6/JPype1-1.5.0-cp39-cp39-win_amd64.whl",
sha256: "6bfdc101c56cab0b6b16e974fd8cbb0b3f7f14178286b8b55413c5d82d5f2bea",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0-cp310-cp310-macosx_10_9_universal2.whl",
url: "https://files.pythonhosted.org/packages/84/9c/80d5edf6d610f82d0658b6402cdf3f8cdd6a7d4f36afb2149da90e0cad47/JPype1-1.5.0-cp310-cp310-macosx_10_9_universal2.whl",
sha256: "7b6b1af3f9e0033080e3532c2686a224cd14706f36c14ef36160a2a1db751a17",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
url: "https://files.pythonhosted.org/packages/74/98/d6517002355b0585d0e66f7b0283c7f6e2271c898a886e1ebac09836b100/JPype1-1.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
sha256: "a02b2f05621c119d35f4acc501b4261eeb48a4af7cc13d9afc2e9eb316c4bd29",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0-cp310-cp310-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/da/5f/253c1c1dba6f7f457b6c3aa2ea9c517287d49764e0ee1042d5818c36e781/JPype1-1.5.0-cp310-cp310-win_amd64.whl",
sha256: "0b40c76e075d4fed2c83340bb30b7b95bbc396fd370c564c6b608faab00ea4ef",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0-cp311-cp311-macosx_10_9_universal2.whl",
url: "https://files.pythonhosted.org/packages/98/37/0049866cbfecb879b46d8e9f9b70944624ab17152a282ad5cf60909054ec/JPype1-1.5.0-cp311-cp311-macosx_10_9_universal2.whl",
sha256: "85a31b30b482eaf788b21af421e0750aa0be7758307314178143a76632b0ad04",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
url: "https://files.pythonhosted.org/packages/17/1e/7728ae8fb41e8fbf3a7309f8936d07b0b1622f2860733df0e7ec30b1ce76/JPype1-1.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
sha256: "5ef976e0f3b2e9604469f449f30bb2031941a159a0637f4c16adb2c5076f3e81",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0-cp311-cp311-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/1f/19/144f3a767b563ba5c6d4aa534ea1f3fad9a5067c3917df4458a6e1afe0ef/JPype1-1.5.0-cp311-cp311-win_amd64.whl",
sha256: "2bc987205ff8d2d8e36dfbef05430e0638e85d4fee1166ba58ebfa6f7a67cdf8",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0-cp312-cp312-macosx_10_9_universal2.whl",
url: "https://files.pythonhosted.org/packages/30/0d/9ac6f0e59427fc5ebf4547c2fdbb38e347b46c2dc20b430490236d037ed8/JPype1-1.5.0-cp312-cp312-macosx_10_9_universal2.whl",
sha256: "8714bfaf09d6877160bc7ac97812016ccb09f6d7ba5ea2a9f519178aefcca93f",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
url: "https://files.pythonhosted.org/packages/7d/ed/549766039d17550da6e3fa59ed776a021b400324d7766358d3b6e33d8b28/JPype1-1.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl",
sha256: "8649b526eccb4047881ad60bdb1974eb71a09cdb7f8bda17c96fdc0f9a3f2d1e",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0-cp312-cp312-win_amd64.whl",
url: "https://files.pythonhosted.org/packages/20/47/9606af72e21703e5fca5e29e5bd5e345506977b6ba492c549648adef47ef/JPype1-1.5.0-cp312-cp312-win_amd64.whl",
sha256: "9aafc00b00bf8c1b624081e5d4ab87f7752e6c7ee6a141cfc332250b05c6d42f",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "JPype1-1.5.0.tar.gz",
url: "https://files.pythonhosted.org/packages/25/42/8ca50a0e27e3053829545829e7bcba071cbfa4d5d8fd7fc5d1d988f325b1/JPype1-1.5.0.tar.gz",
sha256: "425a6e1966afdd5848b60c2688bcaeb7e40ba504a686f1114589668e0631e878",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
],
[
name: "packaging-23.2-py3-none-any.whl",
url: "https://files.pythonhosted.org/packages/ec/1a/610693ac4ee14fcdf2d9bf3c493370e4f2ef7ae2e19217d7a237ff42367d/packaging-23.2-py3-none-any.whl",
sha256: "8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7",
destination: file("${DEPS_DIR}/Pyhidra/")
destination: file("${DEPS_DIR}/PyGhidra/")
]
]