diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index d5c57ea..10e9e45 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -47,6 +47,13 @@ jobs: jep-jar-release-url: ["https://github.com/ninia/jep/releases/download/v4.2.0/jep-4.2.0.jar"] os: [ubuntu-latest, windows-latest, macos-latest] python-version: ["3.8", "3.12"] + include: + - os: ubuntu-latest + ghidrathon-save-path: "/tmp/" + - os: windows-latest + ghidrathon-save-path: "C:\\Temp\\" + - os: macos-latest + ghidrathon-save-path: "/tmp/" steps: - name: Checkout Ghidrathon uses: actions/checkout@v4 @@ -98,12 +105,29 @@ jobs: run: | Rename-Item -Path "./dist/$((Get-ChildItem -Path "./dist").Name)" -NewName "Ghidrathon.zip" tar -xf ./dist/Ghidrathon.zip -C ../tmp/ghidra/ghidra_PUBLIC/Ghidra/Extensions/ - - name: Set Ghidrathon Python interpreter + + # test Ghidrathon when GHIDRATHON_SAVE_PATH is unset + - name: Set Ghidrathon Python interpreter (GHIDRATHON_SAVE_PATH is unset) run: python util/ghidrathon_configure.py ../tmp/ghidra/ghidra_PUBLIC -d - - name: Run tests + - name: Run tests (GHIDRATHON_SAVE_PATH is unset) + run: | # the -overwrite flag ensures that an existing project file that conflicts with an import file is overwritten + ../tmp/ghidra/ghidra_PUBLIC/support/analyzeHeadless ${{ github.workspace }}/../tmp/ghidra test -Import ${{ github.workspace }}/../tmp/ghidra/ghidra_PUBLIC/GPL/DemanglerGnu/os/linux_x86_64/demangler_gnu_v2_24 -overwrite -PostScript ${{ github.workspace }}/data/python/tests/hello.py -PostScript ${{ github.workspace }}/data/python/tests/runall.py > ../tmp/log.txt + - name: Check tests (GHIDRATHON_SAVE_PATH is unset) run: | - ../tmp/ghidra/ghidra_PUBLIC/support/analyzeHeadless ${{ github.workspace }}/../tmp/ghidra test -Import ${{ github.workspace }}/../tmp/ghidra/ghidra_PUBLIC/GPL/DemanglerGnu/os/linux_x86_64/demangler_gnu_v2_24 -PostScript ${{ github.workspace }}/data/python/tests/hello.py -PostScript ${{ github.workspace }}/data/python/tests/runall.py > ../tmp/log.txt - - name: Check tests + python -c "import pathlib, sys;log_text=pathlib.Path('../tmp/log.txt').read_text(encoding='utf-8');print(log_text);sys.exit(0 if 'runall.py called exit with code 0' in log_text else -1)" + python -c "import pathlib, sys; sys.exit(0 if pathlib.Path('hello.txt').exists() else -1)" + + # test Ghidrathon when GHIDRATHON_SAVE_PATH is set + - name: Set Ghidrathon Python interpreter (GHIDRATHON_SAVE_PATH is set) + env: + GHIDRATHON_SAVE_PATH: ${{ matrix.ghidrathon-save-path }} + run: python util/ghidrathon_configure.py ../tmp/ghidra/ghidra_PUBLIC -d + - name: Run tests (GHIDRATHON_SAVE_PATH is set) + env: + GHIDRATHON_SAVE_PATH: ${{ matrix.ghidrathon-save-path }} + run: | # the -overwrite flag ensures that an existing project file that conflicts with an import file is overwritten + ../tmp/ghidra/ghidra_PUBLIC/support/analyzeHeadless ${{ github.workspace }}/../tmp/ghidra test -Import ${{ github.workspace }}/../tmp/ghidra/ghidra_PUBLIC/GPL/DemanglerGnu/os/linux_x86_64/demangler_gnu_v2_24 -overwrite -PostScript ${{ github.workspace }}/data/python/tests/hello.py -PostScript ${{ github.workspace }}/data/python/tests/runall.py > ../tmp/log.txt + - name: Check tests (GHIDRATHON_SAVE_PATH is set) run: | python -c "import pathlib, sys;log_text=pathlib.Path('../tmp/log.txt').read_text(encoding='utf-8');print(log_text);sys.exit(0 if 'runall.py called exit with code 0' in log_text else -1)" python -c "import pathlib, sys; sys.exit(0 if pathlib.Path('hello.txt').exists() else -1)" diff --git a/README.md b/README.md index 1ea055e..7dd5217 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,11 @@ Use the following steps to install Ghidrathon to your Ghidra environment: $ python -m pip install -r requirements.txt $ python ghidrathon_configure.py ``` +**Note**: `ghidrathon_configure.py` by default attempts to write a file named `ghidrathon.save` to ``. You can specify the path where this file is written by setting the `GHIDRATHON_SAVE_PATH` environment variable before running `ghidrathon_configure.py` and Ghidra: +``` +$ export GHIDRATHON_SAVE_PATH="/path/to/custom/dir" # Linux/MacOS +$ set GHIDRATHON_SAVE_PATH="C:\path\to\custom\dir" # Windows +``` **Note**: you may be prompted to set an environment variable named `JAVA_HOME`. This should reference the absolute path of the JDK that you have configured for your Ghidra install. 3. Install the Ghidrathon extension (`.zip`) into Ghidra: diff --git a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java index 1f42c42..bcaded8 100644 --- a/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java +++ b/src/main/java/ghidrathon/interpreter/GhidrathonInterpreter.java @@ -41,6 +41,7 @@ private class GhidrathonSave { } private static final String GHIDRATHON_SAVE_FILENAME = "ghidrathon.save"; + private static final String GHIDRATHON_SAVE_PATH = "GHIDRATHON_SAVE_PATH"; private static final String SUPPORTED_JEP_VERSION = "4.2.0"; private Jep jep_ = null; @@ -193,10 +194,23 @@ private void extendPythonSysPath() { */ private void configureJepMainInterpreter() throws JepException, FileNotFoundException { - File ghidrathonSaveFile = - new File( - Application.getApplicationRootDirectory().getParentFile().getFile(false), - GhidrathonInterpreter.GHIDRATHON_SAVE_FILENAME); + // get the ghidrathon.save path from the environment variable or use the default path + String ghidrathonSavePath = System.getenv(GHIDRATHON_SAVE_PATH); + File ghidrathonSaveFile; + + if (ghidrathonSavePath != null && !ghidrathonSavePath.isEmpty()) { + ghidrathonSaveFile = new File(ghidrathonSavePath, GHIDRATHON_SAVE_FILENAME); + Msg.info( + GhidrathonInterpreter.class, + String.format("Using save file from environment variable %s.", GHIDRATHON_SAVE_PATH)); + } else { + ghidrathonSaveFile = + new File( + Application.getApplicationRootDirectory().getParentFile().getFile(false), + GHIDRATHON_SAVE_FILENAME); + Msg.info(GhidrathonInterpreter.class, String.format("Using default save file path.")); + } + if (!(ghidrathonSaveFile.exists() && ghidrathonSaveFile.isFile())) { throw new JepException( String.format( @@ -206,7 +220,7 @@ private void configureJepMainInterpreter() throws JepException, FileNotFoundExce Msg.info( GhidrathonInterpreter.class, - String.format("Using save file at %s.", ghidrathonSaveFile.getAbsolutePath())); + String.format("Using save file found at %s.", ghidrathonSaveFile.getAbsolutePath())); GhidrathonSave ghidrathonSave = null; try (BufferedReader reader = new BufferedReader(new FileReader(ghidrathonSaveFile))) { diff --git a/util/ghidrathon_configure.py b/util/ghidrathon_configure.py index fc18a61..2218d39 100644 --- a/util/ghidrathon_configure.py +++ b/util/ghidrathon_configure.py @@ -6,6 +6,7 @@ # 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. +import os import sys import json import logging @@ -17,6 +18,8 @@ SUPPORTED_JEP_VERSION = "4.2.0" PYTHON_HOME_DIR_KEY = "home" PYTHON_EXECUTABLE_FILE_KEY = "executable" +GHIDRATHON_SAVE_PATH = "GHIDRATHON_SAVE_PATH" +GHIDRATHON_SAVE_FILENAME = "ghidrathon.save" logger = logging.getLogger(__name__) @@ -91,7 +94,34 @@ def main(args): logger.debug('Using Python home located at "%s".', home_path) json_: str = json.dumps(ghidrathon_save) - save_path: pathlib.Path = install_path / "ghidrathon.save" + ghidrathon_save_path_env = os.environ.get(GHIDRATHON_SAVE_PATH) + + if ghidrathon_save_path_env == "": + logger.error( + 'The path specified by the "%s" environment variable "%s" is not a valid directory.', + GHIDRATHON_SAVE_PATH, + ghidrathon_save_path_env, + ) + return -1 + elif ghidrathon_save_path_env: + save_path: pathlib.Path = pathlib.Path(ghidrathon_save_path_env) + if not all((save_path.exists(), save_path.is_dir())): + logger.error( + 'The path specified by the "%s" environment variable "%s" is not a valid directory.', + GHIDRATHON_SAVE_PATH, + ghidrathon_save_path_env, + ) + return -1 + save_path = save_path / GHIDRATHON_SAVE_FILENAME + logger.debug( + 'Using save file path from environment variable "%s": "%s"', + GHIDRATHON_SAVE_PATH, + save_path, + ) + else: + save_path: pathlib.Path = install_path / GHIDRATHON_SAVE_FILENAME + logger.debug('Using default save file path "%s"', save_path) + try: save_path.write_text(json_, encoding="utf-8") except Exception as e: @@ -133,7 +163,9 @@ def main(args): ) parser.add_argument( - "ghidrathon_install_directory", type=pathlib.Path, help="Absolute path of Ghidra install directory" + "ghidrathon_install_directory", + type=pathlib.Path, + help="Absolute path of Ghidra install directory", ) parser.add_argument("-d", "--debug", action="store_true", help="Show debug messages")