145 lines
4.3 KiB
Python
145 lines
4.3 KiB
Python
|
import argparse
|
||
|
import io
|
||
|
import os
|
||
|
from pathlib import Path
|
||
|
import platform
|
||
|
import sys
|
||
|
import traceback
|
||
|
from typing import NoReturn
|
||
|
import warnings
|
||
|
|
||
|
import pyhidra
|
||
|
|
||
|
|
||
|
class _GuiOutput(io.StringIO):
|
||
|
|
||
|
def __init__(self, title: str, *args, **kwargs):
|
||
|
super().__init__(*args, **kwargs)
|
||
|
self.title = title
|
||
|
|
||
|
def close(self):
|
||
|
import tkinter.messagebox
|
||
|
tkinter.messagebox.showinfo(self.title, self.getvalue())
|
||
|
super().close()
|
||
|
|
||
|
|
||
|
class _GuiArgumentParser(argparse.ArgumentParser):
|
||
|
def exit(self, status=0, *_):
|
||
|
sys.exit(status)
|
||
|
|
||
|
def print_usage(self, file=None):
|
||
|
if file is None:
|
||
|
file = _GuiOutput("Usage")
|
||
|
self._print_message(self.format_usage(), file)
|
||
|
|
||
|
def print_help(self, file=None):
|
||
|
if file is None:
|
||
|
file = _GuiOutput("Help")
|
||
|
self._print_message(self.format_help(), file)
|
||
|
|
||
|
|
||
|
def _gui_mac() -> NoReturn:
|
||
|
args = _parse_args()
|
||
|
install_dir = args.install_dir
|
||
|
path = Path(sys.base_exec_prefix) / "Resources/Python.app/Contents/MacOS/Python"
|
||
|
if path.exists():
|
||
|
# the python launcher app will correctly start the venv if sys.executable is in a venv
|
||
|
argv = [sys.executable, "-m", "pyhidra", "-g"]
|
||
|
if install_dir is not None:
|
||
|
argv += ["--install-dir", str(install_dir)]
|
||
|
actions = ((os.POSIX_SPAWN_CLOSE, 0), (os.POSIX_SPAWN_CLOSE, 1), (os.POSIX_SPAWN_CLOSE, 2))
|
||
|
os.posix_spawn(str(path), argv, os.environ, file_actions=actions)
|
||
|
else:
|
||
|
print("could not find the Python.app path, launch failed")
|
||
|
sys.exit(0)
|
||
|
|
||
|
|
||
|
def _parse_args():
|
||
|
parser = _GuiArgumentParser(prog="pyhidraw")
|
||
|
parser.add_argument(
|
||
|
"--install-dir",
|
||
|
type=Path,
|
||
|
default=None,
|
||
|
dest="install_dir",
|
||
|
metavar="",
|
||
|
help="Path to Ghidra installation. "\
|
||
|
"(defaults to the GHIDRA_INSTALL_DIR environment variable)"
|
||
|
)
|
||
|
return parser.parse_args()
|
||
|
|
||
|
|
||
|
def _gui_default(install_dir: Path):
|
||
|
pid = os.fork()
|
||
|
if pid != 0:
|
||
|
# original process can exit
|
||
|
return
|
||
|
|
||
|
fd = os.open(os.devnull, os.O_RDWR)
|
||
|
# redirect stdin, stdout and stderr to /dev/null so the jvm can't use the terminal
|
||
|
# this also prevents errors from attempting to write to a closed sys.stdout #21
|
||
|
os.dup2(fd, sys.stdin.fileno(), inheritable=False)
|
||
|
os.dup2(fd, sys.stdout.fileno(), inheritable=False)
|
||
|
os.dup2(fd, sys.stderr.fileno(), inheritable=False)
|
||
|
|
||
|
# run the application
|
||
|
gui(install_dir)
|
||
|
|
||
|
|
||
|
def _gui():
|
||
|
# this is the entry from the gui script
|
||
|
# there may or may not be an attached terminal
|
||
|
# depending on the current operating system
|
||
|
|
||
|
if platform.system() == "Darwin":
|
||
|
_gui_mac()
|
||
|
|
||
|
# This check handles the edge case of having a corrupt Python installation
|
||
|
# where tkinter can't be imported. Since there may not be an attached
|
||
|
# terminal, the problem still needs to be reported somehow.
|
||
|
try:
|
||
|
import tkinter.messagebox as _
|
||
|
except ImportError as e:
|
||
|
if platform.system() == "Windows":
|
||
|
# there is no console/terminal to report the error
|
||
|
import ctypes
|
||
|
MessageBox = ctypes.windll.user32.MessageBoxW
|
||
|
MessageBox(None, str(e), "Import Error", 0)
|
||
|
sys.exit(1)
|
||
|
# report this before detaching from the console or no
|
||
|
# errors will be reported if they occur
|
||
|
raise
|
||
|
|
||
|
try:
|
||
|
args = _parse_args()
|
||
|
install_dir = args.install_dir
|
||
|
except Exception as e:
|
||
|
import tkinter.messagebox
|
||
|
msg = "".join(traceback.format_exception(type(e), value=e, tb=e.__traceback__))
|
||
|
tkinter.messagebox.showerror(type(e), msg)
|
||
|
sys.exit(1)
|
||
|
|
||
|
if platform.system() == 'Windows':
|
||
|
# gui_script works like it is supposed to on windows
|
||
|
gui(install_dir)
|
||
|
else:
|
||
|
_gui_default(install_dir)
|
||
|
|
||
|
|
||
|
def gui(install_dir: Path = None):
|
||
|
"""
|
||
|
Starts the Ghidra GUI
|
||
|
|
||
|
:param install_dir: The path to the Ghidra installation directory.
|
||
|
(Defaults to the GHIDRA_INSTALL_DIR environment variable)
|
||
|
"""
|
||
|
pyhidra.GuiPyhidraLauncher(install_dir=install_dir).start()
|
||
|
|
||
|
|
||
|
def get_current_interpreter():
|
||
|
warnings.warn(
|
||
|
"get_current_interpreter has been moved. Please use pyhidra.get_current_interpreter",
|
||
|
DeprecationWarning
|
||
|
)
|
||
|
return pyhidra.get_current_interpreter()
|
||
|
|