From 0f9d1de71875298ef518a39302d7183f387c86a2 Mon Sep 17 00:00:00 2001 From: William Ballenthin Date: Tue, 13 Jun 2023 16:13:29 +0200 Subject: [PATCH 1/5] wip: use JEP from pip installation --- build.gradle | 31 --- .../interpreter/GhidrathonInterpreter.java | 213 ++++++++++++++++-- 2 files changed, 194 insertions(+), 50 deletions(-) diff --git a/build.gradle b/build.gradle index 59b952f..d4d8d19 100644 --- a/build.gradle +++ b/build.gradle @@ -22,37 +22,6 @@ // application.gradle.version property in /Ghidra/application.properties // for the correction version of Gradle to use for the Ghidra installation you specify. -def javaHome -def pythonBin - -if (project.hasProperty("PYTHON_BIN")) { - pythonBin = project.getProperty("PYTHON_BIN") -} -else { - pythonBin = "python" -} - -// we need to install Jep; this requires C++ build tools on Windows (see README); we need to define -// the env variable "JAVA_HOME" containing absolute path to Java JDK configured for Ghidra -task installJep(type: Exec) { - environment "JAVA_HOME", System.getProperty("java.home") - commandLine pythonBin, '-m', 'pip', 'install', 'jep' -} - -// we need to copy the Jep native binaries built in installJep to our extension directory; we use a small -// utility script written in Python -task copyJepNativeBinaries(type: Exec) { - dependsOn installJep - workingDir "${projectDir}" - commandLine pythonBin, "util${File.separator}configure_jep_native_binaries.py" -} - -// make all tasks not matching copyJepNativeBinaries or installJep depend on copyJepNativeBinaries; mostly -// used to ensure our tasks run before Ghidra buildExtension task -tasks.matching { it.name != 'copyJepNativeBinaries' && it.name != 'installJep' }.all { Task task -> - task.dependsOn copyJepNativeBinaries -} - // from here we use the standard Gradle build provided by Ghidra framework //----------------------START "DO NOT MODIFY" SECTION------------------------------ diff --git a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java index bc4b4e7..b7b28be 100644 --- a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java +++ b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java @@ -10,6 +10,19 @@ package ghidrathon.interpreter; +import java.io.BufferedReader; +import java.io.IOException; +import java.nio.charset.Charset; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; +import java.util.stream.Stream; + + import generic.jar.ResourceFile; import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScriptUtil; @@ -26,6 +39,7 @@ import jep.JepConfig; import jep.JepException; import jep.MainInterpreter; +import jep.PyConfig; import org.apache.commons.io.output.WriterOutputStream; /** Utility class used to configure a Jep instance to access Ghidra */ @@ -118,7 +132,7 @@ public void write(byte[] b, int off, int len) throws IOException { } // we must set the native Jep library before creating a Jep instance - setJepNativeBinaryPath(); + setJepPaths(); // create a new Jep interpreter instance jep = new jep.SubInterpreter(jepConfig); @@ -129,6 +143,159 @@ public void write(byte[] b, int off, int len) throws IOException { setJepRunScript(); } + private record JepLocation (Path dll, Path home) {}; + + private PathMatcher getJepDllPathMatcher() throws Exception { + String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); + if ((os.indexOf("mac") >= 0) || (os.indexOf("darwin") >= 0)) { + String arch = System.getProperty("os.arch"); + if (arch == "amd64") { + // x86 + return FileSystems.getDefault().getPathMatcher("glob:**libjep.so"); + } else if (arch == "arm64") { + // arm m1 + // TODO: just guessing this arch name arm64 + return FileSystems.getDefault().getPathMatcher("glob:**libjep.jnilib"); + } + } else if (os.indexOf("win") >= 0) { + return FileSystems.getDefault().getPathMatcher("glob:**jep.dll"); + } else if (os.indexOf("nux") >= 0) { + return FileSystems.getDefault().getPathMatcher("glob:**libjep.so"); + } else { + throw new Exception("OS not implemented: " + os); + } + + throw new Exception("OS not implemented: " + os); + } + + private JepLocation searchJep(Path path) { + JepLocation empty = new JepLocation(null, null); + + PathMatcher matcher; + try { + matcher = getJepDllPathMatcher(); + } catch (Exception e) { + return empty; + } + + List dllPaths; + try (Stream walk = Files.walk(path)) { + dllPaths = walk + .filter(Files::isRegularFile) + .filter(x -> matcher.matches(x)) + .collect(Collectors.toList()); + + } catch (IOException e) { + return empty; + } + + if (dllPaths.isEmpty()) { + return empty; + } + + if (dllPaths.size() > 1) { + // not sure which to pick + System.err.println("too many results in directory: " + path.toString()); + return empty; + } + + Path dll = dllPaths.stream().findFirst().get(); + return new JepLocation(dll, path); + } + + // DANGER: DO NOT PASS DYNAMIC COMMANDS HERE! + private String execCmd(String ... commands) { + Runtime runtime = Runtime.getRuntime(); + Process process = null; + try { + process = runtime.exec(commands); + } catch (IOException e) { + System.err.println("error: " + e.toString()); + return ""; + } + + BufferedReader lineReader = new BufferedReader(new java.io.InputStreamReader(process.getInputStream())); + String output = String.join("\n", lineReader.lines().collect(Collectors.toList())); + + BufferedReader errorReader = new BufferedReader(new java.io.InputStreamReader(process.getErrorStream())); + String error = String.join("\n", errorReader.lines().collect(Collectors.toList())); + + if (error.length() > 0) { + System.err.println(">" + error + "<"); + } + + return output; + } + + private JepLocation findPythonPathJep() { + String var = "PYTHONPATH"; + String env = System.getenv(var); + if (env != null) { + for (String envv : env.split(";")) { + Path path = java.nio.file.FileSystems.getDefault().getPath(envv); + JepLocation location = searchJep(path); + if (location.dll() != null) { + // return first matching DLL + return location; + } + } + } + return new JepLocation(null, null); + } + + private JepLocation findVirtualEnvJep() { + String var = "VIRTUAL_ENV"; + String env = System.getenv(var); + if (env != null) { + Path path = java.nio.file.FileSystems.getDefault().getPath(env); + JepLocation location = searchJep(path); + if (location.dll() != null) { + // return only matching DLL + return location; + } + } + return new JepLocation(null, null); + } + + private JepLocation findSystemJep() { + String output = execCmd("python3", "-c", "import sys; import base64; print((b' '.join(map(lambda s: base64.b64encode(s.encode('utf-8')), sys.path))).decode('ascii'))"); + + Charset UTF8_CHARSET = Charset.forName("UTF-8"); + + for (String base64 : output.split(" ")) { + byte[] bytes = java.util.Base64.getDecoder().decode(base64); + String s = new String(bytes, UTF8_CHARSET); + + Path path1 = java.nio.file.FileSystems.getDefault().getPath(s); + JepLocation location = searchJep(path1); + + if (location.dll() != null) { + // we don't know the PYTHONHOME from just this info + return new JepLocation(location.dll(), null); + } + } + + return new JepLocation(null, null); + } + + private void setJepDll(Path path) { + System.err.println("set JEP DLL: " + path.toString()); + try { + MainInterpreter.setJepLibraryPath(path.toAbsolutePath().toString()); + } catch (IllegalStateException e) { + // library path has already been set elsewhere, + // we expect this to happen as Jep Maininterpreter + // thread exists forever once it's created + } + } + + private void setJepPythonHome(Path path) { + System.err.println("set Python home: " + path.toString()); + PyConfig pyConfig = new PyConfig(); + pyConfig.setPythonHome(path.toAbsolutePath().toString()); + MainInterpreter.setInitParams(pyConfig); + } + /** * Configure native Jep library. * @@ -139,28 +306,36 @@ public void write(byte[] b, int off, int len) throws IOException { * @throws JepException * @throws FileNotFoundException */ - private void setJepNativeBinaryPath() throws JepException, FileNotFoundException { - - File nativeJep; - - try { - - nativeJep = Application.getOSFile(GhidrathonUtils.THIS_EXTENSION_NAME, "libjep.so"); - - } catch (FileNotFoundException e) { - - // whoops try Windows - nativeJep = Application.getOSFile(GhidrathonUtils.THIS_EXTENSION_NAME, "jep.dll"); + private void setJepPaths() throws JepException, FileNotFoundException { + // if this is set, it take precedence over VIRTUAL_ENV. + JepLocation pythonPathJep = findPythonPathJep(); + if (pythonPathJep.dll() != null) { + System.out.println("found JEP dll via PYTHONPATH: " + pythonPathJep.dll()); } - try { + // if this is set, it takes precedence over system python + JepLocation virtualenvJep = findVirtualEnvJep(); + if (virtualenvJep.dll() != null) { + System.out.println("found JEP dll via VIRTUAL_ENV: " + virtualenvJep.dll()); + } - MainInterpreter.setJepLibraryPath(nativeJep.getAbsolutePath()); + // fall back to whatever python3 references + JepLocation systemJep = findSystemJep(); + if (systemJep.dll() != null) { + System.out.println("found JEP dll via python3: " + systemJep.dll()); + } - } catch (IllegalStateException e) { - // library path has already been set elsewhere, we expect this to happen as Jep - // Maininterpreter - // thread exists forever once it's created + if (pythonPathJep.dll() != null) { + setJepDll(pythonPathJep.dll()); + setJepPythonHome(pythonPathJep.home()); + } else if (virtualenvJep.dll() != null) { + setJepDll(virtualenvJep.dll()); + setJepPythonHome(virtualenvJep.home()); + } else if (systemJep.dll() != null) { + setJepDll(systemJep.dll()); + // we don't know home! + } else { + System.out.println("unable to find jep"); } } From c9daa629ba4bf64a270d0fb768e33a9c06745f4d Mon Sep 17 00:00:00 2001 From: William Ballenthin Date: Tue, 13 Jun 2023 16:54:31 +0200 Subject: [PATCH 2/5] interpreter: find JEP DLL from existing python installation --- .../interpreter/GhidrathonInterpreter.java | 240 +++++++++--------- 1 file changed, 123 insertions(+), 117 deletions(-) diff --git a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java index b7b28be..202b3d3 100644 --- a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java +++ b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java @@ -42,8 +42,13 @@ import jep.PyConfig; import org.apache.commons.io.output.WriterOutputStream; +import org.apache.logging.log4j.Logger; +import org.apache.logging.log4j.LogManager; + + /** Utility class used to configure a Jep instance to access Ghidra */ public class GhidrathonInterpreter { + static final Logger log = LogManager.getLogger(GhidrathonInterpreter.class); private Jep jep = null; private GhidrathonConfig ghidrathonConfig = null; @@ -60,91 +65,106 @@ public class GhidrathonInterpreter { * @throws IOException */ private GhidrathonInterpreter(GhidrathonConfig config) throws JepException, IOException { + log.info("GhidrathonInterpreter constructor 1"); - ghidrathonConfig = config; + try { + ghidrathonConfig = config; - // configure the Python includes path with the user's Ghdira script directory - String paths = ""; - for (ResourceFile resourceFile : GhidraScriptUtil.getScriptSourceDirectories()) { + // 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(GhidrathonUtils.THIS_EXTENSION_NAME, "python") - + File.pathSeparator; + paths += resourceFile.getFile(false).getAbsolutePath() + File.pathSeparator; + } - // add paths specified in Ghidrathon config - for (String path : ghidrathonConfig.getPythonIncludePaths()) { + // add data/python/ to Python includes directory + paths += + Application.getModuleDataSubDirectory(GhidrathonUtils.THIS_EXTENSION_NAME, "python") + + File.pathSeparator; - paths += path + File.pathSeparator; - } + // add paths specified in Ghidrathon config + for (String path : ghidrathonConfig.getPythonIncludePaths()) { - // configure Java names that will be ignored when importing from Python - for (String name : ghidrathonConfig.getJavaExcludeLibs()) { + paths += path + File.pathSeparator; + } - ghidrathonClassEnquirer.addJavaExcludeLib(name); - } + // configure Java names that will be ignored when importing from Python + for (String name : ghidrathonConfig.getJavaExcludeLibs()) { - // set the class loader with access to Ghidra scripting API - jepConfig.setClassLoader(ClassLoader.getSystemClassLoader()); + ghidrathonClassEnquirer.addJavaExcludeLib(name); + } - // set class enquirer used to handle Java imports from Python - jepConfig.setClassEnquirer(ghidrathonClassEnquirer); + // set the class loader with access to Ghidra scripting API + jepConfig.setClassLoader(ClassLoader.getSystemClassLoader()); - // configure Python includes Path - jepConfig.addIncludePaths(paths); + // set class enquirer used to handle Java imports from Python + jepConfig.setClassEnquirer(ghidrathonClassEnquirer); - // add Python shared modules - these should be CPython modules for Jep to handle specially - for (String name : ghidrathonConfig.getPythonSharedModules()) { + // configure Python includes Path + jepConfig.addIncludePaths(paths); - jepConfig.addSharedModules(name); - } + // add Python shared modules - these should be CPython modules for Jep to handle specially + for (String name : ghidrathonConfig.getPythonSharedModules()) { - // configure Jep stdout - if (ghidrathonConfig.getStdOut() != null) { + jepConfig.addSharedModules(name); + } - jepConfig.redirectStdout( - new WriterOutputStream( - ghidrathonConfig.getStdOut(), System.getProperty("file.encoding")) { + // configure Jep stdout + if (ghidrathonConfig.getStdOut() != null) { - @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 - } - }); - } + jepConfig.redirectStdout( + new WriterOutputStream( + ghidrathonConfig.getStdOut(), System.getProperty("file.encoding")) { - // 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 - } - }); - } + @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 + } + }); + } - // we must set the native Jep library before creating a Jep instance - setJepPaths(); + // 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 + } + }); + } - // create a new Jep interpreter instance - jep = new jep.SubInterpreter(jepConfig); + // we must set the native Jep library before creating a Jep instance + try { + setJepPaths(); + } catch (Exception e) { + log.info("error setting JEP paths: " + e.toString()); + return; + } - // now that everything is configured, we should be able to run some utility scripts - // to help us further configure the Python environment - setJepEval(); - setJepRunScript(); + try { + // create a new Jep interpreter instance + 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 + setJepEval(); + setJepRunScript(); + + } catch (Exception e) { + log.info("error creating JEP interpreter: " + e.toString()); + return; + } + } catch (Exception e) { + log.info("error: " + e.toString()); + return; + } } - private record JepLocation (Path dll, Path home) {}; - private PathMatcher getJepDllPathMatcher() throws Exception { String os = System.getProperty("os.name", "generic").toLowerCase(Locale.ENGLISH); if ((os.indexOf("mac") >= 0) || (os.indexOf("darwin") >= 0)) { @@ -168,14 +188,12 @@ private PathMatcher getJepDllPathMatcher() throws Exception { throw new Exception("OS not implemented: " + os); } - private JepLocation searchJep(Path path) { - JepLocation empty = new JepLocation(null, null); - + private Path searchJepDll(Path path) { PathMatcher matcher; try { matcher = getJepDllPathMatcher(); } catch (Exception e) { - return empty; + return null; } List dllPaths; @@ -186,21 +204,20 @@ private JepLocation searchJep(Path path) { .collect(Collectors.toList()); } catch (IOException e) { - return empty; + return null; } if (dllPaths.isEmpty()) { - return empty; + return null; } if (dllPaths.size() > 1) { // not sure which to pick - System.err.println("too many results in directory: " + path.toString()); - return empty; + log.error("too many results in directory: " + path.toString()); + return null; } - Path dll = dllPaths.stream().findFirst().get(); - return new JepLocation(dll, path); + return dllPaths.stream().findFirst().get(); } // DANGER: DO NOT PASS DYNAMIC COMMANDS HERE! @@ -210,7 +227,7 @@ private String execCmd(String ... commands) { try { process = runtime.exec(commands); } catch (IOException e) { - System.err.println("error: " + e.toString()); + log.error("error: " + e.toString()); return ""; } @@ -221,43 +238,43 @@ private String execCmd(String ... commands) { String error = String.join("\n", errorReader.lines().collect(Collectors.toList())); if (error.length() > 0) { - System.err.println(">" + error + "<"); + log.error(error); } return output; } - private JepLocation findPythonPathJep() { + private Path findPythonPathJep() { String var = "PYTHONPATH"; String env = System.getenv(var); if (env != null) { for (String envv : env.split(";")) { Path path = java.nio.file.FileSystems.getDefault().getPath(envv); - JepLocation location = searchJep(path); - if (location.dll() != null) { + Path location = searchJepDll(path); + if (location != null) { // return first matching DLL return location; } } } - return new JepLocation(null, null); + return null; } - private JepLocation findVirtualEnvJep() { + private Path findVirtualEnvJep() { String var = "VIRTUAL_ENV"; String env = System.getenv(var); if (env != null) { Path path = java.nio.file.FileSystems.getDefault().getPath(env); - JepLocation location = searchJep(path); - if (location.dll() != null) { + Path location = searchJepDll(path); + if (location != null) { // return only matching DLL return location; } } - return new JepLocation(null, null); + return null; } - private JepLocation findSystemJep() { + private Path findSystemJep() { String output = execCmd("python3", "-c", "import sys; import base64; print((b' '.join(map(lambda s: base64.b64encode(s.encode('utf-8')), sys.path))).decode('ascii'))"); Charset UTF8_CHARSET = Charset.forName("UTF-8"); @@ -267,19 +284,18 @@ private JepLocation findSystemJep() { String s = new String(bytes, UTF8_CHARSET); Path path1 = java.nio.file.FileSystems.getDefault().getPath(s); - JepLocation location = searchJep(path1); + Path location = searchJepDll(path1); - if (location.dll() != null) { - // we don't know the PYTHONHOME from just this info - return new JepLocation(location.dll(), null); + if (location != null) { + return location; } } - return new JepLocation(null, null); + return null; } private void setJepDll(Path path) { - System.err.println("set JEP DLL: " + path.toString()); + log.info("set JEP DLL: " + path.toString()); try { MainInterpreter.setJepLibraryPath(path.toAbsolutePath().toString()); } catch (IllegalStateException e) { @@ -289,13 +305,6 @@ private void setJepDll(Path path) { } } - private void setJepPythonHome(Path path) { - System.err.println("set Python home: " + path.toString()); - PyConfig pyConfig = new PyConfig(); - pyConfig.setPythonHome(path.toAbsolutePath().toString()); - MainInterpreter.setInitParams(pyConfig); - } - /** * Configure native Jep library. * @@ -308,34 +317,31 @@ private void setJepPythonHome(Path path) { */ private void setJepPaths() throws JepException, FileNotFoundException { // if this is set, it take precedence over VIRTUAL_ENV. - JepLocation pythonPathJep = findPythonPathJep(); - if (pythonPathJep.dll() != null) { - System.out.println("found JEP dll via PYTHONPATH: " + pythonPathJep.dll()); + Path pythonPathJep = findPythonPathJep(); + if (pythonPathJep != null) { + log.info("found JEP dll via PYTHONPATH: " + pythonPathJep); } // if this is set, it takes precedence over system python - JepLocation virtualenvJep = findVirtualEnvJep(); - if (virtualenvJep.dll() != null) { - System.out.println("found JEP dll via VIRTUAL_ENV: " + virtualenvJep.dll()); + Path virtualenvJep = findVirtualEnvJep(); + if (virtualenvJep != null) { + log.info("found JEP dll via VIRTUAL_ENV: " + virtualenvJep); } // fall back to whatever python3 references - JepLocation systemJep = findSystemJep(); - if (systemJep.dll() != null) { - System.out.println("found JEP dll via python3: " + systemJep.dll()); + Path systemJep = findSystemJep(); + if (systemJep != null) { + log.info("found JEP dll via python3: " + systemJep); } - if (pythonPathJep.dll() != null) { - setJepDll(pythonPathJep.dll()); - setJepPythonHome(pythonPathJep.home()); - } else if (virtualenvJep.dll() != null) { - setJepDll(virtualenvJep.dll()); - setJepPythonHome(virtualenvJep.home()); - } else if (systemJep.dll() != null) { - setJepDll(systemJep.dll()); - // we don't know home! + if (pythonPathJep != null) { + setJepDll(pythonPathJep); + } else if (virtualenvJep != null) { + setJepDll(virtualenvJep); + } else if (systemJep != null) { + setJepDll(systemJep); } else { - System.out.println("unable to find jep"); + log.error("unable to find jep"); } } From 5b308a59b3682e20e041da5966a1f47ad35ddc0a Mon Sep 17 00:00:00 2001 From: Willi Ballenthin Date: Tue, 13 Jun 2023 17:01:26 +0200 Subject: [PATCH 3/5] interpreter: remove old logging line --- src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java index 202b3d3..bb8d22b 100644 --- a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java +++ b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java @@ -65,7 +65,6 @@ public class GhidrathonInterpreter { * @throws IOException */ private GhidrathonInterpreter(GhidrathonConfig config) throws JepException, IOException { - log.info("GhidrathonInterpreter constructor 1"); try { ghidrathonConfig = config; From 5d9cbb71210d56c75b9b8ef43aaf099db828d6b1 Mon Sep 17 00:00:00 2001 From: William Ballenthin Date: Tue, 13 Jun 2023 17:04:51 +0200 Subject: [PATCH 4/5] interpreter: remove old try/except --- .../interpreter/GhidrathonInterpreter.java | 140 ++++++++---------- 1 file changed, 62 insertions(+), 78 deletions(-) diff --git a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java index 202b3d3..4414769 100644 --- a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java +++ b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java @@ -67,102 +67,86 @@ public class GhidrathonInterpreter { private GhidrathonInterpreter(GhidrathonConfig config) throws JepException, IOException { log.info("GhidrathonInterpreter constructor 1"); - try { - ghidrathonConfig = config; + ghidrathonConfig = config; - // configure the Python includes path with the user's Ghdira script directory - String paths = ""; - for (ResourceFile resourceFile : GhidraScriptUtil.getScriptSourceDirectories()) { + // 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; - } + paths += resourceFile.getFile(false).getAbsolutePath() + File.pathSeparator; + } - // add data/python/ to Python includes directory - paths += - Application.getModuleDataSubDirectory(GhidrathonUtils.THIS_EXTENSION_NAME, "python") - + File.pathSeparator; + // add data/python/ to Python includes directory + paths += + Application.getModuleDataSubDirectory(GhidrathonUtils.THIS_EXTENSION_NAME, "python") + + File.pathSeparator; - // add paths specified in Ghidrathon config - for (String path : ghidrathonConfig.getPythonIncludePaths()) { + // add paths specified in Ghidrathon config + for (String path : ghidrathonConfig.getPythonIncludePaths()) { - paths += path + File.pathSeparator; - } + paths += path + File.pathSeparator; + } - // configure Java names that will be ignored when importing from Python - for (String name : ghidrathonConfig.getJavaExcludeLibs()) { + // configure Java names that will be ignored when importing from Python + for (String name : ghidrathonConfig.getJavaExcludeLibs()) { - ghidrathonClassEnquirer.addJavaExcludeLib(name); - } + ghidrathonClassEnquirer.addJavaExcludeLib(name); + } - // set the class loader with access to Ghidra scripting API - jepConfig.setClassLoader(ClassLoader.getSystemClassLoader()); + // set the class loader with access to Ghidra scripting API + jepConfig.setClassLoader(ClassLoader.getSystemClassLoader()); - // set class enquirer used to handle Java imports from Python - jepConfig.setClassEnquirer(ghidrathonClassEnquirer); + // set class enquirer used to handle Java imports from Python + jepConfig.setClassEnquirer(ghidrathonClassEnquirer); - // configure Python includes Path - jepConfig.addIncludePaths(paths); + // configure Python includes Path + jepConfig.addIncludePaths(paths); - // add Python shared modules - these should be CPython modules for Jep to handle specially - for (String name : ghidrathonConfig.getPythonSharedModules()) { + // add Python shared modules - these should be CPython modules for Jep to handle specially + for (String name : ghidrathonConfig.getPythonSharedModules()) { - jepConfig.addSharedModules(name); - } + jepConfig.addSharedModules(name); + } - // configure Jep stdout - if (ghidrathonConfig.getStdOut() != null) { + // configure Jep stdout + if (ghidrathonConfig.getStdOut() != null) { - jepConfig.redirectStdout( - new WriterOutputStream( - ghidrathonConfig.getStdOut(), System.getProperty("file.encoding")) { + 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 - } - }); - } + @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 - } - }); - } + // 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 - try { - setJepPaths(); - } catch (Exception e) { - log.info("error setting JEP paths: " + e.toString()); - return; - } + // we must set the native Jep library before creating a Jep instance + setJepPaths(); - try { - // create a new Jep interpreter instance - 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 - setJepEval(); - setJepRunScript(); - - } catch (Exception e) { - log.info("error creating JEP interpreter: " + e.toString()); - return; - } - } catch (Exception e) { - log.info("error: " + e.toString()); - return; - } + // create a new Jep interpreter instance + 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 + setJepEval(); + setJepRunScript(); } private PathMatcher getJepDllPathMatcher() throws Exception { From 31bb1ae82cfebdcf57e6827050adc7a2f0f98757 Mon Sep 17 00:00:00 2001 From: William Ballenthin Date: Tue, 13 Jun 2023 17:07:03 +0200 Subject: [PATCH 5/5] interpreter: order imports --- .../interpreter/GhidrathonInterpreter.java | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java index aa08f73..32b430a 100644 --- a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java +++ b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java @@ -10,19 +10,6 @@ package ghidrathon.interpreter; -import java.io.BufferedReader; -import java.io.IOException; -import java.nio.charset.Charset; -import java.nio.file.FileSystems; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.PathMatcher; -import java.util.List; -import java.util.Locale; -import java.util.stream.Collectors; -import java.util.stream.Stream; - - import generic.jar.ResourceFile; import ghidra.app.script.GhidraScript; import ghidra.app.script.GhidraScriptUtil; @@ -31,17 +18,27 @@ import ghidrathon.GhidrathonConfig; import ghidrathon.GhidrathonScript; import ghidrathon.GhidrathonUtils; +import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; +import java.io.IOException; import java.lang.reflect.*; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.FileSystems; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.util.List; +import java.util.Locale; +import java.util.stream.Collectors; +import java.util.stream.Stream; import jep.Jep; import jep.JepConfig; import jep.JepException; import jep.MainInterpreter; import jep.PyConfig; import org.apache.commons.io.output.WriterOutputStream; - import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager;