mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
GP-4706: GhidraScripts can now use @runtime to specify which GhidraScriptProvider to use when multiple expect the same script file extension (e.g., '.py')
This commit is contained in:
parent
5ab72bf4f2
commit
420eb767e8
38 changed files with 438 additions and 93 deletions
|
@ -16,6 +16,7 @@
|
||||||
# Generate the BSim signature for the function at the current address,
|
# Generate the BSim signature for the function at the current address,
|
||||||
# then dump the signature hashes and debug information to the console
|
# then dump the signature hashes and debug information to the console
|
||||||
# @category: BSim.python
|
# @category: BSim.python
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
import ghidra.app.decompiler.DecompInterface as DecompInterface
|
import ghidra.app.decompiler.DecompInterface as DecompInterface
|
||||||
import ghidra.app.decompiler.DecompileOptions as DecompileOptions
|
import ghidra.app.decompiler.DecompileOptions as DecompileOptions
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
# Generate the BSim signature for the function at the current address, then dump the
|
# Generate the BSim signature for the function at the current address, then dump the
|
||||||
# signature hashes to the console
|
# signature hashes to the console
|
||||||
# @category: BSim.python
|
# @category: BSim.python
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
import ghidra.app.decompiler.DecompInterface as DecompInterface
|
import ghidra.app.decompiler.DecompInterface as DecompInterface
|
||||||
import ghidra.app.decompiler.DecompileOptions as DecompileOptions
|
import ghidra.app.decompiler.DecompileOptions as DecompileOptions
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
##
|
##
|
||||||
# Example of how to perform an overview query in a script
|
# Example of how to perform an overview query in a script
|
||||||
# @category BSim.python
|
# @category BSim.python
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
import ghidra.features.bsim.query.facade.SFOverviewInfo as SFOverviewInfo
|
import ghidra.features.bsim.query.facade.SFOverviewInfo as SFOverviewInfo
|
||||||
import ghidra.features.bsim.query.facade.SimilarFunctionQueryService as SimilarFunctionQueryService
|
import ghidra.features.bsim.query.facade.SimilarFunctionQueryService as SimilarFunctionQueryService
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
##
|
##
|
||||||
#Generate signatures for every function in the current program and write them to an XML file in a user-specified directory
|
#Generate signatures for every function in the current program and write them to an XML file in a user-specified directory
|
||||||
#@category BSim.python
|
#@category BSim.python
|
||||||
|
#@runtime Jython
|
||||||
|
|
||||||
import java.lang.System as System
|
import java.lang.System as System
|
||||||
import java.io.File as File
|
import java.io.File as File
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
##
|
##
|
||||||
# Example of performing a BSim query on a single function
|
# Example of performing a BSim query on a single function
|
||||||
# @category BSim.python
|
# @category BSim.python
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
import ghidra.features.bsim.query.BSimClientFactory as BSimClientFactory
|
import ghidra.features.bsim.query.BSimClientFactory as BSimClientFactory
|
||||||
import ghidra.features.bsim.query.GenSignatures as GenSignatures
|
import ghidra.features.bsim.query.GenSignatures as GenSignatures
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#Print the file offset as a Ghidra comment at the memory address in the Ghidra Listing
|
#Print the file offset as a Ghidra comment at the memory address in the Ghidra Listing
|
||||||
#If multiple addresses are located, then print the addresses to the console (do not set a Ghidra comment)
|
#If multiple addresses are located, then print the addresses to the console (do not set a Ghidra comment)
|
||||||
# @category Examples
|
# @category Examples
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
import sys
|
import sys
|
||||||
from ghidra.program.model.address import Address
|
from ghidra.program.model.address import Address
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
##
|
##
|
||||||
#Given a function, find all strings used within all called funtions.
|
#Given a function, find all strings used within all called funtions.
|
||||||
# @category: Strings
|
# @category: Strings
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
# Handles only functions, not subroutines, as of now. Hopefully this will change later
|
# Handles only functions, not subroutines, as of now. Hopefully this will change later
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
# generate the original bytes of the imported file and asks the user to provide a filename to store the bytes. YARA then runs on that file.
|
# generate the original bytes of the imported file and asks the user to provide a filename to store the bytes. YARA then runs on that file.
|
||||||
|
|
||||||
#@category Memory.YARA
|
#@category Memory.YARA
|
||||||
|
#@runtime Jython
|
||||||
|
|
||||||
import os.path
|
import os.path
|
||||||
import sys
|
import sys
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
##
|
##
|
||||||
# Sets up IOPORT IN/OUT references for the Program
|
# Sets up IOPORT IN/OUT references for the Program
|
||||||
#@category Instructions
|
#@category Instructions
|
||||||
|
#@runtime Jython
|
||||||
# Before running this script, you should have created an OVERLAY memory
|
# Before running this script, you should have created an OVERLAY memory
|
||||||
# space called IOMEM, starting at address 0, size 0x10000.
|
# space called IOMEM, starting at address 0, size 0x10000.
|
||||||
#
|
#
|
||||||
|
|
|
@ -127,7 +127,7 @@
|
||||||
</P>
|
</P>
|
||||||
|
|
||||||
<BLOCKQUOTE>
|
<BLOCKQUOTE>
|
||||||
<P>The tag indicates the top-level menu path. Path levels are delimited using the "."
|
<P>This tag indicates the top-level menu path. Path levels are delimited using the "."
|
||||||
character. A mnemonic can be defined by adding an ampersand ("&") in front of the mnemonic
|
character. A mnemonic can be defined by adding an ampersand ("&") in front of the mnemonic
|
||||||
key. Ampersands can be escaped by adding another ampersand ("&&"). </P>
|
key. Ampersands can be escaped by adding another ampersand ("&&"). </P>
|
||||||
|
|
||||||
|
@ -152,6 +152,19 @@
|
||||||
For example, <TT>"@toolbar myScriptImage.gif"</TT>.<BR>
|
For example, <TT>"@toolbar myScriptImage.gif"</TT>.<BR>
|
||||||
</P>
|
</P>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
<P><CODE><B>@runtime</B></CODE></P>
|
||||||
|
|
||||||
|
<BLOCKQUOTE>
|
||||||
|
<P>This tag indicates which Ghidra script runtime environment is required to execute the
|
||||||
|
script. It allows for greater control when more than one Ghidra script runtime environment
|
||||||
|
uses the same script file extension. If left unspecified, the first Ghidra script runtime
|
||||||
|
environment that matches the script's extension will be used.<BR>
|
||||||
|
<BR>
|
||||||
|
For example, specify <TT>"@runtime Jython"</TT> if the script is targetted for a Jython 2
|
||||||
|
runtime environment rather than a Python 3 runtime environment.
|
||||||
|
</P>
|
||||||
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
</BLOCKQUOTE>
|
</BLOCKQUOTE>
|
||||||
|
|
||||||
|
|
|
@ -370,7 +370,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
}
|
}
|
||||||
|
|
||||||
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(script);
|
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(script);
|
||||||
SaveDialog dialog = new SaveDialog(getComponent(), "Rename Script", this, script,
|
SaveDialog dialog = new SaveDialog(getComponent(), "Rename Script", this, script, provider,
|
||||||
actionManager.getRenameHelpLocation());
|
actionManager.getRenameHelpLocation());
|
||||||
if (dialog.isCancelled()) {
|
if (dialog.isCancelled()) {
|
||||||
plugin.getTool().setStatusInfo("User cancelled rename.");
|
plugin.getTool().setStatusInfo("User cancelled rename.");
|
||||||
|
@ -580,7 +580,7 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
ResourceFile newFile = GhidraScriptUtil.createNewScript(provider,
|
ResourceFile newFile = GhidraScriptUtil.createNewScript(provider,
|
||||||
new ResourceFile(userScriptsDir), getScriptDirectories());
|
new ResourceFile(userScriptsDir), getScriptDirectories());
|
||||||
SaveDialog dialog = new SaveNewScriptDialog(getComponent(), "New Script", this, newFile,
|
SaveDialog dialog = new SaveNewScriptDialog(getComponent(), "New Script", this, newFile,
|
||||||
actionManager.getNewHelpLocation());
|
provider, actionManager.getNewHelpLocation());
|
||||||
if (dialog.isCancelled()) {
|
if (dialog.isCancelled()) {
|
||||||
plugin.getTool().setStatusInfo("User cancelled creating a new script.");
|
plugin.getTool().setStatusInfo("User cancelled creating a new script.");
|
||||||
return;
|
return;
|
||||||
|
@ -676,6 +676,11 @@ public class GhidraScriptComponentProvider extends ComponentProviderAdapter {
|
||||||
private GhidraScript getScriptInstance(ResourceFile scriptFile, ConsoleService console) {
|
private GhidraScript getScriptInstance(ResourceFile scriptFile, ConsoleService console) {
|
||||||
String scriptName = scriptFile.getName();
|
String scriptName = scriptFile.getName();
|
||||||
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(scriptFile);
|
GhidraScriptProvider provider = GhidraScriptUtil.getProvider(scriptFile);
|
||||||
|
if (provider == null) {
|
||||||
|
console.addErrorMessage("",
|
||||||
|
"Could not find a compatible script provider for: " + scriptName);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
try {
|
try {
|
||||||
return provider.getScriptInstance(scriptFile, console.getStdErr());
|
return provider.getScriptInstance(scriptFile, console.getStdErr());
|
||||||
}
|
}
|
||||||
|
|
|
@ -561,8 +561,8 @@ public class GhidraScriptEditorComponentProvider extends ComponentProvider {
|
||||||
|
|
||||||
private boolean saveAs() {
|
private boolean saveAs() {
|
||||||
HelpLocation help = new HelpLocation(plugin.getName(), saveAction.getName());
|
HelpLocation help = new HelpLocation(plugin.getName(), saveAction.getName());
|
||||||
SaveDialog dialog =
|
SaveDialog dialog = new SaveDialog(getComponent(), "Save Script", provider,
|
||||||
new SaveDialog(getComponent(), "Save Script", provider, scriptSourceFile, help);
|
scriptSourceFile, GhidraScriptUtil.getProvider(scriptSourceFile), help);
|
||||||
if (dialog.isCancelled()) {
|
if (dialog.isCancelled()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -66,6 +66,8 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||||
descriptor.addVisibleColumn(new CategoryColumn());
|
descriptor.addVisibleColumn(new CategoryColumn());
|
||||||
descriptor.addHiddenColumn(new CreatedColumn());
|
descriptor.addHiddenColumn(new CreatedColumn());
|
||||||
descriptor.addVisibleColumn(new ModifiedColumn());
|
descriptor.addVisibleColumn(new ModifiedColumn());
|
||||||
|
descriptor.addHiddenColumn(new RuntimeColumn());
|
||||||
|
descriptor.addHiddenColumn(new ProviderColumn());
|
||||||
|
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
|
@ -298,7 +300,7 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||||
public Icon getValue(ResourceFile rowObject, Settings settings, Object data,
|
public Icon getValue(ResourceFile rowObject, Settings settings, Object data,
|
||||||
ServiceProvider sp) throws IllegalArgumentException {
|
ServiceProvider sp) throws IllegalArgumentException {
|
||||||
ScriptInfo info = infoManager.getExistingScriptInfo(rowObject);
|
ScriptInfo info = infoManager.getExistingScriptInfo(rowObject);
|
||||||
if (info.isCompileErrors() || info.isDuplicate()) {
|
if (info.hasErrors()) {
|
||||||
return ERROR_IMG;
|
return ERROR_IMG;
|
||||||
}
|
}
|
||||||
return info.getToolBarImage(true);
|
return info.getToolBarImage(true);
|
||||||
|
@ -541,6 +543,61 @@ class GhidraScriptTableModel extends GDynamicColumnTableModel<ResourceFile, Obje
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class RuntimeColumn extends AbstractDynamicTableColumn<ResourceFile, String, Object> {
|
||||||
|
|
||||||
|
private Comparator<String> comparator = new CaseInsensitiveDuplicateStringComparator();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Comparator<String> getComparator() {
|
||||||
|
return comparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getColumnName() {
|
||||||
|
return "Runtime";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue(ResourceFile rowObject, Settings settings, Object data,
|
||||||
|
ServiceProvider sp) throws IllegalArgumentException {
|
||||||
|
return infoManager.getExistingScriptInfo(rowObject).getRuntimeEnvironmentName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumnPreferredWidth() {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ProviderColumn extends AbstractDynamicTableColumn<ResourceFile, String, Object> {
|
||||||
|
|
||||||
|
private Comparator<String> comparator = new CaseInsensitiveDuplicateStringComparator();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Comparator<String> getComparator() {
|
||||||
|
return comparator;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getColumnName() {
|
||||||
|
return "Runtime Provider";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValue(ResourceFile rowObject, Settings settings, Object data,
|
||||||
|
ServiceProvider sp) throws IllegalArgumentException {
|
||||||
|
return infoManager.getExistingScriptInfo(rowObject)
|
||||||
|
.getProvider()
|
||||||
|
.getClass()
|
||||||
|
.getSimpleName();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumnPreferredWidth() {
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class DateRenderer extends AbstractGColumnRenderer<Date> {
|
private class DateRenderer extends AbstractGColumnRenderer<Date> {
|
||||||
@Override
|
@Override
|
||||||
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
public Component getTableCellRendererComponent(GTableCellRenderingData data) {
|
||||||
|
|
|
@ -47,9 +47,9 @@ public class SaveDialog extends DialogComponentProvider implements ListSelection
|
||||||
private boolean cancelled;
|
private boolean cancelled;
|
||||||
|
|
||||||
SaveDialog(Component parent, String title, GhidraScriptComponentProvider componentProvider,
|
SaveDialog(Component parent, String title, GhidraScriptComponentProvider componentProvider,
|
||||||
ResourceFile scriptFile, HelpLocation help) {
|
ResourceFile scriptFile, GhidraScriptProvider scriptProvider, HelpLocation help) {
|
||||||
this(parent, title, componentProvider, componentProvider.getWritableScriptDirectories(),
|
this(parent, title, componentProvider, componentProvider.getWritableScriptDirectories(),
|
||||||
scriptFile, help);
|
scriptFile, scriptProvider, help);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -60,15 +60,16 @@ public class SaveDialog extends DialogComponentProvider implements ListSelection
|
||||||
* @param componentProvider the provider
|
* @param componentProvider the provider
|
||||||
* @param scriptDirs list of directories to give as options when saving
|
* @param scriptDirs list of directories to give as options when saving
|
||||||
* @param scriptFile the default save location
|
* @param scriptFile the default save location
|
||||||
|
* @param scriptProvider the {@link GhidraScriptProvider}
|
||||||
* @param help contextual help, e.g. for rename or save
|
* @param help contextual help, e.g. for rename or save
|
||||||
*/
|
*/
|
||||||
public SaveDialog(Component parent, String title,
|
public SaveDialog(Component parent, String title,
|
||||||
GhidraScriptComponentProvider componentProvider, List<ResourceFile> scriptDirs,
|
GhidraScriptComponentProvider componentProvider, List<ResourceFile> scriptDirs,
|
||||||
ResourceFile scriptFile, HelpLocation help) {
|
ResourceFile scriptFile, GhidraScriptProvider scriptProvider, HelpLocation help) {
|
||||||
super(title, true, true, true, false);
|
super(title, true, true, true, false);
|
||||||
|
|
||||||
this.componentProvider = componentProvider;
|
this.componentProvider = componentProvider;
|
||||||
this.provider = GhidraScriptUtil.getProvider(scriptFile);
|
this.provider = scriptProvider;
|
||||||
this.scriptFile = scriptFile;
|
this.scriptFile = scriptFile;
|
||||||
this.paths = new ArrayList<>(scriptDirs);
|
this.paths = new ArrayList<>(scriptDirs);
|
||||||
|
|
||||||
|
|
|
@ -19,14 +19,15 @@ import java.awt.Component;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
|
import ghidra.app.script.GhidraScriptProvider;
|
||||||
import ghidra.util.HelpLocation;
|
import ghidra.util.HelpLocation;
|
||||||
|
|
||||||
class SaveNewScriptDialog extends SaveDialog {
|
class SaveNewScriptDialog extends SaveDialog {
|
||||||
|
|
||||||
SaveNewScriptDialog(Component parent, String title,
|
SaveNewScriptDialog(Component parent, String title,
|
||||||
GhidraScriptComponentProvider componentProvider, ResourceFile scriptFile,
|
GhidraScriptComponentProvider componentProvider, ResourceFile scriptFile,
|
||||||
HelpLocation help) {
|
GhidraScriptProvider scriptProvider, HelpLocation help) {
|
||||||
super(parent, title, componentProvider, scriptFile, help);
|
super(parent, title, componentProvider, scriptFile, scriptProvider, help);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,99 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.script;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import generic.jar.ResourceFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract {@link GhidraScriptProvider} used to provide common functionality to different
|
||||||
|
* types of Python script implementations
|
||||||
|
*/
|
||||||
|
public abstract class AbstractPythonScriptProvider extends GhidraScriptProvider {
|
||||||
|
|
||||||
|
private static final Pattern BLOCK_COMMENT = Pattern.compile("'''");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract String getDescription();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract String getRuntimeEnvironmentName();
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public abstract GhidraScript getScriptInstance(ResourceFile sourceFile, PrintWriter writer)
|
||||||
|
throws GhidraScriptLoadException;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createNewScript(ResourceFile newScript, String category) throws IOException {
|
||||||
|
try (PrintWriter writer = new PrintWriter(new FileWriter(newScript.getFile(false)))) {
|
||||||
|
writeHeader(writer, category);
|
||||||
|
writer.println("");
|
||||||
|
writeBody(writer);
|
||||||
|
writer.println("");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* <p>
|
||||||
|
* In Python this is a triple single quote sequence, "'''".
|
||||||
|
*
|
||||||
|
* @return the Pattern for Python block comment openings
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Pattern getBlockCommentStart() {
|
||||||
|
return BLOCK_COMMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* {@inheritDoc}
|
||||||
|
* <p>
|
||||||
|
* In Python this is a triple single quote sequence, "'''".
|
||||||
|
*
|
||||||
|
* @return the Pattern for Python block comment openings
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Pattern getBlockCommentEnd() {
|
||||||
|
return BLOCK_COMMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommentCharacter() {
|
||||||
|
return "#";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getCertifyHeaderStart() {
|
||||||
|
return "## ###";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getCertificationBodyPrefix() {
|
||||||
|
return "#";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getCertifyHeaderEnd() {
|
||||||
|
return "##";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExtension() {
|
||||||
|
return ".py";
|
||||||
|
}
|
||||||
|
}
|
|
@ -105,6 +105,19 @@ public abstract class GhidraScriptProvider
|
||||||
public abstract void createNewScript(ResourceFile newScript, String category)
|
public abstract void createNewScript(ResourceFile newScript, String category)
|
||||||
throws IOException;
|
throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns an optional runtime environment name of a {@link GhidraScriptProvider} that scripts
|
||||||
|
* can specify they require to run under. Useful for when more than one
|
||||||
|
* {@link GhidraScriptProvider} uses the same file extension.
|
||||||
|
*
|
||||||
|
* @return an optional runtime environment name of a {@link GhidraScriptProvider} that scripts
|
||||||
|
* can specify they require to run under (could be null if there is no requirement)
|
||||||
|
* @see ScriptInfo#AT_RUNTIME
|
||||||
|
*/
|
||||||
|
public String getRuntimeEnvironmentName() {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a Pattern that matches block comment openings.
|
* Returns a Pattern that matches block comment openings.
|
||||||
*
|
*
|
||||||
|
@ -161,6 +174,9 @@ public abstract class GhidraScriptProvider
|
||||||
if (metadataItem.equals(ScriptInfo.AT_CATEGORY)) {
|
if (metadataItem.equals(ScriptInfo.AT_CATEGORY)) {
|
||||||
writer.print(category);
|
writer.print(category);
|
||||||
}
|
}
|
||||||
|
else if (metadataItem.equals(ScriptInfo.AT_RUNTIME)) {
|
||||||
|
writer.print(getRuntimeEnvironmentName());
|
||||||
|
}
|
||||||
|
|
||||||
writer.println("");
|
writer.println("");
|
||||||
}
|
}
|
||||||
|
|
|
@ -276,29 +276,31 @@ public class GhidraScriptUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a list of all Ghidra script providers
|
* Returns a list of all supported Ghidra script providers
|
||||||
*
|
*
|
||||||
* @return a list of all Ghidra script providers
|
* @return a list of all supported Ghidra script providers
|
||||||
*/
|
*/
|
||||||
// Note: this method is synchronized so that two threads do not try to create the list when null
|
// Note: this method is synchronized so that two threads do not try to create the list when null
|
||||||
public static synchronized List<GhidraScriptProvider> getProviders() {
|
public static synchronized List<GhidraScriptProvider> getProviders() {
|
||||||
if (providers == null) {
|
if (providers == null) {
|
||||||
List<GhidraScriptProvider> newProviders =
|
providers = ClassSearcher.getInstances(GhidraScriptProvider.class)
|
||||||
new ArrayList<>(ClassSearcher.getInstances(GhidraScriptProvider.class));
|
.stream()
|
||||||
Collections.sort(newProviders);
|
.filter(p -> !(p instanceof UnsupportedScriptProvider))
|
||||||
providers = newProviders;
|
.sorted()
|
||||||
|
.toList();
|
||||||
}
|
}
|
||||||
return providers;
|
return providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the corresponding Ghidra script providers
|
* Returns the corresponding Ghidra script provider for the specified script file.
|
||||||
* for the specified script file.
|
*
|
||||||
* @param scriptFile the script file
|
* @param scriptFile the script file
|
||||||
* @return the Ghidra script provider
|
* @return the Ghidra script provider or {@link UnsupportedScriptProvider} if the script file
|
||||||
|
* does not exist or no provider matches
|
||||||
*/
|
*/
|
||||||
public static GhidraScriptProvider getProvider(ResourceFile scriptFile) {
|
public static GhidraScriptProvider getProvider(ResourceFile scriptFile) {
|
||||||
return findProvider(scriptFile.getName());
|
return findProvider(scriptFile);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -308,11 +310,46 @@ public class GhidraScriptUtil {
|
||||||
* @return true if a provider exists that can process the specified file
|
* @return true if a provider exists that can process the specified file
|
||||||
*/
|
*/
|
||||||
public static boolean hasScriptProvider(ResourceFile scriptFile) {
|
public static boolean hasScriptProvider(ResourceFile scriptFile) {
|
||||||
return findProvider(scriptFile.getName()) != null;
|
return findProvider(scriptFile) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Find the provider whose extension matches the given filename extension.
|
* Find the first provider whose extension matches the given file's extension and whose
|
||||||
|
* {@link ScriptInfo#AT_RUNTIME} matches
|
||||||
|
*
|
||||||
|
* @param scriptFile the script file (not guaranteed to exist if this method is called because
|
||||||
|
* the script manager is creating a new script and all it has to go off of initially is
|
||||||
|
* the desired file extension...in this case there will not be a @runtime tag yet)
|
||||||
|
* @return the matching provider or null if no provider matches
|
||||||
|
*/
|
||||||
|
private static GhidraScriptProvider findProvider(ResourceFile scriptFile) {
|
||||||
|
GhidraScriptProvider baseProvider = null;
|
||||||
|
String fileName = scriptFile.getName().toLowerCase();
|
||||||
|
for (GhidraScriptProvider provider : getProviders()) {
|
||||||
|
String extension = provider.getExtension().toLowerCase();
|
||||||
|
if (fileName.endsWith(extension)) {
|
||||||
|
baseProvider = provider;
|
||||||
|
if (!scriptFile.exists()) {
|
||||||
|
// Use UnsupportedScriptProvider. The provider will be updated later when
|
||||||
|
// the file actually exists and we can properly look for an @runtime tag
|
||||||
|
// (or confirm that one is not defined)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
String runtime = new ScriptInfo(provider, scriptFile).getRuntimeEnvironmentName();
|
||||||
|
if (runtime == null ||
|
||||||
|
runtime.equalsIgnoreCase(provider.getRuntimeEnvironmentName())) {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (baseProvider != null) {
|
||||||
|
return new UnsupportedScriptProvider(baseProvider);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the first provider whose extension matches the given filename extension.
|
||||||
*
|
*
|
||||||
* @param fileName name of script file
|
* @param fileName name of script file
|
||||||
* @return the first matching provider or null if no provider matches
|
* @return the first matching provider or null if no provider matches
|
||||||
|
|
|
@ -69,6 +69,11 @@ public class JavaScriptProvider extends GhidraScriptProvider {
|
||||||
return ".java";
|
return ".java";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getRuntimeEnvironmentName() {
|
||||||
|
return "Java";
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean deleteScript(ResourceFile sourceFile) {
|
public boolean deleteScript(ResourceFile sourceFile) {
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -46,12 +46,13 @@ public class ScriptInfo {
|
||||||
static final String AT_KEYBINDING = "@keybinding";
|
static final String AT_KEYBINDING = "@keybinding";
|
||||||
static final String AT_MENUPATH = "@menupath";
|
static final String AT_MENUPATH = "@menupath";
|
||||||
static final String AT_TOOLBAR = "@toolbar";
|
static final String AT_TOOLBAR = "@toolbar";
|
||||||
|
static final String AT_RUNTIME = "@runtime";
|
||||||
|
|
||||||
// omit from METADATA to avoid pre-populating in new scripts
|
// omit from METADATA to avoid pre-populating in new scripts
|
||||||
private static final String AT_IMPORTPACKAGE = "@importpackage";
|
private static final String AT_IMPORTPACKAGE = "@importpackage";
|
||||||
|
|
||||||
public static final String[] METADATA =
|
public static final String[] METADATA =
|
||||||
{ AT_AUTHOR, AT_CATEGORY, AT_KEYBINDING, AT_MENUPATH, AT_TOOLBAR, };
|
{ AT_AUTHOR, AT_CATEGORY, AT_KEYBINDING, AT_MENUPATH, AT_TOOLBAR, AT_RUNTIME };
|
||||||
|
|
||||||
private GhidraScriptProvider provider;
|
private GhidraScriptProvider provider;
|
||||||
private ResourceFile sourceFile;
|
private ResourceFile sourceFile;
|
||||||
|
@ -68,6 +69,7 @@ public class ScriptInfo {
|
||||||
private String toolbar;
|
private String toolbar;
|
||||||
private ImageIcon toolbarImage;
|
private ImageIcon toolbarImage;
|
||||||
private String importpackage;
|
private String importpackage;
|
||||||
|
private String runtime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructs a new script.
|
* Constructs a new script.
|
||||||
|
@ -94,6 +96,7 @@ public class ScriptInfo {
|
||||||
toolbarImage = null;
|
toolbarImage = null;
|
||||||
importpackage = null;
|
importpackage = null;
|
||||||
keybindingErrorMessage = null;
|
keybindingErrorMessage = null;
|
||||||
|
runtime = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -129,6 +132,26 @@ public class ScriptInfo {
|
||||||
return author;
|
return author;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the name of the required runtime environment
|
||||||
|
* @return the name of the required runtime environment
|
||||||
|
* @see GhidraScriptProvider#getRuntimeEnvironmentName()
|
||||||
|
*/
|
||||||
|
public String getRuntimeEnvironmentName() {
|
||||||
|
parseHeader();
|
||||||
|
return runtime;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the {@link GhidraScriptProvider} currently associated with the script
|
||||||
|
* @return The {@link GhidraScriptProvider} currently associated with the script
|
||||||
|
*/
|
||||||
|
public GhidraScriptProvider getProvider() {
|
||||||
|
parseHeader();
|
||||||
|
provider = GhidraScriptUtil.getProvider(sourceFile);
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns true if the script has compile errors.
|
* Returns true if the script has compile errors.
|
||||||
* @return true if the script has compile errors
|
* @return true if the script has compile errors
|
||||||
|
@ -163,6 +186,16 @@ public class ScriptInfo {
|
||||||
this.isDuplicate = isDuplicate;
|
this.isDuplicate = isDuplicate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if this script has an {@link UnsupportedScriptProvider}. This will typically
|
||||||
|
* happen when a script defines a wrong {@link ScriptInfo#AT_RUNTIME} tag.
|
||||||
|
*
|
||||||
|
* @return True if this script has an {@link UnsupportedScriptProvider}; otherwise, false
|
||||||
|
*/
|
||||||
|
public boolean hasUnsupportedProvider() {
|
||||||
|
return provider instanceof UnsupportedScriptProvider;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the script description.
|
* Returns the script description.
|
||||||
* @return the script description
|
* @return the script description
|
||||||
|
@ -329,6 +362,9 @@ public class ScriptInfo {
|
||||||
else if (line.startsWith(AT_IMPORTPACKAGE)) {
|
else if (line.startsWith(AT_IMPORTPACKAGE)) {
|
||||||
importpackage = getTagValue(AT_IMPORTPACKAGE, line);
|
importpackage = getTagValue(AT_IMPORTPACKAGE, line);
|
||||||
}
|
}
|
||||||
|
else if (line.startsWith(AT_RUNTIME)) {
|
||||||
|
runtime = getTagValue(AT_RUNTIME, line);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (Exception e) {
|
catch (Exception e) {
|
||||||
Msg.debug(this, "Unexpected exception reading script metadata " + "line: " + line, e);
|
Msg.debug(this, "Unexpected exception reading script metadata " + "line: " + line, e);
|
||||||
|
@ -514,6 +550,7 @@ public class ScriptInfo {
|
||||||
String htmlCategory = bold("Category:") + space + escapeHTML(toString(category));
|
String htmlCategory = bold("Category:") + space + escapeHTML(toString(category));
|
||||||
String htmlKeyBinding = bold("Key Binding:") + space + getKeybindingToolTip();
|
String htmlKeyBinding = bold("Key Binding:") + space + getKeybindingToolTip();
|
||||||
String htmlMenuPath = bold("Menu Path:") + space + escapeHTML(toString(menupath));
|
String htmlMenuPath = bold("Menu Path:") + space + escapeHTML(toString(menupath));
|
||||||
|
String htmlRuntime = bold("Runtime Environment:") + space + escapeHTML(toString(runtime));
|
||||||
|
|
||||||
StringBuilder buffer = new StringBuilder();
|
StringBuilder buffer = new StringBuilder();
|
||||||
buffer.append("<h3>").append(space).append(escapeHTML(getName())).append("</h3>");
|
buffer.append("<h3>").append(space).append(escapeHTML(getName())).append("</h3>");
|
||||||
|
@ -529,6 +566,8 @@ public class ScriptInfo {
|
||||||
buffer.append(HTML_NEW_LINE);
|
buffer.append(HTML_NEW_LINE);
|
||||||
buffer.append(space).append(htmlMenuPath);
|
buffer.append(space).append(htmlMenuPath);
|
||||||
buffer.append(HTML_NEW_LINE);
|
buffer.append(HTML_NEW_LINE);
|
||||||
|
buffer.append(space).append(htmlRuntime);
|
||||||
|
buffer.append(HTML_NEW_LINE);
|
||||||
buffer.append(HTML_NEW_LINE);
|
buffer.append(HTML_NEW_LINE);
|
||||||
return wrapAsHTML(buffer.toString());
|
return wrapAsHTML(buffer.toString());
|
||||||
}
|
}
|
||||||
|
@ -560,7 +599,7 @@ public class ScriptInfo {
|
||||||
* @return true if the script either has compiler errors, or is a duplicate
|
* @return true if the script either has compiler errors, or is a duplicate
|
||||||
*/
|
*/
|
||||||
public boolean hasErrors() {
|
public boolean hasErrors() {
|
||||||
return isCompileErrors() || isDuplicate();
|
return isCompileErrors() || isDuplicate() || hasUnsupportedProvider();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -575,6 +614,10 @@ public class ScriptInfo {
|
||||||
return "Script is a duplicate of another script";
|
return "Script is a duplicate of another script";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (hasUnsupportedProvider()) {
|
||||||
|
return "Script's @runtime tag specifies an unsupported runtime environment";
|
||||||
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
/* ###
|
||||||
|
* IP: GHIDRA
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package ghidra.app.script;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.PrintWriter;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
import generic.jar.ResourceFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A stub provider for unsupported scripts. These will typically be scripts with supported
|
||||||
|
* extensions but unsupported {@link ScriptInfo#AT_RUNTIME} tags.
|
||||||
|
*/
|
||||||
|
public class UnsupportedScriptProvider extends GhidraScriptProvider {
|
||||||
|
|
||||||
|
private GhidraScriptProvider baseProvider;
|
||||||
|
|
||||||
|
public UnsupportedScriptProvider() {
|
||||||
|
// Necessary for instantiation from the ClassSearcher
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new {@link UnsupportedScriptProvider} that is derived from the given base provider.
|
||||||
|
* The base provider is any provider with a compatible extension, but without the required
|
||||||
|
* {@link ScriptInfo#AT_RUNTIME} tag.
|
||||||
|
*
|
||||||
|
* @param baseProvider The base {@link GhidraScriptProvider}
|
||||||
|
*/
|
||||||
|
public UnsupportedScriptProvider(GhidraScriptProvider baseProvider) {
|
||||||
|
this.baseProvider = baseProvider;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "<unsupported>";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExtension() {
|
||||||
|
return baseProvider.getExtension();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public GhidraScript getScriptInstance(ResourceFile sourceFile, PrintWriter writer)
|
||||||
|
throws GhidraScriptLoadException {
|
||||||
|
throw new GhidraScriptLoadException("Script is not supported.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void createNewScript(ResourceFile newScript, String category) throws IOException {
|
||||||
|
// Do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getCommentCharacter() {
|
||||||
|
return baseProvider.getCommentCharacter();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pattern getBlockCommentStart() {
|
||||||
|
return baseProvider.getBlockCommentStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Pattern getBlockCommentEnd() {
|
||||||
|
return baseProvider.getBlockCommentEnd();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getCertifyHeaderStart() {
|
||||||
|
return baseProvider.getCertifyHeaderStart();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getCertificationBodyPrefix() {
|
||||||
|
return baseProvider.getCertificationBodyPrefix();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getCertifyHeaderEnd() {
|
||||||
|
return baseProvider.getCertifyHeaderEnd();
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,6 +19,7 @@
|
||||||
# use only. Please run the Java version in a production environment.
|
# use only. Please run the Java version in a production environment.
|
||||||
|
|
||||||
#@category Examples.Python
|
#@category Examples.Python
|
||||||
|
#@runtime Jython
|
||||||
|
|
||||||
|
|
||||||
from ghidra.program.model.address.Address import *
|
from ghidra.program.model.address.Address import *
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
# use only. Please run the Java version in a production environment.
|
# use only. Please run the Java version in a production environment.
|
||||||
|
|
||||||
#@category Examples.Python
|
#@category Examples.Python
|
||||||
|
#@runtime Jython
|
||||||
|
|
||||||
from ghidra.framework.model import DomainFile
|
from ghidra.framework.model import DomainFile
|
||||||
from ghidra.framework.model import DomainFolder
|
from ghidra.framework.model import DomainFolder
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
# NOTE: Script will only process unversioned and checked-out files.
|
# NOTE: Script will only process unversioned and checked-out files.
|
||||||
|
|
||||||
#@category Examples.Python
|
#@category Examples.Python
|
||||||
|
#@runtime Jython
|
||||||
|
|
||||||
from ghidra.app.script import GhidraState
|
from ghidra.app.script import GhidraState
|
||||||
from ghidra.framework.model import *
|
from ghidra.framework.model import *
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
# use only. Please run the Java version in a production environment.
|
# use only. Please run the Java version in a production environment.
|
||||||
|
|
||||||
#@category Examples.Python
|
#@category Examples.Python
|
||||||
|
#@runtime Jython
|
||||||
|
|
||||||
runScript("HelloWorldScript.java")
|
runScript("HelloWorldScript.java")
|
||||||
runScript("HelloWorldPopupScript.java")
|
runScript("HelloWorldPopupScript.java")
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
# use only. Please run the Java version in a production environment.
|
# use only. Please run the Java version in a production environment.
|
||||||
|
|
||||||
#@category Examples.Python
|
#@category Examples.Python
|
||||||
|
#@runtime Jython
|
||||||
|
|
||||||
from ghidra.app.util.datatype import DataTypeSelectionDialog
|
from ghidra.app.util.datatype import DataTypeSelectionDialog
|
||||||
from ghidra.framework.plugintool import PluginTool
|
from ghidra.framework.plugintool import PluginTool
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
# use only. Please run the Java version in a production environment.
|
# use only. Please run the Java version in a production environment.
|
||||||
|
|
||||||
#@category Examples.Python
|
#@category Examples.Python
|
||||||
|
#@runtime Jython
|
||||||
|
|
||||||
from ghidra.app.plugin.core.colorizer import ColorizingService
|
from ghidra.app.plugin.core.colorizer import ColorizingService
|
||||||
from ghidra.app.script import GhidraScript
|
from ghidra.app.script import GhidraScript
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
# use only. Please run the Java version in a production environment.
|
# use only. Please run the Java version in a production environment.
|
||||||
|
|
||||||
#@category Examples.Python
|
#@category Examples.Python
|
||||||
|
#@runtime Jython
|
||||||
|
|
||||||
from time import *
|
from time import *
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
# Omitting the address space or memory region specifier from the address will result in the function or label being created in the default address space.
|
# Omitting the address space or memory region specifier from the address will result in the function or label being created in the default address space.
|
||||||
# @author unkown; edited by matedealer <git@matedealer.de>
|
# @author unkown; edited by matedealer <git@matedealer.de>
|
||||||
# @category Data
|
# @category Data
|
||||||
|
# @runtime Jython
|
||||||
#
|
#
|
||||||
|
|
||||||
from ghidra.program.model.symbol.SourceType import *
|
from ghidra.program.model.symbol.SourceType import *
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
##
|
##
|
||||||
# Prints out all the functions in the program that have a non-zero stack purge size
|
# Prints out all the functions in the program that have a non-zero stack purge size
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
for func in currentProgram.getFunctionManager().getFunctions(currentProgram.evaluateAddress("0"), 1):
|
for func in currentProgram.getFunctionManager().getFunctions(currentProgram.evaluateAddress("0"), 1):
|
||||||
if func.getStackPurgeSize() != 0:
|
if func.getStackPurgeSize() != 0:
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
# use only. Please run the Java version in a production environment.
|
# use only. Please run the Java version in a production environment.
|
||||||
|
|
||||||
#@category Examples.Python
|
#@category Examples.Python
|
||||||
|
#@runtime Jython
|
||||||
|
|
||||||
from ghidra.framework.options import Options
|
from ghidra.framework.options import Options
|
||||||
from ghidra.framework.plugintool import PluginTool
|
from ghidra.framework.plugintool import PluginTool
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
##
|
##
|
||||||
# Example of being imported by a Ghidra Python script/module
|
# Example of being imported by a Ghidra Python script/module
|
||||||
# @category: Examples.Python
|
# @category: Examples.Python
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
# The following line will fail if this module is imported from external_module_caller.py,
|
# The following line will fail if this module is imported from external_module_caller.py,
|
||||||
# because only the script that gets directly launched by Ghidra inherits fields and methods
|
# because only the script that gets directly launched by Ghidra inherits fields and methods
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
##
|
##
|
||||||
# Example of importing an external Ghidra Python module
|
# Example of importing an external Ghidra Python module
|
||||||
# @category: Examples.Python
|
# @category: Examples.Python
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
# Import the external module that wants to access the Ghidra scripting API.
|
# Import the external module that wants to access the Ghidra scripting API.
|
||||||
# NOTE: see external_module_callee.py for additional tips.
|
# NOTE: see external_module_callee.py for additional tips.
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
##
|
##
|
||||||
# Examples of basic Ghidra scripting in Python
|
# Examples of basic Ghidra scripting in Python
|
||||||
# @category: Examples.Python
|
# @category: Examples.Python
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
# Get info about the current program
|
# Get info about the current program
|
||||||
print
|
print
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
##
|
##
|
||||||
# Examples of Jython-specific functionality
|
# Examples of Jython-specific functionality
|
||||||
# @category: Examples.Python
|
# @category: Examples.Python
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
# Using Java data structures from Jython
|
# Using Java data structures from Jython
|
||||||
python_list = [1, 2, 3]
|
python_list = [1, 2, 3]
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
##
|
##
|
||||||
# Examples of basic Python
|
# Examples of basic Python
|
||||||
# @category: Examples.Python
|
# @category: Examples.Python
|
||||||
|
# @runtime Jython
|
||||||
|
|
||||||
# Python data types
|
# Python data types
|
||||||
my_int = 32
|
my_int = 32
|
||||||
|
|
|
@ -15,71 +15,17 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.jython;
|
package ghidra.jython;
|
||||||
|
|
||||||
import java.io.*;
|
import java.io.PrintWriter;
|
||||||
import java.util.regex.Pattern;
|
|
||||||
|
|
||||||
import generic.jar.ResourceFile;
|
import generic.jar.ResourceFile;
|
||||||
import ghidra.app.script.*;
|
import ghidra.app.script.*;
|
||||||
|
import ghidra.util.classfinder.ExtensionPointProperties;
|
||||||
|
|
||||||
public class JythonScriptProvider extends GhidraScriptProvider {
|
/**
|
||||||
|
* A {@link GhidraScriptProvider} used to run Jython scripts
|
||||||
private static final Pattern BLOCK_COMMENT = Pattern.compile("'''");
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void createNewScript(ResourceFile newScript, String category) throws IOException {
|
|
||||||
PrintWriter writer = new PrintWriter(new FileWriter(newScript.getFile(false)));
|
|
||||||
writeHeader(writer, category);
|
|
||||||
writer.println("");
|
|
||||||
writeBody(writer);
|
|
||||||
writer.println("");
|
|
||||||
writer.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* In Jython this is a triple single quote sequence, "'''".
|
|
||||||
*
|
|
||||||
* @return the Pattern for Jython block comment openings
|
|
||||||
*/
|
*/
|
||||||
@Override
|
@ExtensionPointProperties(priority = 1000) // Enforce high priority so Jython is the default Python provider
|
||||||
public Pattern getBlockCommentStart() {
|
public class JythonScriptProvider extends AbstractPythonScriptProvider {
|
||||||
return BLOCK_COMMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* {@inheritDoc}
|
|
||||||
*
|
|
||||||
* <p>
|
|
||||||
* In Jython this is a triple single quote sequence, "'''".
|
|
||||||
*
|
|
||||||
* @return the Pattern for Jython block comment openings
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public Pattern getBlockCommentEnd() {
|
|
||||||
return BLOCK_COMMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getCommentCharacter() {
|
|
||||||
return "#";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getCertifyHeaderStart() {
|
|
||||||
return "## ###";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getCertificationBodyPrefix() {
|
|
||||||
return "#";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected String getCertifyHeaderEnd() {
|
|
||||||
return "##";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getDescription() {
|
public String getDescription() {
|
||||||
|
@ -87,8 +33,8 @@ public class JythonScriptProvider extends GhidraScriptProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getExtension() {
|
public String getRuntimeEnvironmentName() {
|
||||||
return ".py";
|
return "Jython";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -105,4 +51,5 @@ public class JythonScriptProvider extends GhidraScriptProvider {
|
||||||
throw new GhidraScriptLoadException(e);
|
throw new GhidraScriptLoadException(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -82,7 +82,7 @@ public class GhidraScriptMgrPluginScreenShots extends GhidraScreenShotGenerator
|
||||||
scriptDirs.add(new ResourceFile("/User/home/ghidra_scripts"));
|
scriptDirs.add(new ResourceFile("/User/home/ghidra_scripts"));
|
||||||
|
|
||||||
SaveDialog dialog = new SaveDialog(tool.getToolFrame(), "Save Script", provider,
|
SaveDialog dialog = new SaveDialog(tool.getToolFrame(), "Save Script", provider,
|
||||||
scriptDirs, scriptFile, helpLocation);
|
scriptDirs, scriptFile, new JavaScriptProvider(), helpLocation);
|
||||||
|
|
||||||
tool.showDialog(dialog);
|
tool.showDialog(dialog);
|
||||||
}, false);
|
}, false);
|
||||||
|
@ -208,7 +208,7 @@ public class GhidraScriptMgrPluginScreenShots extends GhidraScreenShotGenerator
|
||||||
scriptDirs.add(new ResourceFile("/User/home/ghidra_scripts"));
|
scriptDirs.add(new ResourceFile("/User/home/ghidra_scripts"));
|
||||||
|
|
||||||
SaveDialog dialog = new SaveDialog(tool.getToolFrame(), "Rename Script", provider,
|
SaveDialog dialog = new SaveDialog(tool.getToolFrame(), "Rename Script", provider,
|
||||||
scriptDirs, scriptFile, helpLocation);
|
scriptDirs, scriptFile, new JavaScriptProvider(), helpLocation);
|
||||||
|
|
||||||
tool.showDialog(dialog);
|
tool.showDialog(dialog);
|
||||||
}, false);
|
}, false);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue