diff --git a/README.md b/README.md index 594b2c0..3c1f8cc 100644 --- a/README.md +++ b/README.md @@ -321,7 +321,20 @@ the service user and group like upstream, but patches an issue with loading python packages in the ghidra debug feature -this will probably get removed once upstream fixes the issue +additionally, provides a way to specify extensions + +#### `programs.ghidra.extensions` + +Ghidra extensions to be included in the installation. + +example: +``` +[ (ps: with ps; [ binsync ]) ] +``` + +#### `programs.ghidra.binsync.enable` + +enable binsync integration ### [`environment.machineInfo`](./modules/machine-info/default.nix) @@ -474,6 +487,13 @@ server operation with a headless jdk (in particular, the ghidra-server nixos mod this is equivalent to the `lib` output of the split `ghidra` package +### [`ghidra-extensions`](./pkgs/reverse-engineering/ghidra/extensions) + +like upstream, but contains additional extensions: + +- `binsync-ghidra`: the binsync `ghidra_scripts` installation packaged as an extension, so it can be + installed at the system level + ### [`ocamlPackages.ppx_unicode`](./pkgs/ocaml/ppx_unicode) opinionated ppx for string literals: diff --git a/modules/ghidra-client/default.nix b/modules/ghidra-client/default.nix index da6a916..2ee548c 100644 --- a/modules/ghidra-client/default.nix +++ b/modules/ghidra-client/default.nix @@ -7,9 +7,11 @@ let cfg = config.programs.ghidra; - package = cfg.package; - isSplit = lib.elem "lib" package.outputs; - libOutput = if isSplit then package.lib else package; + isSplit = lib.elem "lib" cfg.package.outputs; + libOutput = if isSplit then cfg.package.lib else cfg.package; + + packageWithExts = cfg.package.withExtensions + (p: lib.concatMap (pl: pl p) cfg.extensions); in { disabledModules = [ "programs/ghidra.nix" ]; @@ -26,11 +28,30 @@ in }; package = lib.mkPackageOption pkgs "ghidra" { example = "ghidra_headless"; }; + + extensions = lib.mkOption { + type = with lib.types; listOf (functionTo (listOf package)); + default = []; + description = '' + Ghidra extensions to be included in the installation. + ''; + example = lib.literalExpression "[ (ps: with ps; [ my_extension ]) ]"; + }; + + binsync = { + enable = lib.mkEnableOption "Ghidra binsync integration"; + }; }; config = lib.mkIf cfg.enable { + programs.ghidra.extensions = lib.mkIf (cfg.binsync.enable) [ + (ps: [ ps.binsync ]) + ]; + environment = { - systemPackages = [ package ]; + systemPackages = [ + packageWithExts + ]; etc = lib.mkIf cfg.gdb { "gdb/gdbinit.d/ghidra-modules.gdb".text = with pkgs.python3.pkgs; '' diff --git a/pkgs/reverse-engineering/ghidra/extensions.nix b/pkgs/reverse-engineering/ghidra/extensions.nix index c17eb7f..bc98b77 100644 --- a/pkgs/reverse-engineering/ghidra/extensions.nix +++ b/pkgs/reverse-engineering/ghidra/extensions.nix @@ -34,4 +34,6 @@ lib.makeScope newScope (self: { sleighdevtools = self.callPackage ./extensions/sleighdevtools { inherit ghidra; }; wasm = self.callPackage ./extensions/wasm { inherit ghidra; }; + + binsync = self.callPackage ./extensions/binsync {}; }) diff --git a/pkgs/reverse-engineering/ghidra/extensions/binsync/default.nix b/pkgs/reverse-engineering/ghidra/extensions/binsync/default.nix new file mode 100644 index 0000000..311a02b --- /dev/null +++ b/pkgs/reverse-engineering/ghidra/extensions/binsync/default.nix @@ -0,0 +1,40 @@ +{ + lib, + fetchFromGitHub, + buildGhidraScripts, + runCommand, + rsync, + + python311, +}: let + python = python311; + libbs_path = "${python.pkgs.libbs}/${python.sitePackages}"; + binsync_path = "${python.pkgs.binsync}/${python.sitePackages}"; + + binsync_env = python.withPackages (ps: with ps; ([ + binsync + ] ++ binsync.optional-dependencies.ghidra)); +in buildGhidraScripts { + pname = "binsync-ghidra"; + inherit (python.pkgs.binsync) version; + + src = runCommand "binsync-ghidra-scripts" { + nativeBuildInputs = [ rsync ]; + strictDeps = true; + } '' + mkdir -p $out + + rsync -r \ + --exclude='__pycache__' \ + --exclude='/__init__.py' \ + ${libbs_path}/libbs/decompiler_stubs/ghidra_libbs/. $out/. + + cp ${binsync_path}/binsync/binsync_plugin.py $out + ''; + + postPatch = '' + substituteInPlace binsync_plugin.py \ + --replace-fail 'plugin_command = "binsync -s ghidra"' \ + 'plugin_command = "${lib.getExe' binsync_env "binsync"} -s ghidra"' + ''; +}