From bc4f2ea7f7962bcb797eb46effbe3877ebd421da Mon Sep 17 00:00:00 2001 From: xenia Date: Thu, 10 Oct 2024 22:44:57 -0400 Subject: [PATCH] WIP: new ghidra package(s) --- TODO.md | 6 +- default.nix | 4 + .../0001-Use-protobuf-gradle-plugin.patch | 214 +++++ .../0002-Load-nix-extensions.patch | 15 + .../0003-Remove-build-datestamp.patch | 26 + pkgs/ghidra-xenia-v2/build-extension.nix | 98 +++ pkgs/ghidra-xenia-v2/build.nix | 201 +++++ pkgs/ghidra-xenia-v2/default.nix | 92 +++ pkgs/ghidra-xenia-v2/deps.json | 754 ++++++++++++++++++ pkgs/ghidra-xenia-v2/extensions.nix | 26 + .../ghidraninja-ghidra-scripts/default.nix | 37 + .../extensions/gnudisassembler/default.nix | 69 ++ .../extensions/lightkeeper/default.nix | 24 + .../extensions/machinelearning/default.nix | 35 + .../extensions/ret-sync/default.nix | 32 + .../extensions/sleighdevtools/default.nix | 41 + pkgs/ghidra-xenia-v2/with-extensions.nix | 45 ++ 17 files changed, 1718 insertions(+), 1 deletion(-) create mode 100644 pkgs/ghidra-xenia-v2/0001-Use-protobuf-gradle-plugin.patch create mode 100644 pkgs/ghidra-xenia-v2/0002-Load-nix-extensions.patch create mode 100644 pkgs/ghidra-xenia-v2/0003-Remove-build-datestamp.patch create mode 100644 pkgs/ghidra-xenia-v2/build-extension.nix create mode 100644 pkgs/ghidra-xenia-v2/build.nix create mode 100644 pkgs/ghidra-xenia-v2/default.nix create mode 100644 pkgs/ghidra-xenia-v2/deps.json create mode 100644 pkgs/ghidra-xenia-v2/extensions.nix create mode 100644 pkgs/ghidra-xenia-v2/extensions/ghidraninja-ghidra-scripts/default.nix create mode 100644 pkgs/ghidra-xenia-v2/extensions/gnudisassembler/default.nix create mode 100644 pkgs/ghidra-xenia-v2/extensions/lightkeeper/default.nix create mode 100644 pkgs/ghidra-xenia-v2/extensions/machinelearning/default.nix create mode 100644 pkgs/ghidra-xenia-v2/extensions/ret-sync/default.nix create mode 100644 pkgs/ghidra-xenia-v2/extensions/sleighdevtools/default.nix create mode 100644 pkgs/ghidra-xenia-v2/with-extensions.nix diff --git a/TODO.md b/TODO.md index 04442a2..710d6aa 100644 --- a/TODO.md +++ b/TODO.md @@ -1,7 +1,11 @@ # TODO +## ghidra-xenia-v2 +- split ghidra-lib package with no dependency on any jdk (launch.sh) +- make a custom launch script similar to ghidra-server nixos module to replace launch.sh +- make runtime jdk configurable and independent of build jdk + ## upstream -- fix ghidra StartupWMClass - fix kicad desktop file name ## `ghidra-server` diff --git a/default.nix b/default.nix index 45ce5d8..0641cee 100644 --- a/default.nix +++ b/default.nix @@ -19,6 +19,8 @@ openjdk17 = prev.openjdk17_headless; }; + + # stuff that tracks upstream ghidra = final.callPackage ./pkgs/ghidra-xenia/build.nix { protobuf = final.protobuf_21; }; @@ -27,6 +29,8 @@ kicad = final.callPackage ./pkgs/kicad-xenia { }; kicadAddons = final.lib.recurseIntoAttrs (final.callPackage ./pkgs/kicad-xenia/addons {}); + # end stuff that tracks upstream + ocamlPackages = prev.ocamlPackages.overrideScope (ofinal: oprev: { ppx_unicode = ofinal.callPackage ./pkgs/ocaml/ppx_unicode {}; diff --git a/pkgs/ghidra-xenia-v2/0001-Use-protobuf-gradle-plugin.patch b/pkgs/ghidra-xenia-v2/0001-Use-protobuf-gradle-plugin.patch new file mode 100644 index 0000000..14065f3 --- /dev/null +++ b/pkgs/ghidra-xenia-v2/0001-Use-protobuf-gradle-plugin.patch @@ -0,0 +1,214 @@ +From ffb6777d58f068db7e14372415154cd93f77766e Mon Sep 17 00:00:00 2001 +From: roblabla +Date: Wed, 31 Jan 2024 13:19:55 +0100 +Subject: [PATCH] Use com.google.protobuf:protobuf-gradle-plugin + +--- + Ghidra/Debug/Debugger-gadp/build.gradle | 7 +- + Ghidra/Debug/Debugger-isf/build.gradle | 8 +- + Ghidra/Debug/Debugger-rmi-trace/build.gradle | 14 +-- + build.gradle | 6 ++ + gradle/hasProtobuf.gradle | 94 -------------------- + 5 files changed, 26 insertions(+), 103 deletions(-) + +diff --git a/Ghidra/Debug/Debugger-gadp/build.gradle b/Ghidra/Debug/Debugger-gadp/build.gradle +index 9e1c57faf..3a3242eb5 100644 +--- a/Ghidra/Debug/Debugger-gadp/build.gradle ++++ b/Ghidra/Debug/Debugger-gadp/build.gradle +@@ -18,11 +18,16 @@ apply from: "${rootProject.projectDir}/gradle/javaProject.gradle" + apply from: "${rootProject.projectDir}/gradle/jacocoProject.gradle" + apply from: "${rootProject.projectDir}/gradle/javaTestProject.gradle" + apply from: "${rootProject.projectDir}/gradle/distributableGhidraModule.gradle" +-apply from: "${rootProject.projectDir}/gradle/hasProtobuf.gradle" ++apply plugin: 'com.google.protobuf' + + apply plugin: 'eclipse' + eclipse.project.name = 'Debug Debugger-gadp' + ++buildscript { ++ dependencies { ++ classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.18' ++ } ++} + dependencies { + api project(':Framework-AsyncComm') + api project(':Framework-Debugging') +diff --git a/Ghidra/Debug/Debugger-isf/build.gradle b/Ghidra/Debug/Debugger-isf/build.gradle +index d135294a0..785681ca2 100644 +--- a/Ghidra/Debug/Debugger-isf/build.gradle ++++ b/Ghidra/Debug/Debugger-isf/build.gradle +@@ -18,11 +18,15 @@ apply from: "${rootProject.projectDir}/gradle/javaProject.gradle" + apply from: "${rootProject.projectDir}/gradle/jacocoProject.gradle" + apply from: "${rootProject.projectDir}/gradle/javaTestProject.gradle" + apply from: "${rootProject.projectDir}/gradle/distributableGhidraModule.gradle" +-apply from: "${rootProject.projectDir}/gradle/hasProtobuf.gradle" +- ++apply plugin: 'com.google.protobuf' + apply plugin: 'eclipse' + eclipse.project.name = 'Debug Debugger-isf' + ++buildscript { ++ dependencies { ++ classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.18' ++ } ++} + dependencies { + api project(':Framework-AsyncComm') + api project(':Framework-Debugging') +diff --git a/Ghidra/Debug/Debugger-rmi-trace/build.gradle b/Ghidra/Debug/Debugger-rmi-trace/build.gradle +index 40fbc17ab..7517ffe6e 100644 +--- a/Ghidra/Debug/Debugger-rmi-trace/build.gradle ++++ b/Ghidra/Debug/Debugger-rmi-trace/build.gradle +@@ -18,12 +18,17 @@ apply from: "${rootProject.projectDir}/gradle/javaProject.gradle" + apply from: "${rootProject.projectDir}/gradle/jacocoProject.gradle" + apply from: "${rootProject.projectDir}/gradle/javaTestProject.gradle" + apply from: "${rootProject.projectDir}/gradle/distributableGhidraModule.gradle" +-apply from: "${rootProject.projectDir}/gradle/hasProtobuf.gradle" ++apply plugin: 'com.google.protobuf' + apply from: "${rootProject.projectDir}/gradle/hasPythonPackage.gradle" + + apply plugin: 'eclipse' + eclipse.project.name = 'Debug Debugger-rmi-trace' + ++buildscript { ++ dependencies { ++ classpath 'com.google.protobuf:protobuf-gradle-plugin:0.8.18' ++ } ++} + dependencies { + api project(':Pty') + api project(':Debugger') +@@ -44,12 +49,9 @@ task generateProtoPy { + ext.outdir = file("build/generated/source/proto/main/py") + outputs.dir(outdir) + inputs.files(src) +- dependsOn(configurations.protocArtifact) ++ dependsOn(protobuf.generateProtoTasks.all()) + doLast { +- def exe = configurations.protocArtifact.first() +- if (!isCurrentWindows()) { +- exe.setExecutable(true) +- } ++ def exe = protobuf.tools.protoc.path + exec { + commandLine exe, "--python_out=$outdir", "-I$srcdir" + args src +diff --git a/build.gradle b/build.gradle +index b0c717fb1..5f56506a5 100644 +--- a/build.gradle ++++ b/build.gradle +@@ -74,6 +74,12 @@ if (flatRepo.isDirectory()) { + jcenter() + flatDir name: "flat", dirs:["$flatRepo"] + } ++ buildscript { ++ repositories { ++ mavenLocal() ++ mavenCentral() ++ } ++ } + } + } + else { +diff --git a/gradle/hasProtobuf.gradle b/gradle/hasProtobuf.gradle +index 23b4ce74b..e69de29bb 100644 +--- a/gradle/hasProtobuf.gradle ++++ b/gradle/hasProtobuf.gradle +@@ -1,94 +0,0 @@ +-/* ### +- * IP: GHIDRA +- * +- * Licensed under the Apache License, Version 2.0 (the "License"); +- * you may not use this file except in compliance with the License. +- * You may obtain a copy of the License at +- * +- * http://www.apache.org/licenses/LICENSE-2.0 +- * +- * Unless required by applicable law or agreed to in writing, software +- * distributed under the License 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. +- */ +-/*plugins { +- id 'com.google.protobuf' version '0.8.10' +-}*/ +- +-configurations { +- allProtocArtifacts +- protocArtifact +-} +- +-def platform = getCurrentPlatformName() +- +- +-dependencies { +- allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:windows-x86_64@exe' +- allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:linux-x86_64@exe' +- allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:linux-aarch_64@exe' +- allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:osx-x86_64@exe' +- allProtocArtifacts 'com.google.protobuf:protoc:3.21.8:osx-aarch_64@exe' +- +- if (isCurrentWindows()) { +- protocArtifact 'com.google.protobuf:protoc:3.21.8:windows-x86_64@exe' +- } +- if (isCurrentLinux()) { +- if (platform.endsWith("x86_64")) { +- protocArtifact 'com.google.protobuf:protoc:3.21.8:linux-x86_64@exe' +- } +- else { +- protocArtifact 'com.google.protobuf:protoc:3.21.8:linux-aarch_64@exe' +- } +- } +- if (isCurrentMac()) { +- if (platform.endsWith("x86_64")) { +- protocArtifact 'com.google.protobuf:protoc:3.21.8:osx-x86_64@exe' +- } +- else { +- protocArtifact 'com.google.protobuf:protoc:3.21.8:osx-aarch_64@exe' +- } +- } +-} +- +-/*protobuf { +- protoc { +- artifact = 'com.google.protobuf:protoc:3.21.8' +- } +-}*/ +- +-task generateProto { +- ext.srcdir = file("src/main/proto") +- ext.src = fileTree(srcdir) { +- include "**/*.proto" +- } +- ext.outdir = file("build/generated/source/proto/main/java") +- outputs.dir(outdir) +- inputs.files(src) +- dependsOn(configurations.protocArtifact) +- doLast { +- def exe = configurations.protocArtifact.first() +- if (!isCurrentWindows()) { +- exe.setExecutable(true) +- } +- exec { +- commandLine exe, "--java_out=$outdir", "-I$srcdir" +- args src +- } +- } +-} +- +-tasks.compileJava.dependsOn(tasks.generateProto) +-tasks.eclipse.dependsOn(tasks.generateProto) +-rootProject.tasks.prepDev.dependsOn(tasks.generateProto) +- +-sourceSets { +- main { +- java { +- srcDir tasks.generateProto.outdir +- } +- } +-} +-zipSourceSubproject.dependsOn generateProto +-- +2.42.0 + diff --git a/pkgs/ghidra-xenia-v2/0002-Load-nix-extensions.patch b/pkgs/ghidra-xenia-v2/0002-Load-nix-extensions.patch new file mode 100644 index 0000000..0e87aa7 --- /dev/null +++ b/pkgs/ghidra-xenia-v2/0002-Load-nix-extensions.patch @@ -0,0 +1,15 @@ +diff --git a/Ghidra/Framework/Utility/src/main/java/utility/application/ApplicationUtilities.java b/Ghidra/Framework/Utility/src/main/java/utility/application/ApplicationUtilities.java +index ea12a661f0..da7779b07f 100644 +--- a/Ghidra/Framework/Utility/src/main/java/utility/application/ApplicationUtilities.java ++++ b/Ghidra/Framework/Utility/src/main/java/utility/application/ApplicationUtilities.java +@@ -36,6 +36,10 @@ public class ApplicationUtilities { + */ + public static Collection findDefaultApplicationRootDirs() { + Collection applicationRootDirs = new ArrayList<>(); ++ String nixGhidraHome = System.getenv("NIX_GHIDRAHOME"); ++ if (nixGhidraHome != null) { ++ applicationRootDirs.add(new ResourceFile(nixGhidraHome)); ++ }; + ResourceFile applicationRootDir = findPrimaryApplicationRootDir(); + if (applicationRootDir != null) { + applicationRootDirs.add(applicationRootDir); diff --git a/pkgs/ghidra-xenia-v2/0003-Remove-build-datestamp.patch b/pkgs/ghidra-xenia-v2/0003-Remove-build-datestamp.patch new file mode 100644 index 0000000..0a89487 --- /dev/null +++ b/pkgs/ghidra-xenia-v2/0003-Remove-build-datestamp.patch @@ -0,0 +1,26 @@ +diff --git a/Ghidra/RuntimeScripts/Common/support/buildExtension.gradle b/Ghidra/RuntimeScripts/Common/support/buildExtension.gradle +index bc194f219..94b00fabd 100644 +--- a/Ghidra/RuntimeScripts/Common/support/buildExtension.gradle ++++ b/Ghidra/RuntimeScripts/Common/support/buildExtension.gradle +@@ -82,7 +82,7 @@ dependencies { + helpPath fileTree(dir: ghidraDir + '/Features/Base', include: "**/Base.jar") + } + +-def ZIP_NAME_PREFIX = "${DISTRO_PREFIX}_${RELEASE_NAME}_${getCurrentDate()}" ++def ZIP_NAME_PREFIX = "${DISTRO_PREFIX}_${RELEASE_NAME}" + def DISTRIBUTION_DIR = file("dist") + + def pathInZip = "${project.name}" +diff --git a/gradle/root/distribution.gradle b/gradle/root/distribution.gradle +index f44c8267b..f6231c417 100644 +--- a/gradle/root/distribution.gradle ++++ b/gradle/root/distribution.gradle +@@ -32,7 +32,7 @@ apply from: "$rootProject.projectDir/gradle/support/sbom.gradle" + def currentPlatform = getCurrentPlatformName() + def PROJECT_DIR = file (rootProject.projectDir.absolutePath) + ext.DISTRIBUTION_DIR = file("$buildDir/dist") +-ext.ZIP_NAME_PREFIX = "${rootProject.DISTRO_PREFIX}_${rootProject.BUILD_DATE_SHORT}" ++ext.ZIP_NAME_PREFIX = "${rootProject.DISTRO_PREFIX}" + ext.ZIP_DIR_PREFIX = "${rootProject.DISTRO_PREFIX}" + ext.ALL_REPOS = [rootProject.file('.').getName()] + diff --git a/pkgs/ghidra-xenia-v2/build-extension.nix b/pkgs/ghidra-xenia-v2/build-extension.nix new file mode 100644 index 0000000..652b7bc --- /dev/null +++ b/pkgs/ghidra-xenia-v2/build-extension.nix @@ -0,0 +1,98 @@ +{ + lib, + stdenv, + unzip, + jdk, + gradle, + ghidra, +}: + +let + metaCommon = + oldMeta: + oldMeta + // { + maintainers = (oldMeta.maintainers or [ ]) ++ (with lib.maintainers; [ vringar ]); + platforms = oldMeta.platforms or ghidra.meta.platforms; + }; + + buildGhidraExtension = + { + pname, + nativeBuildInputs ? [ ], + meta ? { }, + ... + }@args: + stdenv.mkDerivation ( + args + // { + nativeBuildInputs = nativeBuildInputs ++ [ + unzip + jdk + gradle + ]; + + preBuild = '' + # Set project name, otherwise defaults to directory name + echo -e '\nrootProject.name = "${pname}"' >> settings.gradle + # A config directory needs to exist when ghidra's GHelpBuilder is run + export XDG_CONFIG_HOME="''${XDG_CONFIG_HOME:-$(mktemp -d)}" + ${args.preBuild or ""} + ''; + + # Needed to run gradle on darwin + __darwinAllowLocalNetworking = true; + + gradleBuildTask = args.gradleBuildTask or "buildExtension"; + gradleFlags = args.gradleFlags or [ ] ++ [ "-PGHIDRA_INSTALL_DIR=${ghidra}/lib/ghidra" ]; + + installPhase = + args.installPhase or '' + runHook preInstall + + mkdir -p $out/lib/ghidra/Ghidra/Extensions + unzip -d $out/lib/ghidra/Ghidra/Extensions dist/*.zip + + runHook postInstall + ''; + + meta = metaCommon meta; + } + ); + + buildGhidraScripts = + { + pname, + meta ? { }, + ... + }@args: + stdenv.mkDerivation ( + args + // { + installPhase = '' + runHook preInstall + + GHIDRA_HOME=$out/lib/ghidra/Ghidra/Extensions/${pname} + mkdir -p $GHIDRA_HOME + cp -r . $GHIDRA_HOME/ghidra_scripts + + touch $GHIDRA_HOME/Module.manifest + cat <<'EOF' > extension.properties + name=${pname} + description=${meta.description or ""} + author= + createdOn= + version=${lib.getVersion ghidra} + + EOF + + runHook postInstall + ''; + + meta = metaCommon meta; + } + ); +in +{ + inherit buildGhidraExtension buildGhidraScripts; +} diff --git a/pkgs/ghidra-xenia-v2/build.nix b/pkgs/ghidra-xenia-v2/build.nix new file mode 100644 index 0000000..e85b58c --- /dev/null +++ b/pkgs/ghidra-xenia-v2/build.nix @@ -0,0 +1,201 @@ +{ + stdenv, + fetchFromGitHub, + lib, + callPackage, + gradle, + makeBinaryWrapper, + openjdk21, + unzip, + makeDesktopItem, + copyDesktopItems, + desktopToDarwinBundle, + xcbuild, + protobuf, + ghidra-extensions, + python3, + python3Packages, +}: + +let + pkg_path = "$out/lib/ghidra"; + pname = "ghidra"; + version = "11.1.2"; + + releaseName = "NIX"; + distroPrefix = "ghidra_${version}_${releaseName}"; + src = fetchFromGitHub { + owner = "NationalSecurityAgency"; + repo = "Ghidra"; + rev = "Ghidra_${version}_build"; + hash = "sha256-FL1nLaq8A9PI+RzqZg5+O+4+ZsH16MG3cf7OIKimDqw="; + # populate values that require us to use git. By doing this in postFetch we + # can delete .git afterwards and maintain better reproducibility of the src. + leaveDotGit = true; + postFetch = '' + cd "$out" + git rev-parse HEAD > $out/COMMIT + # 1970-Jan-01 + date -u -d "@$(git log -1 --pretty=%ct)" "+%Y-%b-%d" > $out/SOURCE_DATE_EPOCH + # 19700101 + date -u -d "@$(git log -1 --pretty=%ct)" "+%Y%m%d" > $out/SOURCE_DATE_EPOCH_SHORT + find "$out" -name .git -print0 | xargs -0 rm -rf + ''; + }; + + patches = [ + # Use our own protoc binary instead of the prebuilt one + ./0001-Use-protobuf-gradle-plugin.patch + + # Override installation directory to allow loading extensions + ./0002-Load-nix-extensions.patch + + # Remove build dates from output filenames for easier reference + ./0003-Remove-build-datestamp.patch + ]; + + postPatch = '' + # Set name of release (eg. PUBLIC, DEV, etc.) + sed -i -e 's/application\.release\.name=.*/application.release.name=${releaseName}/' Ghidra/application.properties + + # Set build date and git revision + echo "application.build.date=$(cat SOURCE_DATE_EPOCH)" >> Ghidra/application.properties + echo "application.build.date.short=$(cat SOURCE_DATE_EPOCH_SHORT)" >> Ghidra/application.properties + echo "application.revision.ghidra=$(cat COMMIT)" >> Ghidra/application.properties + + # Tells ghidra to use our own protoc binary instead of the prebuilt one. + cat >>Ghidra/Debug/Debugger-gadp/build.gradle < /nix/store/3yn0rbnz5mbrxf0x70jbjq73wgkszr5c-ghidra-with-extensions-10.2.2 + */ + withExtensions = + f: + (symlinkJoin { + name = "${ghidra.pname}-with-extensions-${lib.getVersion ghidra}"; + paths = (f allExtensions); + nativeBuildInputs = [ + makeBinaryWrapper + ] ++ lib.optional stdenv.hostPlatform.isDarwin desktopToDarwinBundle; + postBuild = + '' + makeWrapper '${ghidra}/bin/ghidra' "$out/bin/ghidra" \ + --set NIX_GHIDRAHOME "$out/lib/ghidra/Ghidra" + makeWrapper '${ghidra}/bin/ghidra-analyzeHeadless' "$out/bin/ghidra-analyzeHeadless" \ + --set NIX_GHIDRAHOME "$out/lib/ghidra/Ghidra" + ln -s ${ghidra}/share $out/share + '' + + lib.optionalString stdenv.hostPlatform.isDarwin '' + convertDesktopFiles $prefix + ''; + inherit (ghidra) meta; + }); +in +withExtensions