diff --git a/CHANGELOG.md b/CHANGELOG.md index 51d928d..3a86565 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,8 @@ # Changelog +## [0.4.1] - 2023-02-21 +- Fixed bug causing the loading of updated plugins to fail. + ## [0.4.0] - 2023-01-26 - Added manual plugin installation helper. - Analyze the program by default, if provided, when entering the REPL with pyhidra. @@ -55,7 +58,8 @@ ## 0.1.0 - 2021-06-14 - Initial release -[Unreleased]: https://github.com/dod-cyber-crime-center/pyhidra/compare/0.4.0...HEAD +[Unreleased]: https://github.com/dod-cyber-crime-center/pyhidra/compare/0.4.1...HEAD +[0.4.1]: https://github.com/dod-cyber-crime-center/pyhidra/compare/0.4.0...0.4.1 [0.4.0]: https://github.com/dod-cyber-crime-center/pyhidra/compare/0.3.0...0.4.0 [0.3.0]: https://github.com/dod-cyber-crime-center/pyhidra/compare/0.2.1...0.3.0 [0.2.1]: https://github.com/dod-cyber-crime-center/pyhidra/compare/0.2.0...0.2.1 diff --git a/pyhidra/__init__.py b/pyhidra/__init__.py index 417ca28..aa31b5e 100644 --- a/pyhidra/__init__.py +++ b/pyhidra/__init__.py @@ -1,5 +1,5 @@ -__version__ = "0.4.0" +__version__ = "0.4.1" # Expose API from .core import run_script, start, open_program diff --git a/pyhidra/__main__.py b/pyhidra/__main__.py index 042d646..1631434 100644 --- a/pyhidra/__main__.py +++ b/pyhidra/__main__.py @@ -70,7 +70,7 @@ def func(self): self.project_path, self.project_name, self.verbose, - not self.skip_analsis + not self.skip_analysis ) with pyhidra.core._flat_api(*args) as api: _interpreter(api) diff --git a/pyhidra/launcher.py b/pyhidra/launcher.py index d03b569..95b187e 100644 --- a/pyhidra/launcher.py +++ b/pyhidra/launcher.py @@ -203,6 +203,19 @@ def start(self): jvm = _get_libjvm_path(self.java_home) + pyhidra_details = ExtensionDetails( + name="pyhidra", + description="Native Python Plugin", + author="Department of Defense Cyber Crime Center (DC3)", + plugin_version=__version__, + ) + + # uninstall any outdated plugins before starting the JVM to ensure they are loaded correctly + self._uninstall_old_plugin(pyhidra_details) + + for _, details in self._plugins: + self._uninstall_old_plugin(details) + jpype.startJVM( str(jvm), *self.vm_args, @@ -221,12 +234,7 @@ def start(self): # install the Pyhidra plugin. from pyhidra.java import plugin - needs_reload = self._install_plugin(Path(plugin.__file__).parent, ExtensionDetails( - name="pyhidra", - description="Native Python Plugin", - author="Department of Defense Cyber Crime Center (DC3)", - plugin_version=__version__, - )) + needs_reload = self._install_plugin(Path(plugin.__file__).parent, pyhidra_details) if needs_reload: # "restart" Ghidra @@ -237,6 +245,14 @@ def start(self): from pyhidra.java.plugin.plugin import PyPhidraPlugin PyPhidraPlugin.register() + # Add extra class paths + # Do this before installing plugins incase dependencies are needed + if self.class_files: + from java.lang import ClassLoader + gcl = ClassLoader.getSystemClassLoader() + for path in self.class_files: + gcl.addPath(path) + # Install extra plugins. for source_path, details in self._plugins: needs_reload = self._install_plugin(source_path, details) or needs_reload @@ -245,13 +261,6 @@ def start(self): # "restart" Ghidra self.layout = GhidraLauncher.initializeGhidraEnvironment() - # Add extra class paths. - if self.class_files: - from java.lang import ClassLoader - gcl = ClassLoader.getSystemClassLoader() - for path in self.class_files: - gcl.addPath(path) - # import properties to register the property customizer from . import properties as _ @@ -280,24 +289,34 @@ def uninstall_plugin(self, plugin_name: str): logger.exception(msg) self._report_fatal_error(title, msg) - def _install_plugin(self, source_path: Path, details: ExtensionDetails): + def _uninstall_old_plugin(self, details: ExtensionDetails): """ - Compiles and installs a Ghidra extension. - Automatically updates old plugin installation if it exists. + Automatically uninstalls an outdated plugin if it exists. """ plugin_name = details.name path = self.get_install_path(plugin_name) ext = path / "extension.properties" manifest = path / "Module.manifest" - root = source_path # Uninstall old version. if manifest.exists() and ext.exists(): orig_details = ExtensionDetails.from_file(ext) - if not orig_details.plugin_version or orig_details.plugin_version < details.plugin_version: + if not orig_details.plugin_version or orig_details.plugin_version != details.plugin_version: self.uninstall_plugin(plugin_name) logger.info(f"Uninstalled older plugin: {plugin_name} {orig_details.plugin_version}") + + def _install_plugin(self, source_path: Path, details: ExtensionDetails): + """ + Compiles and installs a Ghidra extension. + Automatically updates old plugin installation if it exists. + """ + plugin_name = details.name + path = self.get_install_path(plugin_name) + ext = path / "extension.properties" + manifest = path / "Module.manifest" + root = source_path + if not manifest.exists(): jar_path = path / "lib" / (plugin_name + ".jar") java_compile(root.parent, jar_path)