Skip to content

Commit

Permalink
1.2.0 release
Browse files Browse the repository at this point in the history
  • Loading branch information
dc3-tsd committed Jun 3, 2024
1 parent dab72b9 commit c878e91
Show file tree
Hide file tree
Showing 13 changed files with 285 additions and 32 deletions.
15 changes: 12 additions & 3 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
# Changelog

## [1.2.0] - 2024-05-31
- Fixed Python interpreter completion results for members of currentAddress, currentProgram, etc.
- Fixed handling of complex Python interpreter completions.
- Use configured theme colors for Python interpreter completions.
- Removed Mac specific pyobjc dependency.
- Fixed bug causing Mac specific properties from launch.properties to be omitted.
- Fixed icon bug with the Windows shortcut.
- Added Mac support to the script for installing a desktop launcher.

## [1.1.0] - 2024-04-23
- Improved `pyhidraw` compatibility on Mac.
- Added loader parameter to `open_program` and `run_script` (#37).
- Added script to install a desktop launcher for Windows and Linux. (see [docs](./README.md#desktop-entry))
- Removed `--shortcut` option on `pyhidra` command.


## [1.0.2] - 2024-02-14
- Added `--debug` switch to `pyhidra` command line to set the `pyhidra` logging level to `DEBUG`.
- Warnings when compiling Java code are now logged at the `INFO` logging level.
Expand Down Expand Up @@ -100,10 +108,11 @@
- Fixed noise produced from an exception during analysis due to an analyzer using a script without acquiring a bundle host reference
- Fixed exception in open_program from attempting to use a non-public field in `FlatProgramAPI`

## 0.1.0 - 2021-06-14
## [0.1.0] - 2021-06-14
- Initial release

[Unreleased]: https://github.com/dod-cyber-crime-center/pyhidra/compare/1.1.0...HEAD
[Unreleased]: https://github.com/dod-cyber-crime-center/pyhidra/compare/1.2.0...HEAD
[1.2.0]: https://github.com/dod-cyber-crime-center/pyhidra/compare/1.1.0...1.2.0
[1.1.0]: https://github.com/dod-cyber-crime-center/pyhidra/compare/1.0.2...1.1.0
[1.0.2]: https://github.com/dod-cyber-crime-center/pyhidra/compare/1.0.1...1.0.2
[1.0.1]: https://github.com/dod-cyber-crime-center/pyhidra/compare/1.0.0...1.0.1
Expand Down
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,17 @@ pip install pyhidra

### Desktop Entry

If on linux or windows, a desktop entry can be created to launch an instance of Ghidra with pyhidra attached.
If on linux, mac or windows, a desktop entry can be created to launch an instance of Ghidra with pyhidra attached.
When this script is run from a virtual environment (ie. venv), pyhidra will be started in this virtual environment
when launched.

```console
python -m pyhidra.install_desktop
```

On windows, this will install a shortcut file on the user's desktop. On linux, this will create an entry
that can be found in the applications launcher.
that can be found in the applications launcher. On mac this will create an entry that can be found in
the Launchpad.


To remove, run the following:
Expand Down
2 changes: 1 addition & 1 deletion pyhidra/__init__.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

__version__ = "1.1.0"
__version__ = "1.2.0"

# Expose API
from .core import run_script, start, started, open_program
Expand Down
2 changes: 2 additions & 0 deletions pyhidra/install_desktop.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@
from pyhidra.win_shortcut import create_shortcut
elif sys.platform == "linux":
from pyhidra.linux_shortcut import create_shortcut
elif sys.platform == "darwin":
from pyhidra.mac_shortcut import create_shortcut
else:
sys.exit("Unsupported platform")

Expand Down
39 changes: 27 additions & 12 deletions pyhidra/java/plugin/completions.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,30 @@

NoneType = type(None)

CLASS_COLOR = Color(0, 0, 255)
CODE_COLOR = Color(0, 64, 0)
FUNCTION_COLOR = Color(0, 128, 0)
INSTANCE_COLOR = Color(128, 0, 128)
MAP_COLOR = Color(64, 96, 128)
METHOD_COLOR = Color(0, 128, 128)
NULL_COLOR = Color(255, 0, 0)
NUMBER_COLOR = Color(64, 64, 64)
PACKAGE_COLOR = Color(128, 0, 0)
SEQUENCE_COLOR = Color(128, 96, 64)
try:
from generic.theme import GColor
CLASS_COLOR = GColor("color.fg.plugin.python.syntax.class")
CODE_COLOR = GColor("color.fg.plugin.python.syntax.code")
FUNCTION_COLOR = GColor("color.fg.plugin.python.syntax.function")
INSTANCE_COLOR = GColor("color.fg.plugin.python.syntax.instance")
MAP_COLOR = GColor("color.fg.plugin.python.syntax.map")
METHOD_COLOR = GColor("color.fg.plugin.python.syntax.method")
NULL_COLOR = GColor("color.fg.plugin.python.syntax.null")
NUMBER_COLOR = GColor("color.fg.plugin.python.syntax.number")
PACKAGE_COLOR = GColor("color.fg.plugin.python.syntax.package")
SEQUENCE_COLOR = GColor("color.fg.plugin.python.syntax.sequence")
except:
# no custom theme support yet, fall back to hardcoded values
CLASS_COLOR = Color(0, 0, 255)
CODE_COLOR = Color(0, 64, 0)
FUNCTION_COLOR = Color(0, 128, 0)
INSTANCE_COLOR = Color(128, 0, 128)
MAP_COLOR = Color(64, 96, 128)
METHOD_COLOR = Color(0, 128, 128)
NULL_COLOR = Color(255, 0, 0)
NUMBER_COLOR = Color(64, 64, 64)
PACKAGE_COLOR = Color(128, 0, 0)
SEQUENCE_COLOR = Color(128, 96, 64)

_TYPE_COLORS = {
type: CLASS_COLOR,
Expand Down Expand Up @@ -83,8 +97,9 @@ def _get_label(self, i: int) -> GLabel:
return label

def _supplier(self, i: int) -> CodeCompletion:
insertion = self.matches[i][len(self.cmd):]
return CodeCompletion(self.cmd, insertion, self._get_label(i))
match = self.matches[i]
insertion = match[len(self.cmd):]
return CodeCompletion(match, insertion, self._get_label(i))

def get_completions(self, cmd: str):
"""
Expand Down
9 changes: 6 additions & 3 deletions pyhidra/java/plugin/plugin.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,11 @@
import contextlib
import ctypes
import itertools
import logging
import rlcompleter
import re
import sys
import threading
from code import InteractiveConsole

from ghidra.app.plugin.core.console import CodeCompletion
from ghidra.app.plugin.core.interpreter import InterpreterConsole, InterpreterPanelService
from ghidra.framework import Application
from java.io import BufferedReader, InputStreamReader, PushbackReader
Expand Down Expand Up @@ -170,6 +168,8 @@ class PyPhidraPlugin:
"""
The Python side PyhidraPlugin
"""

_WORD_PATTERN = re.compile(r".*?([\w\.]+)\Z") # get the last word, including '.', from the right

def __init__(self, plugin):
if hasattr(self, '_plugin'):
Expand Down Expand Up @@ -224,6 +224,9 @@ def getCompletions(self, *args):
else:
# older versions of Ghidra don't have the `end` argument.
line, = args
match = self._WORD_PATTERN.match(line)
if match:
line = match.group(1)
return self.completer.get_completions(line)
except Exception as e:
if not self._logged_completions_change:
Expand Down
32 changes: 26 additions & 6 deletions pyhidra/launcher.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import contextlib
import ctypes
import ctypes.util
import importlib.metadata
import inspect
import logging
Expand Down Expand Up @@ -121,6 +123,8 @@ def __init__(self, verbose=False, *, install_dir: Path = None):
@classmethod
def _jvm_args(cls, install_dir: Path) -> List[str]:
suffix = "_" + platform.system().upper()
if suffix == "_DARWIN":
suffix = "_MACOS"
option_pattern: re.Pattern = re.compile(fr"VMARGS(?:{suffix})?=(.+)")
properties = []

Expand Down Expand Up @@ -554,7 +558,6 @@ def _get_thread(name: str):
return None

def _launch(self):
import ctypes
from ghidra import Ghidra
from java.lang import Runtime, Thread

Expand All @@ -565,10 +568,27 @@ def _launch(self):
stdout = _PyhidraStdOut(sys.stdout)
stderr = _PyhidraStdOut(sys.stderr)
with contextlib.redirect_stdout(stdout), contextlib.redirect_stderr(stderr):
jpype.setupGuiEnvironment(lambda: Ghidra.main(["ghidra.GhidraRun", *self.args]))
Thread(lambda: Ghidra.main(["ghidra.GhidraRun", *self.args])).start()
is_exiting = threading.Event()
Runtime.getRuntime().addShutdownHook(Thread(is_exiting.set))
try:
is_exiting.wait()
finally:
jpype.shutdownGuiEnvironment()
if sys.platform == "darwin":
_run_mac_app()
is_exiting.wait()


def _run_mac_app():
# this runs the main event loop
# it is required for the GUI to show up
objc = ctypes.cdll.LoadLibrary(ctypes.util.find_library("libobjc"))
ctypes.cdll.LoadLibrary(ctypes.util.find_library("AppKit")) # required
msgSend = objc.objc_msgSend
msgSend.restype = ctypes.c_void_p
msgSend.argtypes = [ctypes.c_void_p, ctypes.c_void_p]
registerName = objc.sel_registerName
registerName.restype = ctypes.c_void_p
registerName.argtypes = [ctypes.c_char_p]
getClass = objc.objc_getClass
getClass.restype = ctypes.c_void_p
NSApplication = getClass(b"NSApplication")
sharedApplication = msgSend(NSApplication, registerName(b"sharedApplication"))
msgSend(sharedApplication, registerName(b"run"))
9 changes: 7 additions & 2 deletions pyhidra/linux_shortcut.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,26 @@ def extract_png(install_dir: Path) -> Path:
def create_shortcut(install_dir: Path = None):
"""Install a desktop entry on Linux machine."""
pyhidra_exec = Path(sysconfig.get_path("scripts")) / "pyhidra"
if not pyhidra_exec.exists():
# User install
pyhidra_exec = Path(sysconfig.get_path("scripts", "posix_user")) / "pyhidra"
if not pyhidra_exec.exists():
sys.exit("pyhidra executable is not installed.")

command = [str(pyhidra_exec), "--gui"]
if install_dir:
command += ["--install-dir", str(install_dir.expanduser())]
pass
elif install_dir := os.environ.get("GHIDRA_INSTALL_DIR"):
install_dir = Path(install_dir)
else:
sys.exit(
"Unable to determine Ghidra installation directory. "
"Please set the GHIDRA_INSTALL_DIR environment variable."
)

command = [str(pyhidra_exec), "--gui", "--install-dir", str(install_dir.expanduser())]

icon = extract_png(install_dir)
desktop_path.parent.mkdir(parents=True, exist_ok=True)
desktop_path.write_text(desktop_entry.format(icon=icon, exec=shlex.join(command)))
print(f"Installed {desktop_path}")

Expand Down
Loading

0 comments on commit c878e91

Please sign in to comment.