mirror of
https://github.com/NationalSecurityAgency/ghidra.git
synced 2025-10-03 09:49:23 +02:00
don't assume that scripts are Java, fixes #2562
This commit is contained in:
parent
b9129348fc
commit
e4e15cdb9d
4 changed files with 93 additions and 30 deletions
|
@ -133,4 +133,19 @@ public abstract class GhidraScriptProvider
|
||||||
protected void writeBody(PrintWriter writer) {
|
protected void writeBody(PrintWriter writer) {
|
||||||
writer.println(getCommentCharacter() + "TODO Add User Code Here");
|
writer.println(getCommentCharacter() + "TODO Add User Code Here");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fixup a script name for searching in script directories.
|
||||||
|
*
|
||||||
|
* <p>This method is part of a poorly specified behavior that is due for future amendment,
|
||||||
|
* see {@link GhidraScriptUtil#fixupName(String)}.
|
||||||
|
*
|
||||||
|
* @param scriptName the name of the script, must end with this provider's extension
|
||||||
|
* @return a (relative) file path to the corresponding script
|
||||||
|
*/
|
||||||
|
@Deprecated
|
||||||
|
protected String fixupName(String scriptName) {
|
||||||
|
return scriptName;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,7 @@ import generic.jar.ResourceFile;
|
||||||
import ghidra.app.plugin.core.osgi.BundleHost;
|
import ghidra.app.plugin.core.osgi.BundleHost;
|
||||||
import ghidra.app.plugin.core.osgi.OSGiException;
|
import ghidra.app.plugin.core.osgi.OSGiException;
|
||||||
import ghidra.app.plugin.core.script.GhidraScriptMgrPlugin;
|
import ghidra.app.plugin.core.script.GhidraScriptMgrPlugin;
|
||||||
|
import ghidra.app.util.headless.HeadlessAnalyzer;
|
||||||
import ghidra.framework.Application;
|
import ghidra.framework.Application;
|
||||||
import ghidra.util.Msg;
|
import ghidra.util.Msg;
|
||||||
import ghidra.util.classfinder.ClassSearcher;
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
|
@ -139,8 +140,7 @@ public class GhidraScriptUtil {
|
||||||
}
|
}
|
||||||
catch (IOException e) {
|
catch (IOException e) {
|
||||||
Msg.error(GhidraScriptUtil.class,
|
Msg.error(GhidraScriptUtil.class,
|
||||||
"Failed to find script in any script directory: " + sourceFile.toString(),
|
"Failed to find script in any script directory: " + sourceFile.toString(), e);
|
||||||
e);
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -293,14 +293,7 @@ public class GhidraScriptUtil {
|
||||||
* @return the Ghidra script provider
|
* @return the Ghidra script provider
|
||||||
*/
|
*/
|
||||||
public static GhidraScriptProvider getProvider(ResourceFile scriptFile) {
|
public static GhidraScriptProvider getProvider(ResourceFile scriptFile) {
|
||||||
String scriptFileName = scriptFile.getName().toLowerCase();
|
return findProvider(scriptFile.getName());
|
||||||
|
|
||||||
for (GhidraScriptProvider provider : getProviders()) {
|
|
||||||
if (scriptFileName.endsWith(provider.getExtension().toLowerCase())) {
|
|
||||||
return provider;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -310,13 +303,23 @@ 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) {
|
||||||
String scriptFileName = scriptFile.getName().toLowerCase();
|
return findProvider(scriptFile.getName()) != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the provider whose extension matches the given filename extension.
|
||||||
|
*
|
||||||
|
* @param fileName name of script file
|
||||||
|
* @return the first matching provider or null if no provider matches
|
||||||
|
*/
|
||||||
|
private static GhidraScriptProvider findProvider(String fileName) {
|
||||||
|
fileName = fileName.toLowerCase();
|
||||||
for (GhidraScriptProvider provider : getProviders()) {
|
for (GhidraScriptProvider provider : getProviders()) {
|
||||||
if (scriptFileName.endsWith(provider.getExtension().toLowerCase())) {
|
if (fileName.endsWith(provider.getExtension().toLowerCase())) {
|
||||||
return true;
|
return provider;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -362,31 +365,35 @@ public class GhidraScriptUtil {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fixup name issues, such as package parts in the name and inner class names.
|
* Fix script name issues for searching in script directories.
|
||||||
|
* If no provider can be identified, Java is assumed.
|
||||||
*
|
*
|
||||||
* <p>This method can handle names with or without '.java' at the end; names with
|
* <p>This method is part of a poorly specified behavior that is due for future amendment.
|
||||||
* '$' (inner classes) and names with '.' characters for package separators
|
*
|
||||||
|
* <p>It is used by {@link GhidraScript#runScript(String)} methods,
|
||||||
|
* {@link #createNewScript(String, String, ResourceFile, List)}, and by {@link HeadlessAnalyzer} for
|
||||||
|
* {@code preScript} and {@code postScript}. The intent was to allow some freedom in how a user specifies
|
||||||
|
* a script in two ways: 1) if the extension is omitted ".java" is assumed and 2) if a Java class name is
|
||||||
|
* given it's converted to a relative path.
|
||||||
*
|
*
|
||||||
* @param name the name of the script
|
* @param name the name of the script
|
||||||
* @return the name as a '.java' file path (with '/'s and not '.'s)
|
* @return the name as a file path
|
||||||
*/
|
*/
|
||||||
|
@Deprecated
|
||||||
static String fixupName(String name) {
|
static String fixupName(String name) {
|
||||||
if (name.endsWith(".java")) {
|
GhidraScriptProvider provider = findProvider(name);
|
||||||
name = name.substring(0, name.length() - 5);
|
// assume Java if no provider matched
|
||||||
|
if (provider == null) {
|
||||||
|
name = name + ".java";
|
||||||
|
provider = findProvider(".java");
|
||||||
}
|
}
|
||||||
|
return provider.fixupName(name);
|
||||||
String path = name.replace('.', '/');
|
|
||||||
int innerClassIndex = path.indexOf('$');
|
|
||||||
if (innerClassIndex != -1) {
|
|
||||||
path = path.substring(0, innerClassIndex);
|
|
||||||
}
|
|
||||||
return path + ".java";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResourceFile findScriptFileInPaths(Collection<ResourceFile> scriptDirectories,
|
static ResourceFile findScriptFileInPaths(Collection<ResourceFile> scriptDirectories,
|
||||||
String filename) {
|
String name) {
|
||||||
|
|
||||||
String validatedName = fixupName(filename);
|
String validatedName = fixupName(name);
|
||||||
|
|
||||||
for (ResourceFile resourceFile : scriptDirectories) {
|
for (ResourceFile resourceFile : scriptDirectories) {
|
||||||
if (resourceFile.isDirectory()) {
|
if (resourceFile.isDirectory()) {
|
||||||
|
|
|
@ -164,4 +164,29 @@ public class JavaScriptProvider extends GhidraScriptProvider {
|
||||||
return "//";
|
return "//";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Fix script name for search in script directories, such as Java package parts in the name and inner class names.
|
||||||
|
*
|
||||||
|
* <p>This method can handle names with '$' (inner classes) and names with '.'
|
||||||
|
* characters for package separators
|
||||||
|
*
|
||||||
|
* <p>It is part of a poorly specified behavior that is due for future amendment,
|
||||||
|
* see {@link GhidraScriptUtil#fixupName(String)}.
|
||||||
|
*
|
||||||
|
* @param scriptName the name of the script
|
||||||
|
* @return the name as a '.java' file path (with '/'s and not '.'s)
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
protected String fixupName(String scriptName) {
|
||||||
|
scriptName = scriptName.substring(0, scriptName.length() - 5);
|
||||||
|
|
||||||
|
String path = scriptName.replace('.', '/');
|
||||||
|
int innerClassIndex = path.indexOf('$');
|
||||||
|
if (innerClassIndex != -1) {
|
||||||
|
path = path.substring(0, innerClassIndex);
|
||||||
|
}
|
||||||
|
return path + ".java";
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,14 +15,23 @@
|
||||||
*/
|
*/
|
||||||
package ghidra.app.script;
|
package ghidra.app.script;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import generic.test.AbstractGenericTest;
|
import generic.test.AbstractGenericTest;
|
||||||
|
import ghidra.util.classfinder.ClassSearcher;
|
||||||
|
import ghidra.util.exception.CancelledException;
|
||||||
|
import ghidra.util.task.ConsoleTaskMonitor;
|
||||||
|
|
||||||
public class GhidraScriptUtilTest extends AbstractGenericTest {
|
public class GhidraScriptUtilTest extends AbstractGenericTest {
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setup() throws CancelledException {
|
||||||
|
ClassSearcher.search(false, new ConsoleTaskMonitor());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void fixupName_WithExtension() {
|
public void fixupName_WithExtension() {
|
||||||
String input = "Bob.java";
|
String input = "Bob.java";
|
||||||
|
@ -58,4 +67,11 @@ public class GhidraScriptUtilTest extends AbstractGenericTest {
|
||||||
String input = "a.b.c.Bob$InnerClass";
|
String input = "a.b.c.Bob$InnerClass";
|
||||||
assertEquals(GhidraScriptUtil.fixupName(input), "a/b/c/Bob.java");
|
assertEquals(GhidraScriptUtil.fixupName(input), "a/b/c/Bob.java");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void fixupName_Python() {
|
||||||
|
String input = "Bob.py";
|
||||||
|
assertEquals(GhidraScriptUtil.fixupName(input), "Bob.py");
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
Loading…
Add table
Add a link
Reference in a new issue