From 4737aa4ffa5ce0086af3d6ea4a3dfd0323236232 Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Mon, 24 Apr 2023 19:26:16 +0000 Subject: [PATCH 1/7] init commit Ghidrathon configuration --- .../ghidrathon/GhidrathonClassEnquirer.java | 56 ++++++++++++ .../java/ghidrathon/GhidrathonConfig.java | 76 ++++++++++++++++ .../GhidrathonConsoleInputThread.java | 17 ++-- .../java/ghidrathon/GhidrathonScript.java | 30 ++++--- .../interpreter/GhidrathonInterpreter.java | 89 +++++++++++++------ 5 files changed, 221 insertions(+), 47 deletions(-) create mode 100644 src/main/java/ghidrathon/GhidrathonClassEnquirer.java create mode 100644 src/main/java/ghidrathon/GhidrathonConfig.java diff --git a/src/main/java/ghidrathon/GhidrathonClassEnquirer.java b/src/main/java/ghidrathon/GhidrathonClassEnquirer.java new file mode 100644 index 0000000..6ff8192 --- /dev/null +++ b/src/main/java/ghidrathon/GhidrathonClassEnquirer.java @@ -0,0 +1,56 @@ +// Copyright (C) 2022 Mandiant, Inc. All Rights Reserved. +// 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: [package root]/LICENSE.txt +// 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 ghidrathon; + +import java.util.List; +import java.util.ArrayList; + +import jep.ClassList; +import jep.ClassEnquirer; + +public class GhidrathonClassEnquirer implements ClassEnquirer{ + + private final List javaExcludeLibs = new ArrayList(); + private final ClassEnquirer classList = ClassList.getInstance(); + + public void addJavaExcludeLib(String name) { + + javaExcludeLibs.add(name); + + } + + public void addJavaExcludeLibs(List names) { + + javaExcludeLibs.addAll(names); + + } + + public boolean isJavaPackage(String name) { + + if (javaExcludeLibs.contains(name)) { + return false; + } + + return classList.isJavaPackage(name); + + } + + public String[] getClassNames(String name) { + + return classList.getClassNames(name); + + } + + public String[] getSubPackages(String name) { + + return classList.getSubPackages(name); + + } + +} \ No newline at end of file diff --git a/src/main/java/ghidrathon/GhidrathonConfig.java b/src/main/java/ghidrathon/GhidrathonConfig.java new file mode 100644 index 0000000..1cdff55 --- /dev/null +++ b/src/main/java/ghidrathon/GhidrathonConfig.java @@ -0,0 +1,76 @@ +// Copyright (C) 2022 Mandiant, Inc. All Rights Reserved. +// 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: [package root]/LICENSE.txt +// 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 ghidrathon; + +import java.io.PrintWriter; +import java.util.List; +import java.util.ArrayList; +import java.util.Collections; + +public class GhidrathonConfig { + + private final List pythonSharedModules = new ArrayList(); + private final List javaExcludeLibs = new ArrayList(); + private final List pythonIncludePaths = new ArrayList(); + + private PrintWriter out = null; + private PrintWriter err = null; + + public void addStdOut(PrintWriter out) { + this.out = out; + } + + public void addStdErr(PrintWriter err) { + this.err = err; + } + + public PrintWriter getStdOut() { + return out; + } + + public PrintWriter getStdErr() { + return err; + } + + public void addPythonSharedModule(String name) { + pythonSharedModules.add(name); + } + + public void addPythonSharedModules(List names) { + pythonSharedModules.addAll(names); + } + + public Iterable getPythonSharedModules() { + return Collections.unmodifiableList(pythonSharedModules); + } + + public void addJavaExcludeLib(String name) { + javaExcludeLibs.add(name); + } + + public void addJavaExcludeLibs(List names) { + javaExcludeLibs.addAll(names); + } + + public Iterable getJavaExcludeLibs() { + return Collections.unmodifiableList(javaExcludeLibs); + } + + public void addPythonIncludePath(String path) { + pythonIncludePaths.add(path); + } + + public void addPythonIncludePaths(List paths) { + pythonIncludePaths.addAll(paths); + } + + public Iterable getPythonIncludePaths() { + return Collections.unmodifiableList(pythonIncludePaths); + } +} \ No newline at end of file diff --git a/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java b/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java index ddc30fb..10af663 100644 --- a/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java +++ b/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java @@ -20,6 +20,7 @@ import ghidra.app.script.GhidraState; import ghidra.util.Msg; import ghidrathon.interpreter.GhidrathonInterpreter; +import ghidrathon.GhidrathonConfig; public class GhidrathonConsoleInputThread extends Thread { @@ -28,8 +29,8 @@ public class GhidrathonConsoleInputThread extends Thread { private InterpreterConsole console = null; private AtomicBoolean shouldContinue = new AtomicBoolean(true); private GhidrathonInterpreter python = null; - private PrintWriter err = null; - private PrintWriter out = null; + + private final GhidrathonConfig config = new GhidrathonConfig(); GhidrathonConsoleInputThread(GhidrathonPlugin plugin) { @@ -37,8 +38,11 @@ public class GhidrathonConsoleInputThread extends Thread { this.plugin = plugin; this.console = plugin.getConsole(); - this.err = console.getErrWriter(); - this.out = console.getOutWriter(); + + // init Ghidrathon configuration + config.addStdErr(console.getErrWriter()); + config.addStdOut(console.getOutWriter()); + config.addJavaExcludeLib("pdb"); } @@ -56,7 +60,7 @@ public void run() { try { - python = GhidrathonInterpreter.get(out, err); + python = GhidrathonInterpreter.get(config); python.printWelcome(); @@ -66,7 +70,7 @@ public void run() { python.close(); } - e.printStackTrace(err); + e.printStackTrace(config.getStdErr()); return; } @@ -95,7 +99,6 @@ public void run() { continue; } - boolean moreInputWanted = evalPython(line); this.plugin.flushConsole(); diff --git a/src/main/java/ghidrathon/GhidrathonScript.java b/src/main/java/ghidrathon/GhidrathonScript.java index 0fdf576..2c50931 100644 --- a/src/main/java/ghidrathon/GhidrathonScript.java +++ b/src/main/java/ghidrathon/GhidrathonScript.java @@ -21,6 +21,7 @@ import ghidra.app.script.GhidraScriptProvider; import ghidrathon.interpreter.GhidrathonInterpreter; +import ghidrathon.GhidrathonConfig; public class GhidrathonScript extends GhidraScript { @@ -28,24 +29,27 @@ public class GhidrathonScript extends GhidraScript { protected void run() { GhidrathonInterpreter python = null; - - final PrintWriter out = getStdOut(); - final PrintWriter err = getStdErr(); + GhidrathonConfig config = new GhidrathonConfig(); + + // init Ghidrathon configuration + config.addStdOut(getStdOut()); + config.addStdErr(getStdErr()); + config.addJavaExcludeLib("pdb"); try { - python = GhidrathonInterpreter.get(out, err); + python = GhidrathonInterpreter.get(config); // run Python script from Python interpreter python.runScript(getSourceFile(), this); // flush stdout and stderr to ensure all is printed to console window - err.flush(); - out.flush(); + config.getStdErr().flush(); + config.getStdOut().flush(); } catch (RuntimeException e) { - e.printStackTrace(err); + e.printStackTrace(config.getStdErr()); } finally { @@ -68,13 +72,15 @@ protected void run() { public void runScript(String name, GhidraState scriptState) { GhidrathonInterpreter python = null; - - final PrintWriter out = getStdOut(); - final PrintWriter err = getStdErr(); + GhidrathonConfig config = new GhidrathonConfig(); + + config.addStdOut(getStdOut()); + config.addStdErr(getStdErr()); + config.addJavaExcludeLib("pdb"); try { - python = GhidrathonInterpreter.get(out, err); + python = GhidrathonInterpreter.get(config); ResourceFile source = GhidraScriptUtil.findScriptByName(name); if (source == null) { @@ -109,7 +115,7 @@ public void runScript(String name, GhidraState scriptState) { } catch (Exception e) { - e.printStackTrace(err); + e.printStackTrace(config.getStdErr()); } finally { diff --git a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java index c7321de..06d99de 100644 --- a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java +++ b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java @@ -28,20 +28,23 @@ import jep.MainInterpreter; import ghidrathon.GhidrathonScript; +import ghidrathon.GhidrathonConfig; +import ghidrathon.GhidrathonClassEnquirer; /** * Utility class used to configure a Jep instance to access Ghidra */ public class GhidrathonInterpreter { - private Jep jep; - private JepConfig config; + private Jep jep = null; + private GhidrathonConfig ghidrathonConfig = null; + + private final JepConfig jepConfig = new JepConfig(); + private final GhidrathonClassEnquirer ghidrathonClassEnquirer = new GhidrathonClassEnquirer(); private boolean scriptMethodsInjected = false; - private PrintWriter err = null; - private PrintWriter out = null; - + // extension name e.g. "Ghidrathon" private static String extname = Application.getMyModuleRootDirectory().getName(); /** @@ -50,8 +53,10 @@ public class GhidrathonInterpreter { * @throws JepException * @throws IOException */ - private GhidrathonInterpreter(PrintWriter out, PrintWriter err) throws JepException, IOException{ + private GhidrathonInterpreter(GhidrathonConfig config) throws JepException, IOException{ + ghidrathonConfig = config; + // configure the Python includes path with the user's Ghdira script directory String paths = ""; for (ResourceFile resourceFile : GhidraScriptUtil.getScriptSourceDirectories()) { @@ -61,35 +66,63 @@ private GhidrathonInterpreter(PrintWriter out, PrintWriter err) throws JepExcept // add data/python/ to Python includes directory paths += Application.getModuleDataSubDirectory(extname, "python") + File.pathSeparator; - config = new JepConfig(); + // add paths specified in Ghidrathon config + for (String path: ghidrathonConfig.getPythonIncludePaths()) { + paths += path + File.pathSeparator; + } + + // configure Java names that will be ignored when importing from Python + for (String name: ghidrathonConfig.getJavaExcludeLibs()) { + ghidrathonClassEnquirer.addJavaExcludeLib(name); + } // set the class loader with access to Ghidra scripting API - config.setClassLoader(ClassLoader.getSystemClassLoader()); + jepConfig.setClassLoader(ClassLoader.getSystemClassLoader()); + + // set class enquirer used to handle Java imports from Python + jepConfig.setClassEnquirer(ghidrathonClassEnquirer); // configure Python includes Path - config.addIncludePaths(paths); - - // configure Jep stdout and stderr - config.redirectStdout(new WriterOutputStream(out, System.getProperty("file.encoding")) { - @Override - public void write(byte[] b, int off, int len) throws IOException { - super.write(b, off, len); - flush(); // flush the output to ensure it is displayed in real-time - } - }); - config.redirectStdErr(new WriterOutputStream(err, System.getProperty("file.encoding")) { - @Override - public void write(byte[] b, int off, int len) throws IOException { - super.write(b, off, len); - flush(); // flush the error to ensure it is displayed in real-time - } - }); + jepConfig.addIncludePaths(paths); + + // add Python shared modules; necessary for Python modules that leverage the c-api e.g. numpy + for (String name: ghidrathonConfig.getPythonSharedModules()) { + jepConfig.addSharedModules(name); + } + + // configure Jep stdout + if (ghidrathonConfig.getStdOut() != null) { + jepConfig.redirectStdout(new WriterOutputStream(ghidrathonConfig.getStdOut(), System.getProperty("file.encoding")) { + + @Override + public void write(byte[] b, int off, int len) throws IOException { + super.write(b, off, len); + flush(); // flush the output to ensure it is displayed in real-time + } + + }); + } + + // configure Jep stderr + if (ghidrathonConfig.getStdErr() != null ) { + jepConfig.redirectStdErr(new WriterOutputStream(ghidrathonConfig.getStdErr(), System.getProperty("file.encoding")) { + + @Override + public void write(byte[] b, int off, int len) throws IOException { + super.write(b, off, len); + flush(); // flush the error to ensure it is displayed in real-time + } + + }); + } + + // we must set the native Jep library before creating a Jep instance setJepNativeBinaryPath(); // create a new Jep interpreter instance - jep = new jep.SubInterpreter(config); + jep = new jep.SubInterpreter(jepConfig); // now that everything is configured, we should be able to run some utility scripts // to help us further configure the Python environment @@ -224,11 +257,11 @@ private void injectScriptHierarchy(GhidraScript script) throws JepException, Fil * @return GhidrathonInterpreter * @throws RuntimeException */ - public static GhidrathonInterpreter get(PrintWriter out, PrintWriter err) throws RuntimeException { + public static GhidrathonInterpreter get(GhidrathonConfig ghidrathonConfig) throws RuntimeException { try { - return new GhidrathonInterpreter(out, err); + return new GhidrathonInterpreter(ghidrathonConfig); } catch (Exception e) { From 0adaaf3f2066a6b5fa603a9850a8d2859ab3ebae Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Mon, 24 Apr 2023 19:37:31 +0000 Subject: [PATCH 2/7] formatting changes --- .../java/ghidrathon/GhidrathonClassEnquirer.java | 12 +----------- src/main/java/ghidrathon/GhidrathonConfig.java | 4 ++-- .../ghidrathon/GhidrathonConsoleInputThread.java | 16 ++++++++++------ src/main/java/ghidrathon/GhidrathonScript.java | 6 +++--- 4 files changed, 16 insertions(+), 22 deletions(-) diff --git a/src/main/java/ghidrathon/GhidrathonClassEnquirer.java b/src/main/java/ghidrathon/GhidrathonClassEnquirer.java index 6ff8192..d9886c3 100644 --- a/src/main/java/ghidrathon/GhidrathonClassEnquirer.java +++ b/src/main/java/ghidrathon/GhidrathonClassEnquirer.java @@ -14,43 +14,33 @@ import jep.ClassList; import jep.ClassEnquirer; -public class GhidrathonClassEnquirer implements ClassEnquirer{ +public class GhidrathonClassEnquirer implements ClassEnquirer { private final List javaExcludeLibs = new ArrayList(); private final ClassEnquirer classList = ClassList.getInstance(); public void addJavaExcludeLib(String name) { - javaExcludeLibs.add(name); - } public void addJavaExcludeLibs(List names) { - javaExcludeLibs.addAll(names); - } public boolean isJavaPackage(String name) { - if (javaExcludeLibs.contains(name)) { return false; } return classList.isJavaPackage(name); - } public String[] getClassNames(String name) { - return classList.getClassNames(name); - } public String[] getSubPackages(String name) { - return classList.getSubPackages(name); - } } \ No newline at end of file diff --git a/src/main/java/ghidrathon/GhidrathonConfig.java b/src/main/java/ghidrathon/GhidrathonConfig.java index 1cdff55..b44e1a6 100644 --- a/src/main/java/ghidrathon/GhidrathonConfig.java +++ b/src/main/java/ghidrathon/GhidrathonConfig.java @@ -8,16 +8,16 @@ package ghidrathon; -import java.io.PrintWriter; import java.util.List; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collections; public class GhidrathonConfig { - private final List pythonSharedModules = new ArrayList(); private final List javaExcludeLibs = new ArrayList(); private final List pythonIncludePaths = new ArrayList(); + private final List pythonSharedModules = new ArrayList(); private PrintWriter out = null; private PrintWriter err = null; diff --git a/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java b/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java index 10af663..67f2620 100644 --- a/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java +++ b/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java @@ -8,28 +8,32 @@ package ghidrathon; -import java.io.BufferedReader; import java.io.File; +import java.io.PrintWriter; import java.io.IOException; +import java.io.BufferedReader; import java.io.InputStreamReader; -import java.io.PrintWriter; import java.util.concurrent.atomic.AtomicBoolean; import generic.jar.ResourceFile; -import ghidra.app.plugin.core.interpreter.InterpreterConsole; -import ghidra.app.script.GhidraState; + import ghidra.util.Msg; -import ghidrathon.interpreter.GhidrathonInterpreter; +import ghidra.app.script.GhidraState; +import ghidra.app.plugin.core.interpreter.InterpreterConsole; + import ghidrathon.GhidrathonConfig; +import ghidrathon.interpreter.GhidrathonInterpreter; public class GhidrathonConsoleInputThread extends Thread { private static int generationCount = 0; + private GhidrathonPlugin plugin = null; private InterpreterConsole console = null; - private AtomicBoolean shouldContinue = new AtomicBoolean(true); private GhidrathonInterpreter python = null; + private AtomicBoolean shouldContinue = new AtomicBoolean(true); + private final GhidrathonConfig config = new GhidrathonConfig(); GhidrathonConsoleInputThread(GhidrathonPlugin plugin) { diff --git a/src/main/java/ghidrathon/GhidrathonScript.java b/src/main/java/ghidrathon/GhidrathonScript.java index 2c50931..eda4ce9 100644 --- a/src/main/java/ghidrathon/GhidrathonScript.java +++ b/src/main/java/ghidrathon/GhidrathonScript.java @@ -20,8 +20,8 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.app.script.GhidraScriptProvider; -import ghidrathon.interpreter.GhidrathonInterpreter; import ghidrathon.GhidrathonConfig; +import ghidrathon.interpreter.GhidrathonInterpreter; public class GhidrathonScript extends GhidraScript { @@ -29,7 +29,7 @@ public class GhidrathonScript extends GhidraScript { protected void run() { GhidrathonInterpreter python = null; - GhidrathonConfig config = new GhidrathonConfig(); + final GhidrathonConfig config = new GhidrathonConfig(); // init Ghidrathon configuration config.addStdOut(getStdOut()); @@ -72,7 +72,7 @@ protected void run() { public void runScript(String name, GhidraState scriptState) { GhidrathonInterpreter python = null; - GhidrathonConfig config = new GhidrathonConfig(); + final GhidrathonConfig config = new GhidrathonConfig(); config.addStdOut(getStdOut()); config.addStdErr(getStdErr()); From 870a19324e7354bcceb0893b21223cf5d15c0544 Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Mon, 24 Apr 2023 23:08:19 +0000 Subject: [PATCH 3/7] adding default configuration file --- data/GhidrathonConfig.xml | 12 +++ .../java/ghidrathon/GhidrathonConfig.java | 2 +- .../GhidrathonConsoleInputThread.java | 4 +- .../java/ghidrathon/GhidrathonScript.java | 7 +- src/main/java/ghidrathon/GhidrathonUtils.java | 78 +++++++++++++++++++ 5 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 data/GhidrathonConfig.xml create mode 100644 src/main/java/ghidrathon/GhidrathonUtils.java diff --git a/data/GhidrathonConfig.xml b/data/GhidrathonConfig.xml new file mode 100644 index 0000000..401022b --- /dev/null +++ b/data/GhidrathonConfig.xml @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/src/main/java/ghidrathon/GhidrathonConfig.java b/src/main/java/ghidrathon/GhidrathonConfig.java index b44e1a6..1cb8a92 100644 --- a/src/main/java/ghidrathon/GhidrathonConfig.java +++ b/src/main/java/ghidrathon/GhidrathonConfig.java @@ -73,4 +73,4 @@ public void addPythonIncludePaths(List paths) { public Iterable getPythonIncludePaths() { return Collections.unmodifiableList(pythonIncludePaths); } -} \ No newline at end of file +} diff --git a/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java b/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java index 67f2620..e8c2524 100644 --- a/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java +++ b/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java @@ -22,6 +22,7 @@ import ghidra.app.plugin.core.interpreter.InterpreterConsole; import ghidrathon.GhidrathonConfig; +import ghidrathon.GhidrathonUtils; import ghidrathon.interpreter.GhidrathonInterpreter; public class GhidrathonConsoleInputThread extends Thread { @@ -34,7 +35,7 @@ public class GhidrathonConsoleInputThread extends Thread { private AtomicBoolean shouldContinue = new AtomicBoolean(true); - private final GhidrathonConfig config = new GhidrathonConfig(); + private final GhidrathonConfig config = GhidrathonUtils.getDefaultGhidrathonConfig(); GhidrathonConsoleInputThread(GhidrathonPlugin plugin) { @@ -46,7 +47,6 @@ public class GhidrathonConsoleInputThread extends Thread { // init Ghidrathon configuration config.addStdErr(console.getErrWriter()); config.addStdOut(console.getOutWriter()); - config.addJavaExcludeLib("pdb"); } diff --git a/src/main/java/ghidrathon/GhidrathonScript.java b/src/main/java/ghidrathon/GhidrathonScript.java index eda4ce9..9ad4314 100644 --- a/src/main/java/ghidrathon/GhidrathonScript.java +++ b/src/main/java/ghidrathon/GhidrathonScript.java @@ -21,6 +21,7 @@ import ghidra.app.script.GhidraScriptProvider; import ghidrathon.GhidrathonConfig; +import ghidrathon.GhidrathonUtils; import ghidrathon.interpreter.GhidrathonInterpreter; public class GhidrathonScript extends GhidraScript { @@ -29,12 +30,11 @@ public class GhidrathonScript extends GhidraScript { protected void run() { GhidrathonInterpreter python = null; - final GhidrathonConfig config = new GhidrathonConfig(); + GhidrathonConfig config = GhidrathonUtils.getDefaultGhidrathonConfig(); // init Ghidrathon configuration config.addStdOut(getStdOut()); config.addStdErr(getStdErr()); - config.addJavaExcludeLib("pdb"); try { @@ -72,11 +72,10 @@ protected void run() { public void runScript(String name, GhidraState scriptState) { GhidrathonInterpreter python = null; - final GhidrathonConfig config = new GhidrathonConfig(); + GhidrathonConfig config = GhidrathonUtils.getDefaultGhidrathonConfig(); config.addStdOut(getStdOut()); config.addStdErr(getStdErr()); - config.addJavaExcludeLib("pdb"); try { diff --git a/src/main/java/ghidrathon/GhidrathonUtils.java b/src/main/java/ghidrathon/GhidrathonUtils.java new file mode 100644 index 0000000..32867cc --- /dev/null +++ b/src/main/java/ghidrathon/GhidrathonUtils.java @@ -0,0 +1,78 @@ +// Copyright (C) 2022 Mandiant, Inc. All Rights Reserved. +// 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: [package root]/LICENSE.txt +// 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 ghidrathon; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; + +import ghidra.util.Msg; +import ghidra.framework.Application; +import ghidra.framework.options.SaveState; + +import ghidrathon.GhidrathonConfig; + +public class GhidrathonUtils { + + private static String defaultConfigFilename = "GhidrathonConfig.xml"; + private static String javaExcludeLibsKey = "JAVA_EXCLUDE_LIBS"; + private static String pythonSharedModulesKey = "PYTHON_SHARED_MODULES"; + private static String pythonIncludePathsKey = "PYTHON_INCLUDE_PATHS"; + + // extension name e.g. "Ghidrathon" + private static String extname = Application.getMyModuleRootDirectory().getName(); + + public static GhidrathonConfig getDefaultGhidrathonConfig() { + + GhidrathonConfig config = new GhidrathonConfig(); + + File userConfigPath = new File(Application.getUserSettingsDirectory(), defaultConfigFilename); + + if (!userConfigPath.isFile()) { + Msg.info(GhidrathonUtils.class, "adding configuration to user settings at " + userConfigPath); + + // user configuration does not exist, copy default to user settings directory + try { + + File defaultConfigPath = Application.getModuleDataFile(extname, defaultConfigFilename).getFile(false); + Files.copy(defaultConfigPath.toPath(), userConfigPath.toPath(), StandardCopyOption.REPLACE_EXISTING); + + } catch (IOException e) { + + Msg.error(GhidrathonUtils.class, "failed to write user configuration [" + e + "]"); + return config; + + } + } + + SaveState state = null; + try { + state = new SaveState(userConfigPath); + } catch (IOException e) { + Msg.error(GhidrathonUtils.class, "failed to read configuration state [" + e + "]"); + return config; + } + + for (String name: state.getStrings(javaExcludeLibsKey, new String[0])) { + config.addJavaExcludeLib(name); + } + + for (String name: state.getStrings(pythonIncludePathsKey, new String[0])) { + config.addPythonIncludePath(name); + } + + for (String name: state.getStrings(pythonSharedModulesKey, new String[0])) { + config.addPythonSharedModule(name); + } + + return config; + } + +} From dc679b215a97c43e995a3af96e4551e757913ee4 Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Mon, 24 Apr 2023 23:12:02 +0000 Subject: [PATCH 4/7] formatting changes --- src/main/java/ghidrathon/GhidrathonClassEnquirer.java | 2 +- src/main/java/ghidrathon/GhidrathonConsoleInputThread.java | 2 +- src/main/java/ghidrathon/GhidrathonScript.java | 2 +- src/main/java/ghidrathon/GhidrathonUtils.java | 4 ---- 4 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/main/java/ghidrathon/GhidrathonClassEnquirer.java b/src/main/java/ghidrathon/GhidrathonClassEnquirer.java index d9886c3..eb58a02 100644 --- a/src/main/java/ghidrathon/GhidrathonClassEnquirer.java +++ b/src/main/java/ghidrathon/GhidrathonClassEnquirer.java @@ -43,4 +43,4 @@ public String[] getSubPackages(String name) { return classList.getSubPackages(name); } -} \ No newline at end of file +} diff --git a/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java b/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java index e8c2524..317208c 100644 --- a/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java +++ b/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java @@ -21,8 +21,8 @@ import ghidra.app.script.GhidraState; import ghidra.app.plugin.core.interpreter.InterpreterConsole; -import ghidrathon.GhidrathonConfig; import ghidrathon.GhidrathonUtils; +import ghidrathon.GhidrathonConfig; import ghidrathon.interpreter.GhidrathonInterpreter; public class GhidrathonConsoleInputThread extends Thread { diff --git a/src/main/java/ghidrathon/GhidrathonScript.java b/src/main/java/ghidrathon/GhidrathonScript.java index 9ad4314..b64a02c 100644 --- a/src/main/java/ghidrathon/GhidrathonScript.java +++ b/src/main/java/ghidrathon/GhidrathonScript.java @@ -20,8 +20,8 @@ import ghidra.framework.plugintool.PluginTool; import ghidra.app.script.GhidraScriptProvider; -import ghidrathon.GhidrathonConfig; import ghidrathon.GhidrathonUtils; +import ghidrathon.GhidrathonConfig; import ghidrathon.interpreter.GhidrathonInterpreter; public class GhidrathonScript extends GhidraScript { diff --git a/src/main/java/ghidrathon/GhidrathonUtils.java b/src/main/java/ghidrathon/GhidrathonUtils.java index 32867cc..d0f8543 100644 --- a/src/main/java/ghidrathon/GhidrathonUtils.java +++ b/src/main/java/ghidrathon/GhidrathonUtils.java @@ -40,15 +40,11 @@ public static GhidrathonConfig getDefaultGhidrathonConfig() { // user configuration does not exist, copy default to user settings directory try { - File defaultConfigPath = Application.getModuleDataFile(extname, defaultConfigFilename).getFile(false); Files.copy(defaultConfigPath.toPath(), userConfigPath.toPath(), StandardCopyOption.REPLACE_EXISTING); - } catch (IOException e) { - Msg.error(GhidrathonUtils.class, "failed to write user configuration [" + e + "]"); return config; - } } From 3acfe2d5c504d0d934662f867772e01a9e1cbe50 Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Tue, 25 Apr 2023 15:52:54 +0000 Subject: [PATCH 5/7] adding comments and unit tests --- data/python/tests/test_cpython.py | 26 ++++++++ data/python/tests/test_jepbridge.py | 10 +++ .../ghidrathon/GhidrathonClassEnquirer.java | 14 ++++ .../java/ghidrathon/GhidrathonConfig.java | 25 +++++--- src/main/java/ghidrathon/GhidrathonUtils.java | 64 +++++++++++++------ .../interpreter/GhidrathonInterpreter.java | 32 ++++++---- 6 files changed, 133 insertions(+), 38 deletions(-) create mode 100644 data/python/tests/test_cpython.py diff --git a/data/python/tests/test_cpython.py b/data/python/tests/test_cpython.py new file mode 100644 index 0000000..c4cf4c8 --- /dev/null +++ b/data/python/tests/test_cpython.py @@ -0,0 +1,26 @@ +# Copyright (C) 2022 Mandiant, Inc. All Rights Reserved. +# 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: [package root]/LICENSE.txt +# 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. + +"""Unit tests to verify CPython modules + +Note: you must run these tests from the Ghidra script manager or headless mode +""" + +import unittest +import warnings + + +class TestCPython(unittest.TestCase): + def test_numpy(self): + try: + import numpy + + a = numpy.array(["cat", "dog"]) + except ImportError: + warnings.warn("numpy module is not installed - ignoring test") + pass diff --git a/data/python/tests/test_jepbridge.py b/data/python/tests/test_jepbridge.py index 30d7f40..8ecb3de 100644 --- a/data/python/tests/test_jepbridge.py +++ b/data/python/tests/test_jepbridge.py @@ -21,6 +21,12 @@ def assertIsJavaObject(self, o): if not (o is None or isinstance(o, Object)): raise AssertionError("Object %s is not valid" % str(o)) + def assertIsNotJavaObject(self, o): + from java.lang import Object + + if o is not None and isinstance(o, Object): + raise AssertionError("Object %s is not valid" % str(o)) + def test_type_instance(self): # see Jep: https://github.com/ninia/jep/blob/15e36a7ba54eb7d8f7ffd85f16675fa4fd54eb1d/src/test/python/test_import.py#L54-L65 from java.lang import Object @@ -46,3 +52,7 @@ def test_ghidra_script_variables(self): def test_ghidra_script_methods(self): self.assertIsInstance(getGhidraVersion(), str) + + def test_java_excluded_packages(self): + import pdb + self.assertIsNotJavaObject(pdb) diff --git a/src/main/java/ghidrathon/GhidrathonClassEnquirer.java b/src/main/java/ghidrathon/GhidrathonClassEnquirer.java index eb58a02..df5a68a 100644 --- a/src/main/java/ghidrathon/GhidrathonClassEnquirer.java +++ b/src/main/java/ghidrathon/GhidrathonClassEnquirer.java @@ -14,33 +14,47 @@ import jep.ClassList; import jep.ClassEnquirer; +/** + * Implments Jep ClassEnquirer used to handle Java imports from Python - specifically we + * use this class to handle naming conflicts, e.g. pdb + */ public class GhidrathonClassEnquirer implements ClassEnquirer { private final List javaExcludeLibs = new ArrayList(); private final ClassEnquirer classList = ClassList.getInstance(); public void addJavaExcludeLib(String name) { + javaExcludeLibs.add(name); + } public void addJavaExcludeLibs(List names) { + javaExcludeLibs.addAll(names); + } public boolean isJavaPackage(String name) { + if (javaExcludeLibs.contains(name)) { return false; } return classList.isJavaPackage(name); + } public String[] getClassNames(String name) { + return classList.getClassNames(name); + } public String[] getSubPackages(String name) { + return classList.getSubPackages(name); + } } diff --git a/src/main/java/ghidrathon/GhidrathonConfig.java b/src/main/java/ghidrathon/GhidrathonConfig.java index 1cb8a92..d3ae56a 100644 --- a/src/main/java/ghidrathon/GhidrathonConfig.java +++ b/src/main/java/ghidrathon/GhidrathonConfig.java @@ -13,11 +13,20 @@ import java.util.ArrayList; import java.util.Collections; +/** + * Ghidrathon's configuration class + * + * Stores + * - stdout and stderr + * - Python modules to handle as shared modules - relevant to CPython modules + * - Java package names to exclude from Python imports + * - Python include paths to add to Python interpreter environment + */ public class GhidrathonConfig { private final List javaExcludeLibs = new ArrayList(); - private final List pythonIncludePaths = new ArrayList(); - private final List pythonSharedModules = new ArrayList(); + private final List pyIncludePaths = new ArrayList(); + private final List pySharedModules = new ArrayList(); private PrintWriter out = null; private PrintWriter err = null; @@ -39,15 +48,15 @@ public PrintWriter getStdErr() { } public void addPythonSharedModule(String name) { - pythonSharedModules.add(name); + pySharedModules.add(name); } public void addPythonSharedModules(List names) { - pythonSharedModules.addAll(names); + pySharedModules.addAll(names); } public Iterable getPythonSharedModules() { - return Collections.unmodifiableList(pythonSharedModules); + return Collections.unmodifiableList(pySharedModules); } public void addJavaExcludeLib(String name) { @@ -63,14 +72,14 @@ public Iterable getJavaExcludeLibs() { } public void addPythonIncludePath(String path) { - pythonIncludePaths.add(path); + pyIncludePaths.add(path); } public void addPythonIncludePaths(List paths) { - pythonIncludePaths.addAll(paths); + pyIncludePaths.addAll(paths); } public Iterable getPythonIncludePaths() { - return Collections.unmodifiableList(pythonIncludePaths); + return Collections.unmodifiableList(pyIncludePaths); } } diff --git a/src/main/java/ghidrathon/GhidrathonUtils.java b/src/main/java/ghidrathon/GhidrathonUtils.java index d0f8543..d470501 100644 --- a/src/main/java/ghidrathon/GhidrathonUtils.java +++ b/src/main/java/ghidrathon/GhidrathonUtils.java @@ -19,53 +19,81 @@ import ghidrathon.GhidrathonConfig; +/** + * Utility functions + */ public class GhidrathonUtils { - private static String defaultConfigFilename = "GhidrathonConfig.xml"; - private static String javaExcludeLibsKey = "JAVA_EXCLUDE_LIBS"; - private static String pythonSharedModulesKey = "PYTHON_SHARED_MODULES"; - private static String pythonIncludePathsKey = "PYTHON_INCLUDE_PATHS"; - - // extension name e.g. "Ghidrathon" - private static String extname = Application.getMyModuleRootDirectory().getName(); + // name of this extension e.g. "Ghidrathon" + public static final String THIS_EXTENSION_NAME = Application.getMyModuleRootDirectory().getName(); + private static final String DEFAULT_CONFIG_FILENAME = "GhidrathonConfig.xml"; + private static final String JAVA_EXCLUDE_LIBS_KEY = "JAVA_EXCLUDE_LIBS"; + private static final String PY_SHARED_MODULES_KEY = "PYTHON_SHARED_MODULES"; + private static final String PY_INCLUDE_PATHS_KEY = "PYTHON_INCLUDE_PATHS"; + + /** + * Get Ghidrathon's default configuration - default configuration is stored in data and copied to Ghidra user + * settings directory when first accessed + */ public static GhidrathonConfig getDefaultGhidrathonConfig() { GhidrathonConfig config = new GhidrathonConfig(); + File userSettingsPath = new File(Application.getUserSettingsDirectory(), DEFAULT_CONFIG_FILENAME); - File userConfigPath = new File(Application.getUserSettingsDirectory(), defaultConfigFilename); + // copy configuration from /data to Ghidra user settings if file does not already exist + if (!userSettingsPath.isFile()) { - if (!userConfigPath.isFile()) { - Msg.info(GhidrathonUtils.class, "adding configuration to user settings at " + userConfigPath); + Msg.info(GhidrathonUtils.class, "Addings configuration to user settings at " + userSettingsPath); - // user configuration does not exist, copy default to user settings directory try { - File defaultConfigPath = Application.getModuleDataFile(extname, defaultConfigFilename).getFile(false); - Files.copy(defaultConfigPath.toPath(), userConfigPath.toPath(), StandardCopyOption.REPLACE_EXISTING); + + File dataPath = Application.getModuleDataFile(THIS_EXTENSION_NAME, DEFAULT_CONFIG_FILENAME).getFile(false); + Files.copy(dataPath.toPath(), userSettingsPath.toPath(), StandardCopyOption.REPLACE_EXISTING); + } catch (IOException e) { - Msg.error(GhidrathonUtils.class, "failed to write user configuration [" + e + "]"); + + Msg.error(GhidrathonUtils.class, "Failed to write user configuration [" + e + "]"); return config; + } } SaveState state = null; + + // attempt to read configuration from Ghidra user settings try { - state = new SaveState(userConfigPath); + + state = new SaveState(userSettingsPath); + } catch (IOException e) { + Msg.error(GhidrathonUtils.class, "failed to read configuration state [" + e + "]"); return config; + } - for (String name: state.getStrings(javaExcludeLibsKey, new String[0])) { + // add Java exclude libs that will be ignored when importing from Python - this is used to avoid + // naming conflicts, e.g. "pdb" + for (String name: state.getStrings(JAVA_EXCLUDE_LIBS_KEY, new String[0])) { + config.addJavaExcludeLib(name); + } - for (String name: state.getStrings(pythonIncludePathsKey, new String[0])) { + // add Python include paths + for (String name: state.getStrings(PY_INCLUDE_PATHS_KEY, new String[0])) { + config.addPythonIncludePath(name); + } - for (String name: state.getStrings(pythonSharedModulesKey, new String[0])) { + // add Python shared modules - these modules are handled specially by Jep to avoid crashes caused + // by CPython extensions, e.g. numpy + for (String name: state.getStrings(PY_SHARED_MODULES_KEY, new String[0])) { + config.addPythonSharedModule(name); + } return config; diff --git a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java index 06d99de..eed15ab 100644 --- a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java +++ b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java @@ -27,6 +27,7 @@ import jep.JepException; import jep.MainInterpreter; +import ghidrathon.GhidrathonUtils; import ghidrathon.GhidrathonScript; import ghidrathon.GhidrathonConfig; import ghidrathon.GhidrathonClassEnquirer; @@ -43,9 +44,6 @@ public class GhidrathonInterpreter { private final GhidrathonClassEnquirer ghidrathonClassEnquirer = new GhidrathonClassEnquirer(); private boolean scriptMethodsInjected = false; - - // extension name e.g. "Ghidrathon" - private static String extname = Application.getMyModuleRootDirectory().getName(); /** * Create and configure a new GhidrathonInterpreter instance. @@ -60,20 +58,26 @@ private GhidrathonInterpreter(GhidrathonConfig config) throws JepException, IOEx // configure the Python includes path with the user's Ghdira script directory String paths = ""; for (ResourceFile resourceFile : GhidraScriptUtil.getScriptSourceDirectories()) { + paths += resourceFile.getFile(false).getAbsolutePath() + File.pathSeparator; + } // add data/python/ to Python includes directory - paths += Application.getModuleDataSubDirectory(extname, "python") + File.pathSeparator; + paths += Application.getModuleDataSubDirectory(GhidrathonUtils.THIS_EXTENSION_NAME, "python") + File.pathSeparator; // add paths specified in Ghidrathon config for (String path: ghidrathonConfig.getPythonIncludePaths()) { + paths += path + File.pathSeparator; + } // configure Java names that will be ignored when importing from Python for (String name: ghidrathonConfig.getJavaExcludeLibs()) { + ghidrathonClassEnquirer.addJavaExcludeLib(name); + } // set the class loader with access to Ghidra scripting API @@ -85,13 +89,16 @@ private GhidrathonInterpreter(GhidrathonConfig config) throws JepException, IOEx // configure Python includes Path jepConfig.addIncludePaths(paths); - // add Python shared modules; necessary for Python modules that leverage the c-api e.g. numpy + // add Python shared modules - these should be CPython modules for Jep to handle specially for (String name: ghidrathonConfig.getPythonSharedModules()) { + jepConfig.addSharedModules(name); + } // configure Jep stdout if (ghidrathonConfig.getStdOut() != null) { + jepConfig.redirectStdout(new WriterOutputStream(ghidrathonConfig.getStdOut(), System.getProperty("file.encoding")) { @Override @@ -114,6 +121,7 @@ public void write(byte[] b, int off, int len) throws IOException { } }); + } @@ -148,12 +156,12 @@ private void setJepNativeBinaryPath() throws JepException, FileNotFoundException try { - nativeJep = Application.getOSFile(extname, "libjep.so"); + nativeJep = Application.getOSFile(GhidrathonUtils.THIS_EXTENSION_NAME, "libjep.so"); } catch (FileNotFoundException e) { // whoops try Windows - nativeJep = Application.getOSFile(extname, "jep.dll"); + nativeJep = Application.getOSFile(GhidrathonUtils.THIS_EXTENSION_NAME, "jep.dll"); } @@ -181,7 +189,7 @@ private void setJepNativeBinaryPath() throws JepException, FileNotFoundException */ private void setJepEval() throws JepException, FileNotFoundException { - ResourceFile file = Application.getModuleDataFile(extname, "python/jepeval.py"); + ResourceFile file = Application.getModuleDataFile(GhidrathonUtils.THIS_EXTENSION_NAME, "python/jepeval.py"); jep.runScript(file.getAbsolutePath()); @@ -198,7 +206,7 @@ private void setJepEval() throws JepException, FileNotFoundException { */ private void setJepRunScript() throws JepException, FileNotFoundException { - ResourceFile file = Application.getModuleDataFile(extname, "python/jeprunscript.py"); + ResourceFile file = Application.getModuleDataFile(GhidrathonUtils.THIS_EXTENSION_NAME, "python/jeprunscript.py"); jep.runScript(file.getAbsolutePath()); @@ -220,7 +228,7 @@ private void injectScriptHierarchy(GhidraScript script) throws JepException, Fil return; } - ResourceFile file = Application.getModuleDataFile(extname, "python/jepbuiltins.py"); + ResourceFile file = Application.getModuleDataFile(GhidrathonUtils.THIS_EXTENSION_NAME, "python/jepbuiltins.py"); jep.runScript(file.getAbsolutePath()); // inject GhidraScript public/private fields e.g. currentAddress into Python @@ -243,7 +251,7 @@ private void injectScriptHierarchy(GhidraScript script) throws JepException, Fil if (!scriptMethodsInjected) { // inject GhidraScript methods into Python - file = Application.getModuleDataFile(extname, "python/jepinject.py"); + file = Application.getModuleDataFile(GhidrathonUtils.THIS_EXTENSION_NAME, "python/jepinject.py"); jep.set("__ghidra_script__", script); jep.runScript(file.getAbsolutePath()); } @@ -435,7 +443,7 @@ public void printWelcome() { try { - ResourceFile file = Application.getModuleDataFile(extname, "python/jepwelcome.py"); + ResourceFile file = Application.getModuleDataFile(GhidrathonUtils.THIS_EXTENSION_NAME, "python/jepwelcome.py"); jep.set("GhidraVersion", Application.getApplicationVersion()); From 51bc51d15393fadcac8d1c166de6361b943e92cd Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Tue, 25 Apr 2023 16:04:27 +0000 Subject: [PATCH 6/7] minor formatting changes --- .../java/ghidrathon/GhidrathonClassEnquirer.java | 12 +----------- .../ghidrathon/GhidrathonConsoleInputThread.java | 3 +-- src/main/java/ghidrathon/GhidrathonUtils.java | 4 ++-- 3 files changed, 4 insertions(+), 15 deletions(-) diff --git a/src/main/java/ghidrathon/GhidrathonClassEnquirer.java b/src/main/java/ghidrathon/GhidrathonClassEnquirer.java index df5a68a..09fa0f8 100644 --- a/src/main/java/ghidrathon/GhidrathonClassEnquirer.java +++ b/src/main/java/ghidrathon/GhidrathonClassEnquirer.java @@ -15,7 +15,7 @@ import jep.ClassEnquirer; /** - * Implments Jep ClassEnquirer used to handle Java imports from Python - specifically we + * Implements Jep ClassEnquirer used to handle Java imports from Python - specifically we * use this class to handle naming conflicts, e.g. pdb */ public class GhidrathonClassEnquirer implements ClassEnquirer { @@ -24,37 +24,27 @@ public class GhidrathonClassEnquirer implements ClassEnquirer { private final ClassEnquirer classList = ClassList.getInstance(); public void addJavaExcludeLib(String name) { - javaExcludeLibs.add(name); - } public void addJavaExcludeLibs(List names) { - javaExcludeLibs.addAll(names); - } public boolean isJavaPackage(String name) { - if (javaExcludeLibs.contains(name)) { return false; } return classList.isJavaPackage(name); - } public String[] getClassNames(String name) { - return classList.getClassNames(name); - } public String[] getSubPackages(String name) { - return classList.getSubPackages(name); - } } diff --git a/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java b/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java index 317208c..7217852 100644 --- a/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java +++ b/src/main/java/ghidrathon/GhidrathonConsoleInputThread.java @@ -34,8 +34,7 @@ public class GhidrathonConsoleInputThread extends Thread { private GhidrathonInterpreter python = null; private AtomicBoolean shouldContinue = new AtomicBoolean(true); - - private final GhidrathonConfig config = GhidrathonUtils.getDefaultGhidrathonConfig(); + private GhidrathonConfig config = GhidrathonUtils.getDefaultGhidrathonConfig(); GhidrathonConsoleInputThread(GhidrathonPlugin plugin) { diff --git a/src/main/java/ghidrathon/GhidrathonUtils.java b/src/main/java/ghidrathon/GhidrathonUtils.java index d470501..f68fcad 100644 --- a/src/main/java/ghidrathon/GhidrathonUtils.java +++ b/src/main/java/ghidrathon/GhidrathonUtils.java @@ -33,7 +33,7 @@ public class GhidrathonUtils { private static final String PY_INCLUDE_PATHS_KEY = "PYTHON_INCLUDE_PATHS"; /** - * Get Ghidrathon's default configuration - default configuration is stored in data and copied to Ghidra user + * Get Ghidrathon's default configuration - default configuration is stored in data/ and copied to Ghidra user * settings directory when first accessed */ public static GhidrathonConfig getDefaultGhidrathonConfig() { @@ -68,7 +68,7 @@ public static GhidrathonConfig getDefaultGhidrathonConfig() { } catch (IOException e) { - Msg.error(GhidrathonUtils.class, "failed to read configuration state [" + e + "]"); + Msg.error(GhidrathonUtils.class, "Failed to read configuration state [" + e + "]"); return config; } From 085b4e37074601a02bbdae94ed38af0c10052801 Mon Sep 17 00:00:00 2001 From: Mike Hunhoff Date: Tue, 25 Apr 2023 16:07:42 +0000 Subject: [PATCH 7/7] updating unit tests --- data/python/tests/test_jepbridge.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/data/python/tests/test_jepbridge.py b/data/python/tests/test_jepbridge.py index 8ecb3de..ff31581 100644 --- a/data/python/tests/test_jepbridge.py +++ b/data/python/tests/test_jepbridge.py @@ -24,7 +24,7 @@ def assertIsJavaObject(self, o): def assertIsNotJavaObject(self, o): from java.lang import Object - if o is not None and isinstance(o, Object): + if isinstance(o, Object): raise AssertionError("Object %s is not valid" % str(o)) def test_type_instance(self): @@ -55,4 +55,5 @@ def test_ghidra_script_methods(self): def test_java_excluded_packages(self): import pdb + self.assertIsNotJavaObject(pdb)